1 //
2 // fskmodem_waterfall_example.c
3 //
4 // This example demostrates the M-ary frequency-shift keying
5 // (MFSK) modem in liquid by showing the resulting spectral
6 // waterfall.
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 // print usage/help message
usage()18 void usage()
19 {
20     printf("fskmodem_waterfall_example -- frequency-shift keying waterfall example\n");
21     printf("options:\n");
22     printf("  -h       : print help\n");
23     printf("  -m <bps> : bits/symbol,            default:  2\n");
24     printf("  -b <bw>  : signal bandwidth        default:  0.2\n");
25     printf("  -n <num> : number of data symbols, default: 80\n");
26     printf("  -s <snr> : SNR [dB],               default: 40\n");
27 }
28 
main(int argc,char * argv[])29 int main(int argc, char*argv[])
30 {
31     // options
32     unsigned int m           =     2;   // number of bits/symbol
33     unsigned int num_symbols =   400;   // number of data symbols
34     float        SNRdB       = 30.0f;   // signal-to-noise ratio [dB]
35     float        bandwidth   =  0.10;   // frequency spacing
36 
37     int dopt;
38     while ((dopt = getopt(argc,argv,"hm:b:n:s:")) != EOF) {
39         switch (dopt) {
40         case 'h': usage();                      return 0;
41         case 'm': m           = atoi(optarg);   break;
42         case 'b': bandwidth   = atof(optarg);   break;
43         case 'n': num_symbols = atoi(optarg);   break;
44         case 's': SNRdB       = atof(optarg);   break;
45         default:
46             exit(1);
47         }
48     }
49 
50     unsigned int i;
51     unsigned int j;
52 
53     // derived values
54     unsigned int M    = 1 << m;     // constellation size
55     unsigned int k    = 500 * M;    // samples per symbol (highly over-sampled)
56     float        nstd = powf(10.0f, -SNRdB/20.0f);  // noise std. dev.
57 
58     // validate input
59     if (k < M) {
60         fprintf(stderr,"errors: %s, samples/symbol must be at least modulation size (M=%u)\n", __FILE__,M);
61         exit(1);
62     } else if (k > 2048) {
63         fprintf(stderr,"errors: %s, samples/symbol exceeds maximum (2048)\n", __FILE__);
64         exit(1);
65     } else if (M > 1024) {
66         fprintf(stderr,"errors: %s, modulation size (M=%u) exceeds maximum (1024)\n", __FILE__, M);
67         exit(1);
68     } else if (bandwidth <= 0.0f || bandwidth >= 0.5f) {
69         fprintf(stderr,"errors: %s, bandwidht must be in (0,0.5)\n", __FILE__);
70         exit(1);
71     }
72 
73     // create spectral waterfall object
74     unsigned int nfft  = 1 << liquid_nextpow2(k);
75     int          wtype = LIQUID_WINDOW_HAMMING;
76     unsigned int wlen  = nfft/2;
77     unsigned int delay = nfft/2;
78     unsigned int time  =    512;
79     spwaterfallcf periodogram = spwaterfallcf_create(nfft,wtype,wlen,delay,time);
80     spwaterfallcf_print(periodogram);
81 
82     // create modulator/demodulator pair
83     fskmod mod = fskmod_create(m,k,bandwidth);
84 
85     float complex buf_tx[k];    // transmit buffer
86     float complex buf_rx[k];    // transmit buffer
87 
88     // modulate, demodulate, count errors
89     for (i=0; i<num_symbols; i++) {
90         // generate random symbol
91         unsigned int sym_in = rand() % M;
92 
93         // modulate
94         fskmod_modulate(mod, sym_in, buf_tx);
95 
96         // add noise
97         for (j=0; j<k; j++)
98             buf_rx[j] = buf_tx[j] + nstd*(randnf() + _Complex_I*randnf())*M_SQRT1_2;
99 
100         // estimate power spectral density
101         spwaterfallcf_write(periodogram, buf_rx, k);
102     }
103 
104     // export output files
105     spwaterfallcf_export(periodogram,"fskmodem_waterfall_example");
106 
107     // destroy objects
108     spwaterfallcf_print(periodogram);
109     fskmod_destroy(mod);
110 
111     return 0;
112 }
113