1 //
2 // symtrack_cccf_example.c
3 //
4 // This example demonstrates how to recover data symbols using the symtrack
5 // object. A stream of modulated and interpolated symbols are generated using
6 // the symstream object. The resulting samples are passed through a channel
7 // to add various impairments. The symtrack object recovers timing, carrier,
8 // and other information imparted by the channel and returns data symbols
9 // ready for demodulation.
10 //
11 
12 #include <stdio.h>
13 #include <stdlib.h>
14 #include <string.h>
15 #include <math.h>
16 #include <getopt.h>
17 #include <time.h>
18 #include <assert.h>
19 
20 #include "liquid.h"
21 
22 #define OUTPUT_FILENAME "symtrack_cccf_example.m"
23 
24 // print usage/help message
usage()25 void usage()
26 {
27     printf("symtrack_cccf_example [options]\n");
28     printf("  h     : print this help file\n");
29     printf("  k     : filter samples/symbol,   default: 2\n");
30     printf("  m     : filter delay (symbols),  default: 3\n");
31     printf("  b     : filter excess bandwidth, default: 0.5\n");
32     printf("  s     : signal-to-noise ratio,   default: 30 dB\n");
33     printf("  w     : timing pll bandwidth,    default: 0.02\n");
34     printf("  n     : number of symbols,       default: 4000\n");
35 }
36 
main(int argc,char * argv[])37 int main(int argc, char*argv[])
38 {
39     // options
40     int          ftype       = LIQUID_FIRFILT_ARKAISER;
41     int          ms          = LIQUID_MODEM_QAM16;
42     unsigned int k           = 2;       // samples per symbol
43     unsigned int m           = 7;       // filter delay (symbols)
44     float        beta        = 0.20f;   // filter excess bandwidth factor
45     unsigned int num_symbols = 4000;    // number of data symbols
46     unsigned int hc_len      =   4;     // channel filter length
47     float        noise_floor = -60.0f;  // noise floor [dB]
48     float        SNRdB       = 30.0f;   // signal-to-noise ratio [dB]
49     float        bandwidth   =  0.10f;  // loop filter bandwidth
50     float        dphi        =  0.02f;  // carrier frequency offset [radians/sample]
51     float        phi         =  2.1f;   // carrier phase offset [radians]
52 
53     unsigned int nfft        =   2400;  // spectral periodogram FFT size
54     unsigned int num_samples = 200000;  // number of samples
55 
56     int dopt;
57     while ((dopt = getopt(argc,argv,"hk:m:b:s:w:n:")) != EOF) {
58         switch (dopt) {
59         case 'h':   usage();                        return 0;
60         case 'k':   k           = atoi(optarg);     break;
61         case 'm':   m           = atoi(optarg);     break;
62         case 'b':   beta        = atof(optarg);     break;
63         case 's':   SNRdB       = atof(optarg);     break;
64         case 'w':   bandwidth   = atof(optarg);     break;
65         case 'n':   num_symbols = atoi(optarg);     break;
66         default:
67             exit(1);
68         }
69     }
70 
71     // validate input
72     if (k < 2) {
73         fprintf(stderr,"error: k (samples/symbol) must be greater than 1\n");
74         exit(1);
75     } else if (m < 1) {
76         fprintf(stderr,"error: m (filter delay) must be greater than 0\n");
77         exit(1);
78     } else if (beta <= 0.0f || beta > 1.0f) {
79         fprintf(stderr,"error: beta (excess bandwidth factor) must be in (0,1]\n");
80         exit(1);
81     } else if (bandwidth <= 0.0f) {
82         fprintf(stderr,"error: timing PLL bandwidth must be greater than 0\n");
83         exit(1);
84     } else if (num_symbols == 0) {
85         fprintf(stderr,"error: number of symbols must be greater than 0\n");
86         exit(1);
87     }
88 
89     unsigned int i;
90 
91     // buffers
92     unsigned int    buf_len = 800;      // buffer size
93     float complex   x   [buf_len];      // original signal
94     float complex   y   [buf_len];      // channel output
95     float complex   syms[buf_len];      // recovered symbols
96     // window for saving last few symbols
97     windowcf sym_buf = windowcf_create(buf_len);
98 
99     // create stream generator
100     symstreamcf gen = symstreamcf_create_linear(ftype,k,m,beta,ms);
101 
102     // create channel emulator and add impairments
103     channel_cccf channel = channel_cccf_create();
104     channel_cccf_add_awgn          (channel, noise_floor, SNRdB);
105     channel_cccf_add_carrier_offset(channel, dphi, phi);
106     channel_cccf_add_multipath     (channel, NULL, hc_len);
107 
108     // create symbol tracking synchronizer
109     symtrack_cccf symtrack = symtrack_cccf_create(ftype,k,m,beta,ms);
110     symtrack_cccf_set_bandwidth(symtrack,bandwidth);
111 
112     // create spectral periodogram for estimating spectrum
113     spgramcf periodogram = spgramcf_create_default(nfft);
114 
115     unsigned int total_samples = 0;
116     unsigned int total_symbols = 0;
117     while (total_samples < num_samples)
118     {
119         // write samples to buffer
120         symstreamcf_write_samples(gen, x, buf_len);
121 
122         // apply channel
123         channel_cccf_execute_block(channel, x, buf_len, y);
124 
125         // push resulting sample through periodogram
126         spgramcf_write(periodogram, y, buf_len);
127 
128         // run resulting stream through synchronizer
129         unsigned int num_symbols_sync;
130         symtrack_cccf_execute_block(symtrack, y, buf_len, syms, &num_symbols_sync);
131         total_symbols += num_symbols_sync;
132 
133         // write resulting symbols to window buffer for plotting
134         windowcf_write(sym_buf, syms, num_symbols_sync);
135 
136         // accumulated samples
137         total_samples += buf_len;
138     }
139     printf("total samples: %u\n", total_samples);
140     printf("total symbols: %u\n", total_symbols);
141 
142     // write accumulated power spectral density estimate
143     float psd[nfft];
144     spgramcf_get_psd(periodogram, psd);
145 
146     //
147     // export output file
148     //
149 
150     FILE * fid = fopen(OUTPUT_FILENAME,"w");
151     fprintf(fid,"%% %s, auto-generated file\n\n", OUTPUT_FILENAME);
152     fprintf(fid,"clear all;\n");
153     fprintf(fid,"close all;\n");
154 
155     // read buffer and write last symbols to file
156     float complex * rc;
157     windowcf_read(sym_buf, &rc);
158     fprintf(fid,"syms = zeros(1,%u);\n", buf_len);
159     for (i=0; i<buf_len; i++)
160         fprintf(fid,"syms(%3u) = %12.8f + j*%12.8f;\n", i+1, crealf(rc[i]), cimagf(rc[i]));
161 
162     // power spectral density estimate
163     fprintf(fid,"nfft = %u;\n", nfft);
164     fprintf(fid,"f=[0:(nfft-1)]/nfft - 0.5;\n");
165     fprintf(fid,"psd = zeros(1,nfft);\n");
166     for (i=0; i<nfft; i++)
167         fprintf(fid,"psd(%3u) = %12.8f;\n", i+1, psd[i]);
168 
169     fprintf(fid,"figure('Color','white','position',[500 500 1400 400]);\n");
170     fprintf(fid,"subplot(1,3,1);\n");
171     fprintf(fid,"plot(real(syms),imag(syms),'x','MarkerSize',4);\n");
172     fprintf(fid,"  axis square;\n");
173     fprintf(fid,"  grid on;\n");
174     fprintf(fid,"  axis([-1 1 -1 1]*1.6);\n");
175     fprintf(fid,"  xlabel('In-phase');\n");
176     fprintf(fid,"  ylabel('Quadrature');\n");
177     fprintf(fid,"  title('Last %u symbols');\n", buf_len);
178     fprintf(fid,"subplot(1,3,2:3);\n");
179     fprintf(fid,"  plot(f, psd, 'LineWidth',1.5,'Color',[0 0.5 0.2]);\n");
180     fprintf(fid,"  grid on;\n");
181     fprintf(fid,"  pmin = 10*floor(0.1*min(psd - 5));\n");
182     fprintf(fid,"  pmax = 10*ceil (0.1*max(psd + 5));\n");
183     fprintf(fid,"  axis([-0.5 0.5 pmin pmax]);\n");
184     fprintf(fid,"  xlabel('Normalized Frequency [f/F_s]');\n");
185     fprintf(fid,"  ylabel('Power Spectral Density [dB]');\n");
186 
187     fclose(fid);
188     printf("results written to %s.\n", OUTPUT_FILENAME);
189 
190     // destroy objects
191     symstreamcf_destroy  (gen);
192     spgramcf_destroy     (periodogram);
193     channel_cccf_destroy (channel);
194     symtrack_cccf_destroy(symtrack);
195     windowcf_destroy     (sym_buf);
196 
197     // clean it up
198     printf("done.\n");
199     return 0;
200 }
201