File: fskmodem_example.c

package info (click to toggle)
liquid-dsp 1.7.0-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 9,216 kB
  • sloc: ansic: 115,859; sh: 3,513; makefile: 1,350; python: 274; asm: 11
file content (157 lines) | stat: -rw-r--r-- 5,022 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
// 
// fskmodem_example.c
//
// This example demonstrates the M-ary frequency-shift keying
// (MFSK) modem in liquid. A message signal is modulated and the
// resulting signal is recovered using a demodulator object.
//

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <getopt.h>
#include <math.h>

#include "liquid.h"

#define OUTPUT_FILENAME "fskmodem_example.m"

// print usage/help message
void usage()
{
    printf("fskmodem_example -- frequency-shift keying example\n");
    printf("options:\n");
    printf("  h     : print help\n");
    printf("  m     : bits/symbol,              default:  3\n");
    printf("  k     : samples/symbol,           default:  2*2^m\n");
    printf("  b     : signal bandwidth          default:  0.2\n");
    printf("  n     : number of data symbols,   default: 80\n");
    printf("  s     : SNR [dB],                 default: 40\n");
}

int main(int argc, char*argv[])
{
    // options
    unsigned int m           =   3;     // number of bits/symbol
    unsigned int k           =   0;     // filter samples/symbol
    unsigned int num_symbols = 8000;    // number of data symbols
    float        SNRdB       = 40.0f;   // signal-to-noise ratio [dB]
    float        bandwidth   = 0.20;    // frequency spacing
    unsigned int nfft        = 1200;    // FFT size for compute spectrum

    int dopt;
    while ((dopt = getopt(argc,argv,"hm:k:b:n:s:")) != EOF) {
        switch (dopt) {
        case 'h': usage();                      return 0;
        case 'm': m           = atoi(optarg);   break;
        case 'k': k           = atoi(optarg);   break;
        case 'b': bandwidth   = atof(optarg);   break;
        case 'n': num_symbols = atoi(optarg);   break;
        case 's': SNRdB       = atof(optarg);   break;
        default:
            exit(1);
        }
    }

    unsigned int i;
    unsigned int j;

    // derived values
    if (k == 0)
        k = 2 << m; // set samples per symbol if not otherwise specified
    unsigned int M    = 1 << m;
    float        nstd = powf(10.0f, -SNRdB/20.0f);

    // validate input
    if (k < M) {
        fprintf(stderr,"errors: %s, samples/symbol must be at least modulation size (M=%u)\n", __FILE__,M);
        exit(1);
    } else if (k > 2048) {
        fprintf(stderr,"errors: %s, samples/symbol exceeds maximum (2048)\n", __FILE__);
        exit(1);
    } else if (M > 1024) {
        fprintf(stderr,"errors: %s, modulation size (M=%u) exceeds maximum (1024)\n", __FILE__, M);
        exit(1);
    } else if (bandwidth <= 0.0f || bandwidth >= 0.5f) {
        fprintf(stderr,"errors: %s, bandwidth must be in (0,0.5)\n", __FILE__);
        exit(1);
    }

    // create modulator/demodulator pair
    fskmod mod = fskmod_create(m,k,bandwidth);
    fskdem dem = fskdem_create(m,k,bandwidth);
    fskdem_print(dem);

    // 
    float complex buf_tx[k];    // transmit buffer
    float complex buf_rx[k];    // transmit buffer
    
    // spectral periodogram
    spgramcf periodogram = spgramcf_create_default(nfft);

    // modulate, demodulate, count errors
    unsigned int num_symbol_errors = 0;
    for (i=0; i<num_symbols; i++) {
        // generate random symbol
        unsigned int sym_in = rand() % M;

        // modulate
        fskmod_modulate(mod, sym_in, buf_tx);

        // add noise
        for (j=0; j<k; j++)
            buf_rx[j] = buf_tx[j] + nstd*(randnf() + _Complex_I*randnf())*M_SQRT1_2;

        // demodulate
        unsigned int sym_out = fskdem_demodulate(dem, buf_rx);

        // count errors
        num_symbol_errors += (sym_in == sym_out) ? 0 : 1;

        // estimate power spectral density
        spgramcf_write(periodogram, buf_rx, k);
    }

    // destroy modulator/demodulator pair
    fskmod_destroy(mod);
    fskdem_destroy(dem);

    printf("symbol errors: %u / %u\n", num_symbol_errors, num_symbols);

    // compute power spectral density of received signal
    float psd[nfft];
    spgramcf_get_psd(periodogram, psd);
    spgramcf_destroy(periodogram);

    // 
    // export results
    //
    
    FILE * fid = fopen(OUTPUT_FILENAME,"w");
    fprintf(fid,"%% %s : auto-generated file\n", OUTPUT_FILENAME);
    fprintf(fid,"clear all\n");
    fprintf(fid,"close all\n");
    fprintf(fid,"k = %u;\n", k);
    fprintf(fid,"M = %u;\n", M);
    fprintf(fid,"num_symbols = %u;\n", num_symbols);
    fprintf(fid,"nfft        = %u;\n", nfft);

    // save power spectral density
    fprintf(fid,"psd = zeros(1,nfft);\n");
    for (i=0; i<nfft; i++)
        fprintf(fid,"psd(%4u) = %12.8f;\n", i+1, psd[i]);

    // plot PSD
    fprintf(fid,"figure('Color','white');\n");
    fprintf(fid,"f = [0:(nfft-1)]/nfft - 0.5;\n");
    fprintf(fid,"plot(f,psd,'LineWidth',1.5,'Color',[0.5 0 0]);\n");
    fprintf(fid,"axis([-0.5 0.5 -40 20]);\n");
    fprintf(fid,"xlabel('Normalized Frequency [f/F_s]');\n");
    fprintf(fid,"ylabel('PSD [dB]');\n");
    fprintf(fid,"grid on;\n");

    fclose(fid);
    printf("results written to '%s'\n", OUTPUT_FILENAME);

    return 0;
}