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