1 //
2 // eqlms_cccf_block_example.c
3 //
4 // This example tests the least mean-squares (LMS) equalizer (EQ) on a
5 // signal with an unknown modulation and carrier frequency offset.
6 // Equalization is performed blind on a block of samples and the reulting
7 // constellation is output to a file for plotting.
8 //
9
10 #include <stdio.h>
11 #include <stdlib.h>
12 #include <string.h>
13 #include <math.h>
14 #include <complex.h>
15 #include <getopt.h>
16 #include <time.h>
17 #include "liquid.h"
18
19 #define OUTPUT_FILENAME "eqlms_cccf_block_example.m"
20
21 // print usage/help message
usage()22 void usage()
23 {
24 printf("Usage: eqlms_cccf_block_example [OPTION]\n");
25 printf(" h : print help\n");
26 printf(" n : number of symbols, default: 500\n");
27 printf(" c : number of channel filter taps (minimum: 1), default: 5\n");
28 printf(" k : samples/symbol, default: 2\n");
29 printf(" m : filter semi-length (symbols), default: 4\n");
30 printf(" b : filter excess bandwidth factor, default: 0.3\n");
31 printf(" p : equalizer semi-length (symbols), default: 3\n");
32 printf(" u : equalizer learning rate, default; 0.05\n");
33 }
34
main(int argc,char * argv[])35 int main(int argc, char*argv[])
36 {
37 //srand(time(NULL));
38
39 // options
40 unsigned int num_samples = 2400; // number of symbols to observe
41 unsigned int hc_len = 5; // channel filter length
42 unsigned int k = 2; // matched filter samples/symbol
43 unsigned int m = 3; // matched filter delay (symbols)
44 float beta = 0.3f; // matched filter excess bandwidth factor
45 unsigned int p = 3; // equalizer length (symbols, hp_len = 2*k*p+1)
46 float mu = 0.15f; // equalizer learning rate
47 modulation_scheme ms = LIQUID_MODEM_QPSK;
48
49 int dopt;
50 while ((dopt = getopt(argc,argv,"hn:c:k:m:b:p:u:")) != EOF) {
51 switch (dopt) {
52 case 'h': usage(); return 0;
53 case 'n': num_samples = atoi(optarg); break;
54 case 'c': hc_len = atoi(optarg); break;
55 case 'k': k = atoi(optarg); break;
56 case 'm': m = atoi(optarg); break;
57 case 'b': beta = atof(optarg); break;
58 case 'p': p = atoi(optarg); break;
59 case 'u': mu = atof(optarg); break;
60 default:
61 exit(1);
62 }
63 }
64 unsigned int i;
65
66 // validate input
67 if (num_samples == 0) {
68 fprintf(stderr,"error: %s, number of symbols must be greater than zero\n", argv[0]);
69 exit(1);
70 } else if (hc_len == 0) {
71 fprintf(stderr,"error: %s, channel must have at least 1 tap\n", argv[0]);
72 exit(1);
73 } else if (k < 2) {
74 fprintf(stderr,"error: %s, samples/symbol must be at least 2\n", argv[0]);
75 exit(1);
76 } else if (m == 0) {
77 fprintf(stderr,"error: %s, filter semi-length must be at least 1 symbol\n", argv[0]);
78 exit(1);
79 } else if (beta < 0.0f || beta > 1.0f) {
80 fprintf(stderr,"error: %s, filter excess bandwidth must be in [0,1]\n", argv[0]);
81 exit(1);
82 } else if (p == 0) {
83 fprintf(stderr,"error: %s, equalizer semi-length must be at least 1 symbol\n", argv[0]);
84 exit(1);
85 } else if (mu < 0.0f || mu > 1.0f) {
86 fprintf(stderr,"error: %s, equalizer learning rate must be in [0,1]\n", argv[0]);
87 exit(1);
88 }
89
90 // derived/fixed values
91 unsigned int buf_len = 37;
92 float complex buf_input [buf_len];
93 float complex buf_channel[buf_len];
94 float complex buf_output [buf_len];
95
96 //
97 // generate input sequence using symbol stream generator
98 //
99 symstreamcf gen = symstreamcf_create_linear(LIQUID_FIRFILT_ARKAISER,k,m,beta,ms);
100
101 //
102 // create multi-path channel filter
103 //
104 float complex hc[hc_len];
105 for (i=0; i<hc_len; i++)
106 hc[i] = (i==0) ? 0.5f : (randnf() + _Complex_I*randnf())*0.2f;
107 firfilt_cccf channel = firfilt_cccf_create(hc, hc_len);
108
109 //
110 // create equalizer
111 //
112 eqlms_cccf eq = eqlms_cccf_create_rnyquist(LIQUID_FIRFILT_RRC, k, p, beta, 0.0f);
113 eqlms_cccf_set_bw(eq, mu);
114
115 FILE * fid = fopen(OUTPUT_FILENAME,"w");
116 fprintf(fid,"%% %s : auto-generated file\n\n", OUTPUT_FILENAME);
117 fprintf(fid,"clear all\n");
118 fprintf(fid,"close all\n");
119 fprintf(fid,"x = [];\n");
120 fprintf(fid,"y = [];\n");
121 fprintf(fid,"z = [];\n");
122
123 unsigned int num_samples_total = 0;
124 while (num_samples_total < num_samples)
125 {
126 // generate block of input samples
127 symstreamcf_write_samples(gen, buf_input, buf_len);
128
129 // apply channel to input signal
130 firfilt_cccf_execute_block(channel, buf_input, buf_len, buf_channel);
131
132 // run equalizer
133 eqlms_cccf_execute_block(eq, k, buf_channel, buf_len, buf_output);
134
135 // save results to output file
136 for (i=0; i<buf_len; i++) {
137 fprintf(fid,"x(end+1) = %12.4e + %12.4ei;\n", crealf(buf_input [i]), cimagf(buf_input [i]));
138 fprintf(fid,"y(end+1) = %12.4e + %12.4ei;\n", crealf(buf_channel[i]), cimagf(buf_channel[i]));
139 fprintf(fid,"z(end+1) = %12.4e + %12.4ei;\n", crealf(buf_output [i]), cimagf(buf_output [i]));
140 }
141
142 // increment number of samples
143 num_samples_total += buf_len;
144 }
145
146 // destroy objects
147 symstreamcf_destroy(gen);
148 firfilt_cccf_destroy(channel);
149 eqlms_cccf_destroy(eq);
150
151 fprintf(fid,"k = %u;\n", k);
152 fprintf(fid,"m = %u;\n", m);
153 fprintf(fid,"n = length(x);\n");
154
155 fprintf(fid,"figure('Color','white','position',[500 500 1200 500]);\n");
156 // plot constellation
157 fprintf(fid,"subplot(2,8,[5 6 7 8 13 14 15 16]),\n");
158 fprintf(fid," s = 1:k:n;\n");
159 fprintf(fid," s0 = round(length(s)/2);\n");
160 fprintf(fid," syms_rx_0 = z(s(1:s0));\n");
161 fprintf(fid," syms_rx_1 = z(s(s0:end));\n");
162 fprintf(fid," plot(real(syms_rx_0),imag(syms_rx_0),'x','Color',[1 1 1]*0.7,...\n");
163 fprintf(fid," real(syms_rx_1),imag(syms_rx_1),'x','Color',[1 1 1]*0.0);\n");
164 fprintf(fid," xlabel('In-Phase');\n");
165 fprintf(fid," ylabel('Quadrature');\n");
166 fprintf(fid," axis([-1 1 -1 1]*1.5);\n");
167 fprintf(fid," axis square;\n");
168 fprintf(fid," grid on;\n");
169 // plot time response
170 fprintf(fid,"t = 0:(n-1);\n");
171 fprintf(fid,"subplot(2,8,1:4),\n");
172 fprintf(fid," plot(t, real(z), '-','Color',[1 1 1]*0.7,...\n");
173 fprintf(fid," t(s),real(z(s)),'s','Color',[0 0.2 0.5],'MarkerSize',3);\n");
174 fprintf(fid," axis([0 n -1.5 1.5]);\n");
175 fprintf(fid," grid on;\n");
176 fprintf(fid," ylabel('real');\n");
177 fprintf(fid,"subplot(2,8,9:12),\n");
178 fprintf(fid," plot(t, imag(z), '-','Color',[1 1 1]*0.7,...\n");
179 fprintf(fid," t(s),imag(z(s)),'s','Color',[0 0.5 0.2],'MarkerSize',3);\n");
180 fprintf(fid," axis([0 n -1.5 1.5]);\n");
181 fprintf(fid," grid on;\n");
182 fprintf(fid," ylabel('imag');\n");
183
184 fclose(fid);
185 printf("results written to '%s'\n", OUTPUT_FILENAME);
186
187 return 0;
188 }
189