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