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