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