1 //
2 // fskmodem_example.c
3 //
4 // This example demostrates the M-ary frequency-shift keying
5 // (MFSK) 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 
15 #include "liquid.h"
16 
17 #define OUTPUT_FILENAME "fskmodem_example.m"
18 
19 // print usage/help message
usage()20 void usage()
21 {
22     printf("fskmodem_example -- frequency-shift keying example\n");
23     printf("options:\n");
24     printf("  h     : print help\n");
25     printf("  m     : bits/symbol,              default:  3\n");
26     printf("  k     : samples/symbol,           default:  2*2^m\n");
27     printf("  b     : signal bandwidth          default:  0.2\n");
28     printf("  n     : number of data symbols,   default: 80\n");
29     printf("  s     : SNR [dB],                 default: 40\n");
30 }
31 
main(int argc,char * argv[])32 int main(int argc, char*argv[])
33 {
34     // options
35     unsigned int m           =   3;     // number of bits/symbol
36     unsigned int k           =   0;     // filter samples/symbol
37     unsigned int num_symbols = 8000;    // number of data symbols
38     float        SNRdB       = 40.0f;   // signal-to-noise ratio [dB]
39     float        bandwidth   = 0.20;    // frequency spacing
40     unsigned int nfft        = 1200;    // FFT size for compute spectrum
41 
42     int dopt;
43     while ((dopt = getopt(argc,argv,"hm:k:b:n:s:")) != EOF) {
44         switch (dopt) {
45         case 'h': usage();                      return 0;
46         case 'm': m           = atoi(optarg);   break;
47         case 'k': k           = atoi(optarg);   break;
48         case 'b': bandwidth   = atof(optarg);   break;
49         case 'n': num_symbols = atoi(optarg);   break;
50         case 's': SNRdB       = atof(optarg);   break;
51         default:
52             exit(1);
53         }
54     }
55 
56     unsigned int i;
57     unsigned int j;
58 
59     // derived values
60     if (k == 0)
61         k = 2 << m; // set samples per symbol if not otherwise specified
62     unsigned int M    = 1 << m;
63     float        nstd = powf(10.0f, -SNRdB/20.0f);
64 
65     // validate input
66     if (k < M) {
67         fprintf(stderr,"errors: %s, samples/symbol must be at least modulation size (M=%u)\n", __FILE__,M);
68         exit(1);
69     } else if (k > 2048) {
70         fprintf(stderr,"errors: %s, samples/symbol exceeds maximum (2048)\n", __FILE__);
71         exit(1);
72     } else if (M > 1024) {
73         fprintf(stderr,"errors: %s, modulation size (M=%u) exceeds maximum (1024)\n", __FILE__, M);
74         exit(1);
75     } else if (bandwidth <= 0.0f || bandwidth >= 0.5f) {
76         fprintf(stderr,"errors: %s, bandwidht must be in (0,0.5)\n", __FILE__);
77         exit(1);
78     }
79 
80     // create modulator/demodulator pair
81     fskmod mod = fskmod_create(m,k,bandwidth);
82     fskdem dem = fskdem_create(m,k,bandwidth);
83     fskdem_print(dem);
84 
85     //
86     float complex buf_tx[k];    // transmit buffer
87     float complex buf_rx[k];    // transmit buffer
88 
89     // spectral periodogram
90     spgramcf periodogram = spgramcf_create_default(nfft);
91 
92     // modulate, demodulate, count errors
93     unsigned int num_symbol_errors = 0;
94     for (i=0; i<num_symbols; i++) {
95         // generate random symbol
96         unsigned int sym_in = rand() % M;
97 
98         // modulate
99         fskmod_modulate(mod, sym_in, buf_tx);
100 
101         // add noise
102         for (j=0; j<k; j++)
103             buf_rx[j] = buf_tx[j] + nstd*(randnf() + _Complex_I*randnf())*M_SQRT1_2;
104 
105         // demodulate
106         unsigned int sym_out = fskdem_demodulate(dem, buf_rx);
107 
108         // count errors
109         num_symbol_errors += (sym_in == sym_out) ? 0 : 1;
110 
111         // estimate power spectral density
112         spgramcf_write(periodogram, buf_rx, k);
113     }
114 
115     // destroy modulator/demodulator pair
116     fskmod_destroy(mod);
117     fskdem_destroy(dem);
118 
119     printf("symbol errors: %u / %u\n", num_symbol_errors, num_symbols);
120 
121     // compute power spectral density of received signal
122     float psd[nfft];
123     spgramcf_get_psd(periodogram, psd);
124     spgramcf_destroy(periodogram);
125 
126     //
127     // export results
128     //
129 
130     FILE * fid = fopen(OUTPUT_FILENAME,"w");
131     fprintf(fid,"%% %s : auto-generated file\n", OUTPUT_FILENAME);
132     fprintf(fid,"clear all\n");
133     fprintf(fid,"close all\n");
134     fprintf(fid,"k = %u;\n", k);
135     fprintf(fid,"M = %u;\n", M);
136     fprintf(fid,"num_symbols = %u;\n", num_symbols);
137     fprintf(fid,"nfft        = %u;\n", nfft);
138 
139     // save power spectral density
140     fprintf(fid,"psd = zeros(1,nfft);\n");
141     for (i=0; i<nfft; i++)
142         fprintf(fid,"psd(%4u) = %12.8f;\n", i+1, psd[i]);
143 
144     // plot PSD
145     fprintf(fid,"figure('Color','white');\n");
146     fprintf(fid,"f = [0:(nfft-1)]/nfft - 0.5;\n");
147     fprintf(fid,"plot(f,psd,'LineWidth',1.5,'Color',[0.5 0 0]);\n");
148     fprintf(fid,"axis([-0.5 0.5 -40 20]);\n");
149     fprintf(fid,"xlabel('Normalized Frequency [f/F_s]');\n");
150     fprintf(fid,"ylabel('PSD [dB]');\n");
151     fprintf(fid,"grid on;\n");
152 
153     fclose(fid);
154     printf("results written to '%s'\n", OUTPUT_FILENAME);
155 
156     return 0;
157 }
158