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