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