1 //
2 // symsync_crcf_example.c
3 //
4 // This example demonstrates the basic principles of the symbol timing
5 // recovery family of objects, specifically symsync_crcf. A set of random
6 // QPSK symbols are generated and interpolated with a timing offset. The
7 // resulting signal is run through the symsync_crcf object which applies a
8 // matched filter and recovers timing producing a clean constellation.
9 //
10
11 #include <stdio.h>
12 #include <stdlib.h>
13 #include <string.h>
14 #include <math.h>
15 #include <getopt.h>
16 #include <time.h>
17 #include <assert.h>
18
19 #include "liquid.h"
20
21 #define OUTPUT_FILENAME "symsync_crcf_example.m"
22
23 // print usage/help message
usage()24 void usage()
25 {
26 printf("symsync_crcf_example [options]\n");
27 printf(" h : print help\n");
28 printf(" k : filter samples/symbol, default: 2\n");
29 printf(" m : filter delay (symbols), default: 5\n");
30 printf(" b : filter excess bandwidth, default: 0.5\n");
31 printf(" B : filter polyphase banks, default: 32\n");
32 printf(" n : number of symbols, default: 400\n");
33 }
34
main(int argc,char * argv[])35 int main(int argc, char*argv[]) {
36 srand(time(NULL));
37
38 // options
39 unsigned int k = 2; // samples/symbol (input)
40 unsigned int m = 5; // filter delay (symbols)
41 float beta = 0.5f; // filter excess bandwidth factor
42 unsigned int num_filters = 32; // number of filters in the bank
43 unsigned int num_symbols = 400; // number of data symbols
44
45 int dopt;
46 while ((dopt = getopt(argc,argv,"hk:m:b:B:s:n:")) != EOF) {
47 switch (dopt) {
48 case 'h': usage(); return 0;
49 case 'k': k = atoi(optarg); break;
50 case 'm': m = atoi(optarg); break;
51 case 'b': beta = atof(optarg); break;
52 case 'B': num_filters = atoi(optarg); break;
53 case 'n': num_symbols = atoi(optarg); break;
54 default:
55 exit(1);
56 }
57 }
58
59 // validate input
60 if (k < 2) {
61 fprintf(stderr,"error: k (samples/symbol) must be at least 2\n");
62 exit(1);
63 } else if (m < 1) {
64 fprintf(stderr,"error: m (filter delay) must be greater than 0\n");
65 exit(1);
66 } else if (beta <= 0.0f || beta > 1.0f) {
67 fprintf(stderr,"error: beta (excess bandwidth factor) must be in (0,1]\n");
68 exit(1);
69 } else if (num_filters == 0) {
70 fprintf(stderr,"error: number of polyphase filters must be greater than 0\n");
71 exit(1);
72 } else if (num_symbols == 0) {
73 fprintf(stderr,"error: number of symbols must be greater than 0\n");
74 exit(1);
75 }
76
77 unsigned int i;
78
79 // static values
80 liquid_firfilt_type ftype = LIQUID_FIRFILT_ARKAISER;
81 float bandwidth = 0.02f; // loop filter bandwidth
82 float dt = -0.5f; // fractional sample offset
83
84 // derived values
85 unsigned int num_samples = k*num_symbols;
86
87 float complex s[num_symbols]; // data symbols
88 float complex x[num_samples]; // interpolated samples
89 float complex y[num_symbols + 64]; // synchronized symbols
90
91 // generate random QPSK symbols
92 for (i=0; i<num_symbols; i++) {
93 // random signal (QPSK)
94 s[i] = (rand() % 2 ? -M_SQRT1_2 : M_SQRT1_2) +
95 (rand() % 2 ? -M_SQRT1_2 : M_SQRT1_2) * _Complex_I;
96 }
97
98 // design interpolating filter with 'dt' samples of delay
99 firinterp_crcf interp = firinterp_crcf_create_prototype(ftype,k,m,beta,dt);
100
101 // run interpolator
102 firinterp_crcf_execute_block(interp, s, num_symbols, x);
103
104 // destroy interpolator
105 firinterp_crcf_destroy(interp);
106
107 // create symbol synchronizer
108 symsync_crcf sync = symsync_crcf_create_rnyquist(ftype, k, m, beta, num_filters);
109
110 // set bandwidth
111 symsync_crcf_set_lf_bw(sync,bandwidth);
112
113 // execute on entire block of samples
114 unsigned int ny=0;
115 symsync_crcf_execute(sync, x, num_samples, y, &ny);
116
117 // destroy synchronizer
118 symsync_crcf_destroy(sync);
119
120 // print last several symbols to screen
121 printf("output symbols:\n");
122 printf(" ...\n");
123 for (i=ny-10; i<ny; i++)
124 printf(" sym_out(%2u) = %8.4f + j*%8.4f;\n", i+1, crealf(y[i]), cimagf(y[i]));
125
126 //
127 // export output file
128 //
129
130 FILE* fid = fopen(OUTPUT_FILENAME,"w");
131 fprintf(fid,"%% %s, auto-generated file\n\n", OUTPUT_FILENAME);
132 fprintf(fid,"close all;\n");
133 fprintf(fid,"clear all;\n");
134
135 fprintf(fid,"ny=%u;\n",ny);
136
137 for (i=0; i<ny; i++)
138 fprintf(fid,"y(%3u) = %12.8f + j*%12.8f;\n", i+1, crealf(y[i]), cimagf(y[i]));
139
140 fprintf(fid,"i0 = 1:round(0.5*ny);\n");
141 fprintf(fid,"i1 = round(0.5*ny):ny;\n");
142 fprintf(fid,"figure;\n");
143 fprintf(fid,"hold on;\n");
144 fprintf(fid,"plot(real(y(i0)),imag(y(i0)),'x','MarkerSize',4,'Color',[1 1 1]*0.7);\n");
145 fprintf(fid,"plot(real(y(i1)),imag(y(i1)),'o','MarkerSize',4,'Color',[0 0.25 0.5]);\n");
146 fprintf(fid,"hold off;\n");
147 fprintf(fid,"axis square;\n");
148 fprintf(fid,"grid on;\n");
149 fprintf(fid,"axis([-1 1 -1 1]*1.6);\n");
150 fprintf(fid,"xlabel('In-phase');\n");
151 fprintf(fid,"ylabel('Quadrature');\n");
152 fprintf(fid,"legend(['first 50%%'],['last 50%%'],'location','northeast');\n");
153
154 fclose(fid);
155 printf("results written to %s.\n", OUTPUT_FILENAME);
156
157 // clean it up
158 printf("done.\n");
159 return 0;
160 }
161