1 //
2 // cpfskmodem_example.c
3 //
4 // This example demostrates the continuous phase frequency-shift keying
5 // (CP-FSK) modem in liquid. A message signal is modulated and the
6 // resulting signal is recovered using a demodulator object.
7 //
8 
9 #include <stdio.h>
10 #include <stdlib.h>
11 #include <string.h>
12 #include <getopt.h>
13 #include <math.h>
14 #include "liquid.h"
15 
16 #define OUTPUT_FILENAME "cpfskmodem_example.m"
17 
18 // print usage/help message
usage()19 void usage()
20 {
21     printf("cpfskmodem_example -- continuous-phase frequency-shift keying example\n");
22     printf("options:\n");
23     printf(" -h             : print help\n");
24     printf(" -t <type>      : filter type: [square], rcos-full, rcos-half, gmsk\n");
25     printf(" -p <b/s>       : bits/symbol,              default:  1\n");
26     printf(" -H <index>     : modulation index,         default:  0.5\n");
27     printf(" -k <s/sym>     : samples/symbol,           default:  8\n");
28     printf(" -m <delay>     : filter delay (symbols),   default:  3\n");
29     printf(" -b <rolloff>   : filter roll-off,          default:  0.35\n");
30     printf(" -n <num>       : number of data symbols,   default: 80\n");
31     printf(" -s <snr>       : SNR [dB],                 default: 40\n");
32 }
33 
main(int argc,char * argv[])34 int main(int argc, char*argv[])
35 {
36     // options
37     unsigned int    bps         = 1;        // number of bits/symbol
38     float           h           = 0.5f;     // modulation index (h=1/2 for MSK)
39     unsigned int    k           = 4;        // filter samples/symbol
40     unsigned int    m           = 3;        // filter delay (symbols)
41     float           beta        = 0.35f;    // GMSK bandwidth-time factor
42     unsigned int    num_symbols = 20;       // number of data symbols
43     float           SNRdB       = 40.0f;    // signal-to-noise ratio [dB]
44     int             filter_type = LIQUID_CPFSK_SQUARE;
45 
46     int dopt;
47     while ((dopt = getopt(argc,argv,"ht:p:H:k:m:b:n:s:")) != EOF) {
48         switch (dopt) {
49         case 'h': usage();                      return 0;
50         case 't':
51             if (strcmp(optarg,"square")==0) {
52                 filter_type = LIQUID_CPFSK_SQUARE;
53             } else if (strcmp(optarg,"rcos-full")==0) {
54                 filter_type = LIQUID_CPFSK_RCOS_FULL;
55             } else if (strcmp(optarg,"rcos-half")==0) {
56                 filter_type = LIQUID_CPFSK_RCOS_PARTIAL;
57             } else if (strcmp(optarg,"gmsk")==0) {
58                 filter_type = LIQUID_CPFSK_GMSK;
59             } else {
60                 fprintf(stderr,"error: %s, unknown filter type '%s'\n", argv[0], optarg);
61                 exit(1);
62             }
63             break;
64         case 'p': bps   = atoi(optarg);         break;
65         case 'H': h     = atof(optarg);         break;
66         case 'k': k     = atoi(optarg);         break;
67         case 'm': m     = atoi(optarg);         break;
68         case 'b': beta  = atof(optarg);         break;
69         case 'n': num_symbols = atoi(optarg);   break;
70         case 's': SNRdB = atof(optarg);         break;
71         default:
72             exit(1);
73         }
74     }
75 
76     unsigned int i;
77 
78     // derived values
79     unsigned int  num_samples = k*num_symbols;
80     unsigned int  M           = 1 << bps;
81     float         nstd        = powf(10.0f, -SNRdB/20.0f);
82 
83     // arrays
84     unsigned int  sym_in [num_symbols]; // input symbols
85     float complex x      [num_samples]; // transmitted signal
86     float complex y      [num_samples]; // received signal
87     unsigned int  sym_out[num_symbols]; // output symbols
88 
89     // create modem objects
90     cpfskmod mod = cpfskmod_create(bps, h, k, m, beta, filter_type);
91     cpfskdem dem = cpfskdem_create(bps, h, k, m, beta, filter_type);
92 
93     // print modulator
94     cpfskmod_print(mod);
95 
96     // get full symbol delay
97     unsigned int delay = cpfskmod_get_delay(mod) + cpfskdem_get_delay(dem);
98     printf("delay: %u samples\n", delay);
99 
100     // generate message signal
101     for (i=0; i<num_symbols; i++)
102         sym_in[i] = rand() % M;
103 
104     // modulate signal
105     for (i=0; i<num_symbols; i++)
106         cpfskmod_modulate(mod, sym_in[i], &x[k*i]);
107 
108     // push through channel (add noise)
109     for (i=0; i<num_samples; i++)
110         y[i] = x[i] + nstd*(randnf() + _Complex_I*randnf())*M_SQRT1_2;
111 
112     // demodulate signal
113     for (i=0; i<num_symbols; i++)
114         sym_out[i] = cpfskdem_demodulate(dem, &y[i*k]);
115 
116     // print/count errors
117     unsigned int num_errors = 0;
118     for (i=delay; i<num_symbols; i++) {
119         int is_err = (sym_in[i-delay] == sym_out[i]) ? 0 : 1;
120         printf("  %3u : %2u %2u %s\n", i, sym_in[i-delay], sym_out[i], is_err ? "*" : "");
121         num_errors += is_err;
122     }
123     printf("symbol errors: %u / %u\n", num_errors, num_symbols-delay);
124 
125     // destroy modem objects
126     cpfskmod_destroy(mod);
127     cpfskdem_destroy(dem);
128 
129     // compute power spectral density of transmitted signal
130     unsigned int nfft = 1024;
131     float psd[nfft];
132     spgramcf_estimate_psd(nfft, x, num_samples, psd);
133 
134     //
135     // export results
136     //
137     FILE * fid = fopen(OUTPUT_FILENAME,"w");
138     fprintf(fid,"%% %s : auto-generated file\n", OUTPUT_FILENAME);
139     fprintf(fid,"clear all\n");
140     fprintf(fid,"close all\n");
141     fprintf(fid,"k = %u;\n", k);
142     fprintf(fid,"h = %f;\n", h);
143     fprintf(fid,"num_symbols = %u;\n", num_symbols);
144     fprintf(fid,"num_samples = %u;\n", num_samples);
145     fprintf(fid,"nfft        = %u;\n", nfft);
146     fprintf(fid,"delay       = %u; %% receive filter delay\n", m);
147 
148     fprintf(fid,"x   = zeros(1,num_samples);\n");
149     fprintf(fid,"y   = zeros(1,num_samples);\n");
150     for (i=0; i<num_samples; i++) {
151         fprintf(fid,"x(%4u) = %12.8f + j*%12.8f;\n", i+1, crealf(x[i]), cimagf(x[i]));
152         fprintf(fid,"y(%4u) = %12.8f + j*%12.8f;\n", i+1, crealf(y[i]), cimagf(y[i]));
153     }
154     // save power spectral density
155     fprintf(fid,"psd = zeros(1,nfft);\n");
156     for (i=0; i<nfft; i++)
157         fprintf(fid,"psd(%4u) = %12.8f;\n", i+1, psd[i]);
158 
159     fprintf(fid,"t=[0:(num_samples-1)]/k;\n");
160     fprintf(fid,"i = 1:k:num_samples;\n");
161     fprintf(fid,"figure;\n");
162     fprintf(fid,"subplot(3,4,1:3);\n");
163     fprintf(fid,"  plot(t,real(x),'-', t(i),real(x(i)),'ob',...\n");
164     fprintf(fid,"       t,imag(x),'-', t(i),imag(x(i)),'og');\n");
165     fprintf(fid,"  axis([0 num_symbols -1.2 1.2]);\n");
166     fprintf(fid,"  xlabel('time');\n");
167     fprintf(fid,"  ylabel('x(t)');\n");
168     fprintf(fid,"  grid on;\n");
169     fprintf(fid,"subplot(3,4,5:7);\n");
170     fprintf(fid,"  plot(t,real(y),'-', t(i),real(y(i)),'ob',...\n");
171     fprintf(fid,"       t,imag(y),'-', t(i),imag(y(i)),'og');\n");
172     fprintf(fid,"  axis([0 num_symbols -1.2 1.2]);\n");
173     fprintf(fid,"  xlabel('time');\n");
174     fprintf(fid,"  ylabel('y(t)');\n");
175     fprintf(fid,"  grid on;\n");
176     // plot I/Q constellations
177     fprintf(fid,"subplot(3,4,4);\n");
178     fprintf(fid,"  plot(real(x),imag(x),'-',real(x(i)),imag(x(i)),'rs','MarkerSize',4);\n");
179     fprintf(fid,"  xlabel('I');\n");
180     fprintf(fid,"  ylabel('Q');\n");
181     fprintf(fid,"  axis([-1 1 -1 1]*1.2);\n");
182     fprintf(fid,"  axis square;\n");
183     fprintf(fid,"  grid on;\n");
184     fprintf(fid,"subplot(3,4,8);\n");
185     fprintf(fid,"  plot(real(y),imag(y),'-',real(y(i)),imag(y(i)),'rs','MarkerSize',4);\n");
186     fprintf(fid,"  xlabel('I');\n");
187     fprintf(fid,"  ylabel('Q');\n");
188     fprintf(fid,"  axis([-1 1 -1 1]*1.2);\n");
189     fprintf(fid,"  axis square;\n");
190     fprintf(fid,"  grid on;\n");
191     // plot PSD
192     fprintf(fid,"f = [0:(nfft-1)]/nfft - 0.5;\n");
193     fprintf(fid,"subplot(3,4,9:12);\n");
194     fprintf(fid,"  plot(f,psd,'LineWidth',1.5);\n");
195     fprintf(fid,"  axis([-0.5 0.5 -60 20]);\n");
196     fprintf(fid,"  xlabel('Normalized Frequency [f/F_s]');\n");
197     fprintf(fid,"  ylabel('PSD [dB]');\n");
198     fprintf(fid,"  grid on;\n");
199 
200     fclose(fid);
201     printf("results written to '%s'\n", OUTPUT_FILENAME);
202 
203     return 0;
204 }
205