1 //
2 // fskframesync_example.c
3 //
4 // This example demonstrates the interfaces to the fskframegen and
5 // fskframesync objects used to completely encapsulate data for
6 // over-the-air transmission.
7 //
8 // SEE ALSO: flexframesync_example.c
9 //
10
11 #include <stdio.h>
12 #include <stdlib.h>
13 #include <math.h>
14 #include <getopt.h>
15 #include <time.h>
16
17 #include "liquid.h"
18
19 #define OUTPUT_FILENAME "fskframesync_example.m"
20
usage()21 void usage()
22 {
23 printf("fskframesync_example [options]\n");
24 printf(" h : print usage\n");
25 printf(" d : enable debugging\n");
26 printf(" S : signal-to-noise ratio [dB], default: 20\n");
27 printf(" F : carrier frequency offset, default: 0\n");
28 printf(" P : carrier phase offset, default: 0\n");
29 printf(" T : fractional sample timing offset, default: 0.01\n");
30 }
31
32 // static callback function
33 static int callback(unsigned char * _header,
34 int _header_valid,
35 unsigned char * _payload,
36 unsigned int _payload_len,
37 int _payload_valid,
38 framesyncstats_s _stats,
39 void * _userdata);
40
41 // global arrays
42 unsigned char header[8];
43 unsigned char payload[200];
44
main(int argc,char * argv[])45 int main(int argc, char*argv[])
46 {
47 srand( time(NULL) );
48
49 // options
50 float SNRdB = 20.0f; // signal-to-noise ratio
51 float noise_floor = -20.0f; // noise floor
52 float dphi = 0.01f; // carrier frequency offset
53 float theta = 0.0f; // carrier phase offset
54 float dt = -0.2f; // fractional sample timing offset
55
56 crc_scheme check = LIQUID_CRC_32; // data validity check
57 fec_scheme fec0 = LIQUID_FEC_NONE; // fec (inner)
58 fec_scheme fec1 = LIQUID_FEC_NONE; // fec (outer)
59 unsigned int payload_len = 200; // payload length
60
61 int debug_enabled = 0;
62
63 // get options
64 int dopt;
65 while((dopt = getopt(argc,argv,"hdS:F:P:T:")) != EOF){
66 switch (dopt) {
67 case 'h': usage(); return 0;
68 case 'd': debug_enabled = 1; break;
69 case 'S': SNRdB = atof(optarg); break;
70 case 'F': dphi = atof(optarg); break;
71 case 'P': theta = atof(optarg); break;
72 case 'T': dt = atof(optarg); break;
73 default:
74 exit(-1);
75 }
76 }
77 printf("channel offsets: dt=%.3f, dphi=%.3f, theta=%.3f\n", dt, dphi, theta);
78
79 // derived values
80 float nstd = powf(10.0f, noise_floor/20.0f); // noise std. dev.
81 float gamma = powf(10.0f, (SNRdB+noise_floor)/20.0f); // channel gain
82
83 // create frame generator
84 fskframegen fg = fskframegen_create();
85 fskframegen_print(fg);
86
87 // create frame synchronizer using default properties
88 fskframesync fs = fskframesync_create(callback,NULL);
89 fskframesync_print(fs);
90 if (debug_enabled)
91 fskframesync_debug_enable(fs);
92
93 // data payload
94 unsigned int i;
95 // initialize header and payload data
96 for (i=0; i<8; i++)
97 header[i] = i;
98 for (i=0; i<200; i++)
99 payload[i] = rand() & 0xff;
100
101 // allocate memory for the frame samples
102 unsigned int buf_len = 64;
103 float complex buf_tx[buf_len]; // receive buffer
104 float complex buf_rx[buf_len]; // transmit buffer
105
106 // assemble the frame
107 fskframegen_assemble(fg, header, payload, payload_len, check, fec0, fec1);
108
109 // spectral periodogram
110 unsigned int nfft = 4200;
111 spgramcf periodogram = spgramcf_create_default(nfft);
112
113 // write frame in blocks
114 int frame_complete = 0;
115 while (!frame_complete)
116 {
117 frame_complete = fskframegen_write_samples(fg, buf_tx, buf_len);
118
119 // add noise, channel gain
120 for (i=0; i<buf_len; i++)
121 buf_rx[i] = buf_tx[i]*gamma + nstd*(randnf() + randnf()*_Complex_I)*M_SQRT1_2;
122
123 // synchronize/receive the frame
124 fskframesync_execute_block(fs, buf_rx, buf_len);
125
126 // estimate power spectral density
127 spgramcf_write(periodogram, buf_rx, buf_len);
128 }
129
130 // compute power spectral density of received signal
131 float psd[nfft];
132 spgramcf_get_psd(periodogram, psd);
133
134 // clean up allocated objects
135 spgramcf_destroy(periodogram);
136 fskframegen_destroy(fg);
137 fskframesync_destroy(fs);
138
139 //
140 // export results
141 //
142 FILE * fid = fopen(OUTPUT_FILENAME,"w");
143 fprintf(fid,"%% %s : auto-generated file\n", OUTPUT_FILENAME);
144 fprintf(fid,"clear all\n");
145 fprintf(fid,"close all\n");
146 fprintf(fid,"nfft = %u;\n", nfft);
147
148 // save power spectral density
149 fprintf(fid,"psd = zeros(1,nfft);\n");
150 for (i=0; i<nfft; i++)
151 fprintf(fid,"psd(%4u) = %12.8f;\n", i+1, psd[i]);
152
153 // plot PSD
154 fprintf(fid,"figure('Color','white');\n");
155 fprintf(fid,"f = [0:(nfft-1)]/nfft - 0.5;\n");
156 fprintf(fid,"plot(f,psd,'LineWidth',1.5,'Color',[0.5 0 0]);\n");
157 fprintf(fid,"axis([-0.5 0.5 -30 30]);\n");
158 fprintf(fid,"xlabel('Normalized Frequency [f/F_s]');\n");
159 fprintf(fid,"ylabel('PSD [dB]');\n");
160 fprintf(fid,"grid on;\n");
161
162 fclose(fid);
163 printf("results written to '%s'\n", OUTPUT_FILENAME);
164
165 printf("done.\n");
166 return 0;
167 }
168
169 // static callback function
callback(unsigned char * _header,int _header_valid,unsigned char * _payload,unsigned int _payload_len,int _payload_valid,framesyncstats_s _stats,void * _userdata)170 static int callback(unsigned char * _header,
171 int _header_valid,
172 unsigned char * _payload,
173 unsigned int _payload_len,
174 int _payload_valid,
175 framesyncstats_s _stats,
176 void * _userdata)
177 {
178 printf("*** callback invoked ***\n");
179 printf(" error vector mag. : %12.8f dB\n", _stats.evm);
180 printf(" rssi : %12.8f dB\n", _stats.rssi);
181 printf(" carrier offset : %12.8f\n", _stats.cfo);
182 printf(" mod. scheme : %s\n", modulation_types[_stats.mod_scheme].fullname);
183 printf(" mod. depth : %u\n", _stats.mod_bps);
184 printf(" payload CRC : %s\n", crc_scheme_str[_stats.check][1]);
185 printf(" payload fec (inner) : %s\n", fec_scheme_str[_stats.fec0][1]);
186 printf(" payload fec (outer) : %s\n", fec_scheme_str[_stats.fec1][1]);
187 printf(" header crc : %s\n", _header_valid ? "pass" : "FAIL");
188 printf(" header data : %.2x %.2x %.2x %.2x %.2x %.2x %.2x %.2x\n",
189 _header[0], _header[1], _header[2], _header[3],
190 _header[4], _header[5], _header[6], _header[7]);
191 printf(" num header errors : %u / %u\n",
192 count_bit_errors_array(_header, header, 8),
193 8*8);
194 printf(" payload crc : %s\n", _payload_valid ? "pass" : "FAIL");
195 printf(" num payload errors : %u / %u\n",
196 count_bit_errors_array(_payload, payload, 64),
197 64*8);
198
199 return 0;
200 }
201
202