1 //
2 // framesync64_example.c
3 //
4 // This example demonstrates the interfaces to the framegen64 and
5 // framesync64 objects used to completely encapsulate data for
6 // over-the-air transmission.  A 64-byte payload is generated, and then
7 // encoded, modulated, and interpolated using the framegen64 object.
8 // The resulting complex baseband samples are corrupted with noise and
9 // moderate carrier frequency and phase offsets before the framesync64
10 // object attempts to decode the frame.  The resulting data are compared
11 // to the original to validate correctness.
12 //
13 // SEE ALSO: flexframesync_example.c
14 //
15 
16 #include <stdio.h>
17 #include <stdlib.h>
18 #include <math.h>
19 #include <getopt.h>
20 #include <time.h>
21 
22 #include "liquid.h"
23 
24 #define OUTPUT_FILENAME  "framesync64_example.m"
25 
usage()26 void usage()
27 {
28     printf("framesync64_example [options]\n");
29     printf("  h     : print usage\n");
30     printf("  d     : enable debugging\n");
31     printf("  S     : signal-to-noise ratio [dB], default: 20\n");
32     printf("  F     : carrier frequency offset, default: 0\n");
33     printf("  P     : carrier phase offset, default: 0\n");
34     printf("  T     : fractional sample timing offset, default: 0.01\n");
35 }
36 
37 // static callback function
38 static int callback(unsigned char *  _header,
39                     int              _header_valid,
40                     unsigned char *  _payload,
41                     unsigned int     _payload_len,
42                     int              _payload_valid,
43                     framesyncstats_s _stats,
44                     void *           _userdata);
45 
46 // global arrays
47 unsigned char header[8];
48 unsigned char payload[64];
49 
main(int argc,char * argv[])50 int main(int argc, char*argv[])
51 {
52     srand( time(NULL) );
53 
54     // options
55     float SNRdB       =  20.0f; // signal-to-noise ratio
56     float noise_floor = -40.0f; // noise floor
57     float dphi        =  0.01f; // carrier frequency offset
58     float theta       =  0.0f;  // carrier phase offset
59     float dt          =  -0.2f;  // fractional sample timing offset
60     int debug_enabled = 0;
61 
62     // get options
63     int dopt;
64     while((dopt = getopt(argc,argv,"hdS:F:P:T:")) != EOF){
65         switch (dopt) {
66         case 'h': usage();              return 0;
67         case 'd': debug_enabled = 1;    break;
68         case 'S': SNRdB = atof(optarg); break;
69         case 'F': dphi  = atof(optarg); break;
70         case 'P': theta = atof(optarg); break;
71         case 'T': dt    = atof(optarg); break;
72         default:
73             exit(-1);
74         }
75     }
76 
77     // derived values
78     unsigned int frame_len = LIQUID_FRAME64_LEN;          // fixed frame length
79     unsigned int num_samples = frame_len + 200;           // total number of samples
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     framegen64 fg = framegen64_create();
85     framegen64_print(fg);
86 
87     // create frame synchronizer using default properties
88     framesync64 fs = framesync64_create(callback,NULL);
89     framesync64_print(fs);
90     if (debug_enabled)
91         framesync64_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<64; i++)
99         payload[i] = rand() & 0xff;
100 
101     // allocate memory for the frame samples
102     float complex frame[frame_len]; // generated frame
103     float complex y[num_samples];   // received sequence
104 
105     // generate the frame
106     framegen64_execute(fg, header, payload, frame);
107 
108     // fractional sample timing offset
109     unsigned int d = 11;    // fractional sample filter delay
110     firfilt_crcf finterp = firfilt_crcf_create_kaiser(2*d+1, 0.45f, 40.0f, -dt);
111     for (i=0; i<num_samples; i++) {
112         // fractional sample timing offset
113         if      (i < 100)             firfilt_crcf_push(finterp, 0.0f);
114         else if (i < frame_len + 100) firfilt_crcf_push(finterp, frame[i-100]);
115         else                          firfilt_crcf_push(finterp, 0.0f);
116 
117         // compute output
118         firfilt_crcf_execute(finterp, &y[i]);
119     }
120     firfilt_crcf_destroy(finterp);
121 
122     // add channel impairments
123     for (i=0; i<num_samples; i++) {
124         y[i] *= cexpf(_Complex_I*(dphi*i +theta));
125         y[i] *= gamma;
126         y[i] += nstd*( randnf() + _Complex_I*randnf())*M_SQRT1_2;
127     }
128 
129     // synchronize/receive the frame
130     framesync64_execute(fs, y, num_samples);
131 
132     // export debugging file
133     if (debug_enabled)
134         framesync64_debug_print(fs, "framesync64_debug.m");
135 
136     // clean up allocated objects
137     framegen64_destroy(fg);
138     framesync64_destroy(fs);
139 
140     //
141     // export results
142     //
143     FILE* fid = fopen(OUTPUT_FILENAME, "w");
144     fprintf(fid,"%% %s: auto-generated file\n", OUTPUT_FILENAME);
145     fprintf(fid,"\n\n");
146     fprintf(fid,"clear all;\n");
147     fprintf(fid,"close all;\n");
148     fprintf(fid,"frame_len   = %u;\n", frame_len);
149     fprintf(fid,"num_samples = %u;\n", num_samples);
150     for (i=0; i<num_samples; i++)
151         fprintf(fid, "y(%4u) = %12.4e + j*%12.4e;\n", i+1, crealf(y[i]), cimagf(y[i]));
152 
153     fprintf(fid,"t=0:(length(y)-1);\n");
154     fprintf(fid,"plot(t,real(y),t,imag(y));\n");
155     fclose(fid);
156     printf("results written to %s\n", OUTPUT_FILENAME);
157 
158     printf("done.\n");
159     return 0;
160 }
161 
162 // 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)163 static int callback(unsigned char *  _header,
164                     int              _header_valid,
165                     unsigned char *  _payload,
166                     unsigned int     _payload_len,
167                     int              _payload_valid,
168                     framesyncstats_s _stats,
169                     void *           _userdata)
170 {
171     printf("*** callback invoked ***\n");
172     printf("    error vector mag.   : %12.8f dB\n", _stats.evm);
173     printf("    rssi                : %12.8f dB\n", _stats.rssi);
174     printf("    carrier offset      : %12.8f\n", _stats.cfo);
175     printf("    mod. scheme         : %s\n", modulation_types[_stats.mod_scheme].fullname);
176     printf("    mod. depth          : %u\n", _stats.mod_bps);
177     printf("    payload CRC         : %s\n", crc_scheme_str[_stats.check][1]);
178     printf("    payload fec (inner) : %s\n", fec_scheme_str[_stats.fec0][1]);
179     printf("    payload fec (outer) : %s\n", fec_scheme_str[_stats.fec1][1]);
180     printf("    header crc          : %s\n", _header_valid ? "pass" : "FAIL");
181     printf("    header data         : %.2x %.2x %.2x %.2x %.2x %.2x %.2x %.2x\n",
182             _header[0], _header[1], _header[2], _header[3],
183             _header[4], _header[5], _header[6], _header[7]);
184     printf("    num header errors   : %u / %u\n",
185             count_bit_errors_array(_header, header, 8),
186             8*8);
187     printf("    payload crc         : %s\n", _payload_valid ? "pass" : "FAIL");
188     printf("    num payload errors  : %u / %u\n",
189             count_bit_errors_array(_payload, payload, 64),
190             64*8);
191 
192     return 0;
193 }
194 
195