1 //
2 // nco_pll_modem_example.c
3 //
4 // This example demonstrates how the nco/pll object (numerically-controlled
5 // oscillator with phase-locked loop) can be used for carrier frequency
6 // recovery in digital modems. The modem type, SNR, and other parameters are
7 // specified via the command-line interface.
8 //
9 // SEE ALSO: nco_example.c
10 // nco_pll_example.c
11 //
12
13 #include <stdio.h>
14 #include <stdlib.h>
15 #include <time.h>
16 #include <math.h>
17 #include <getopt.h>
18
19 #include "liquid.h"
20
21 #define OUTPUT_FILENAME "nco_pll_modem_example.m"
22
23 // print usage/help message
usage()24 void usage()
25 {
26 printf("nco_pll_modem_example [options]\n");
27 printf(" u/h : print usage\n");
28 printf(" s : signal-to-noise ratio, default: 30dB\n");
29 printf(" b : pll bandwidth, default: 20e-3\n");
30 printf(" n : number of symbols, default: 256\n");
31 printf(" P : phase offset (radians), default: pi/10 ~ 0.3146\n");
32 printf(" F : frequency offset (radians), default: 0.001\n");
33 printf(" m : modulation scheme, default: qpsk\n");
34 liquid_print_modulation_schemes();
35 }
36
main(int argc,char * argv[])37 int main(int argc, char*argv[]) {
38 srand( time(NULL) );
39 // parameters
40 float phase_offset = M_PI/10;
41 float frequency_offset = 0.001f;
42 float SNRdB = 30.0f;
43 float pll_bandwidth = 0.02f;
44 modulation_scheme ms = LIQUID_MODEM_QPSK;
45 unsigned int n=256; // number of iterations
46
47 int dopt;
48 while ((dopt = getopt(argc,argv,"uhs:b:n:P:F:m:")) != EOF) {
49 switch (dopt) {
50 case 'u':
51 case 'h': usage(); return 0;
52 case 's': SNRdB = atof(optarg); break;
53 case 'b': pll_bandwidth = atof(optarg); break;
54 case 'n': n = atoi(optarg); break;
55 case 'P': phase_offset = atof(optarg); break;
56 case 'F': frequency_offset= atof(optarg); break;
57 case 'm':
58 ms = liquid_getopt_str2mod(optarg);
59 if (ms == LIQUID_MODEM_UNKNOWN) {
60 fprintf(stderr,"error: %s, unknown/unsupported modulation scheme \"%s\"\n", argv[0], optarg);
61 return 1;
62 }
63 break;
64 default:
65 exit(1);
66 }
67 }
68 unsigned int d=n/32; // print every "d" lines
69
70 FILE * fid = fopen(OUTPUT_FILENAME,"w");
71 fprintf(fid, "%% %s : auto-generated file\n", OUTPUT_FILENAME);
72 fprintf(fid, "clear all;\n");
73 fprintf(fid, "phi=zeros(1,%u);\n",n);
74 fprintf(fid, "r=zeros(1,%u);\n",n);
75
76 // objects
77 nco_crcf nco_tx = nco_crcf_create(LIQUID_VCO);
78 nco_crcf nco_rx = nco_crcf_create(LIQUID_VCO);
79
80 modem mod = modem_create(ms);
81 modem demod = modem_create(ms);
82
83 unsigned int bps = modem_get_bps(mod);
84
85 // initialize objects
86 nco_crcf_set_phase(nco_tx, phase_offset);
87 nco_crcf_set_frequency(nco_tx, frequency_offset);
88 nco_crcf_pll_set_bandwidth(nco_rx, pll_bandwidth);
89
90 float noise_power = powf(10.0f, -SNRdB/20.0f);
91
92 // print parameters
93 printf("PLL example :\n");
94 printf("modem : %u-%s\n", 1<<bps, modulation_types[ms].name);
95 printf("frequency offset: %6.3f, phase offset: %6.3f, SNR: %6.2fdB, pll b/w: %6.3f\n",
96 frequency_offset, phase_offset, SNRdB, pll_bandwidth);
97
98 // run loop
99 unsigned int i, M=1<<bps, sym_in, sym_out, num_errors=0;
100 float phase_error;
101 float complex x, r, v, noise;
102 for (i=0; i<n; i++) {
103 // generate random symbol
104 sym_in = rand() % M;
105
106 // modulate
107 modem_modulate(mod, sym_in, &x);
108
109 // channel
110 //r = nco_crcf_cexpf(nco_tx);
111 nco_crcf_mix_up(nco_tx, x, &r);
112
113 // add complex white noise
114 crandnf(&noise);
115 r += noise * noise_power;
116
117 //
118 //v = nco_crcf_cexpf(nco_rx);
119 nco_crcf_mix_down(nco_rx, r, &v);
120
121 // demodulate
122 modem_demodulate(demod, v, &sym_out);
123 num_errors += count_bit_errors(sym_in, sym_out);
124
125 // error estimation
126 //phase_error = cargf(r*conjf(v));
127 phase_error = modem_get_demodulator_phase_error(demod);
128
129 // perfect error estimation
130 //phase_error = nco_tx->theta - nco_rx->theta;
131
132 // print every line in a format that octave can read
133 fprintf(fid, "phi(%u) = %10.6E;\n", i+1, phase_error);
134 fprintf(fid, "r(%u) = %10.6E + j*%10.6E;\n",
135 i+1, crealf(v), cimagf(v));
136
137 if ((i+1)%d == 0 || i==n-1) {
138 printf(" %4u: e_hat : %6.3f, phase error : %6.3f, freq error : %6.3f\n",
139 i+1, // iteration
140 phase_error, // estimated phase error
141 nco_crcf_get_phase(nco_tx) - nco_crcf_get_phase(nco_rx),// true phase error
142 nco_crcf_get_frequency(nco_tx) - nco_crcf_get_frequency(nco_rx)// true frequency error
143 );
144 }
145
146 // update tx nco object
147 nco_crcf_step(nco_tx);
148
149 // update pll
150 nco_crcf_pll_step(nco_rx, phase_error);
151
152 // update rx nco object
153 nco_crcf_step(nco_rx);
154 }
155
156 fprintf(fid, "figure;\n");
157 fprintf(fid, "plot(1:length(phi),phi,'LineWidth',2,'Color',[0 0.25 0.5]);\n");
158 fprintf(fid, "xlabel('Symbol Index');\n");
159 fprintf(fid, "ylabel('Phase Error [radians]');\n");
160 fprintf(fid, "grid on;\n");
161
162 fprintf(fid, "t0 = round(0.25*length(r));\n");
163 fprintf(fid, "figure;\n");
164 fprintf(fid, "plot(r(1:t0),'x','Color',[0.6 0.6 0.6],r(t0:end),'x','Color',[0 0.25 0.5]);\n");
165 fprintf(fid, "grid on;\n");
166 fprintf(fid, "axis([-1.5 1.5 -1.5 1.5]);\n");
167 fprintf(fid, "axis('square');\n");
168 fprintf(fid, "xlabel('In-Phase');\n");
169 fprintf(fid, "ylabel('Quadrature');\n");
170 fprintf(fid, "legend(['first 25%%'],['last 75%%'],1);\n");
171 fclose(fid);
172
173 printf("results written to %s.\n",OUTPUT_FILENAME);
174
175 nco_crcf_destroy(nco_tx);
176 nco_crcf_destroy(nco_rx);
177
178 modem_destroy(mod);
179 modem_destroy(demod);
180
181 printf("bit errors: %u / %u\n", num_errors, bps*n);
182 printf("done.\n");
183 return 0;
184 }
185