File: eqlms_cccf_block_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 (188 lines) | stat: -rw-r--r-- 7,098 bytes parent folder | download | duplicates (5)
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
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
// 
// eqlms_cccf_block_example.c
//
// This example tests the least mean-squares (LMS) equalizer (EQ) on a
// signal with an unknown modulation and carrier frequency offset.
// Equalization is performed blind on a block of samples and the reulting
// constellation is output to a file for plotting.
//

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <complex.h>
#include <getopt.h>
#include <time.h>
#include "liquid.h"

#define OUTPUT_FILENAME "eqlms_cccf_block_example.m"

// print usage/help message
void usage()
{
    printf("Usage: eqlms_cccf_block_example [OPTION]\n");
    printf("  h     : print help\n");
    printf("  n     : number of symbols, default: 500\n");
    printf("  c     : number of channel filter taps (minimum: 1), default: 5\n");
    printf("  k     : samples/symbol, default: 2\n");
    printf("  m     : filter semi-length (symbols), default: 4\n");
    printf("  b     : filter excess bandwidth factor, default: 0.3\n");
    printf("  p     : equalizer semi-length (symbols), default: 3\n");
    printf("  u     : equalizer learning rate, default; 0.05\n");
}

int main(int argc, char*argv[])
{
    //srand(time(NULL));

    // options
    unsigned int    num_samples = 2400;     // number of symbols to observe
    unsigned int    hc_len      = 5;        // channel filter length
    unsigned int    k           = 2;        // matched filter samples/symbol
    unsigned int    m           = 3;        // matched filter delay (symbols)
    float           beta        = 0.3f;     // matched filter excess bandwidth factor
    unsigned int    p           = 3;        // equalizer length (symbols, hp_len = 2*k*p+1)
    float           mu          = 0.15f;    // equalizer learning rate
    modulation_scheme ms        = LIQUID_MODEM_QPSK;

    int dopt;
    while ((dopt = getopt(argc,argv,"hn:c:k:m:b:p:u:")) != EOF) {
        switch (dopt) {
        case 'h': usage();                      return 0;
        case 'n': num_samples   = atoi(optarg); break;
        case 'c': hc_len        = atoi(optarg); break;
        case 'k': k             = atoi(optarg); break;
        case 'm': m             = atoi(optarg); break;
        case 'b': beta          = atof(optarg); break;
        case 'p': p             = atoi(optarg); break;
        case 'u': mu            = atof(optarg); break;
        default:
            exit(1);
        }
    }
    unsigned int i;

    // validate input
    if (num_samples == 0) {
        fprintf(stderr,"error: %s, number of symbols must be greater than zero\n", argv[0]);
        exit(1);
    } else if (hc_len == 0) {
        fprintf(stderr,"error: %s, channel must have at least 1 tap\n", argv[0]);
        exit(1);
    } else if (k < 2) {
        fprintf(stderr,"error: %s, samples/symbol must be at least 2\n", argv[0]);
        exit(1);
    } else if (m == 0) {
        fprintf(stderr,"error: %s, filter semi-length must be at least 1 symbol\n", argv[0]);
        exit(1);
    } else if (beta < 0.0f || beta > 1.0f) {
        fprintf(stderr,"error: %s, filter excess bandwidth must be in [0,1]\n", argv[0]);
        exit(1);
    } else if (p == 0) {
        fprintf(stderr,"error: %s, equalizer semi-length must be at least 1 symbol\n", argv[0]);
        exit(1);
    } else if (mu < 0.0f || mu > 1.0f) {
        fprintf(stderr,"error: %s, equalizer learning rate must be in [0,1]\n", argv[0]);
        exit(1);
    }

    // derived/fixed values
    unsigned int    buf_len = 37;
    float complex   buf_input  [buf_len];
    float complex   buf_channel[buf_len];
    float complex   buf_output [buf_len];

    // 
    // generate input sequence using symbol stream generator
    //
    symstreamcf gen = symstreamcf_create_linear(LIQUID_FIRFILT_ARKAISER,k,m,beta,ms);

    //
    // create multi-path channel filter
    //
    float complex hc[hc_len];
    for (i=0; i<hc_len; i++)
        hc[i] = (i==0) ? 0.5f : (randnf() + _Complex_I*randnf())*0.2f;
    firfilt_cccf channel = firfilt_cccf_create(hc, hc_len);

    //
    // create equalizer
    //
    eqlms_cccf eq = eqlms_cccf_create_rnyquist(LIQUID_FIRFILT_RRC, k, p, beta, 0.0f);
    eqlms_cccf_set_bw(eq, mu);

    FILE * fid = fopen(OUTPUT_FILENAME,"w");
    fprintf(fid,"%% %s : auto-generated file\n\n", OUTPUT_FILENAME);
    fprintf(fid,"clear all\n");
    fprintf(fid,"close all\n");
    fprintf(fid,"x = [];\n");
    fprintf(fid,"y = [];\n");
    fprintf(fid,"z = [];\n");

    unsigned int num_samples_total = 0;
    while (num_samples_total < num_samples)
    {
        // generate block of input samples
        symstreamcf_write_samples(gen, buf_input, buf_len);

        // apply channel to input signal
        firfilt_cccf_execute_block(channel, buf_input, buf_len, buf_channel);

        // run equalizer
        eqlms_cccf_execute_block(eq, k, buf_channel, buf_len, buf_output);
        
        // save results to output file
        for (i=0; i<buf_len; i++) {
            fprintf(fid,"x(end+1) = %12.4e + %12.4ei;\n", crealf(buf_input  [i]), cimagf(buf_input  [i]));
            fprintf(fid,"y(end+1) = %12.4e + %12.4ei;\n", crealf(buf_channel[i]), cimagf(buf_channel[i]));
            fprintf(fid,"z(end+1) = %12.4e + %12.4ei;\n", crealf(buf_output [i]), cimagf(buf_output [i]));
        }

        // increment number of samples
        num_samples_total += buf_len;
    }

    // destroy objects
    symstreamcf_destroy(gen);
    firfilt_cccf_destroy(channel);
    eqlms_cccf_destroy(eq);

    fprintf(fid,"k = %u;\n", k);
    fprintf(fid,"m = %u;\n", m);
    fprintf(fid,"n = length(x);\n");

    fprintf(fid,"figure('Color','white','position',[500 500 1200 500]);\n");
    // plot constellation
    fprintf(fid,"subplot(2,8,[5 6 7 8 13 14 15 16]),\n");
    fprintf(fid,"  s = 1:k:n;\n");
    fprintf(fid,"  s0 = round(length(s)/2);\n");
    fprintf(fid,"  syms_rx_0 = z(s(1:s0));\n");
    fprintf(fid,"  syms_rx_1 = z(s(s0:end));\n");
    fprintf(fid,"  plot(real(syms_rx_0),imag(syms_rx_0),'x','Color',[1 1 1]*0.7,...\n");
    fprintf(fid,"       real(syms_rx_1),imag(syms_rx_1),'x','Color',[1 1 1]*0.0);\n");
    fprintf(fid,"  xlabel('In-Phase');\n");
    fprintf(fid,"  ylabel('Quadrature');\n");
    fprintf(fid,"  axis([-1 1 -1 1]*1.5);\n");
    fprintf(fid,"  axis square;\n");
    fprintf(fid,"  grid on;\n");
    // plot time response
    fprintf(fid,"t = 0:(n-1);\n");
    fprintf(fid,"subplot(2,8,1:4),\n");
    fprintf(fid,"  plot(t,   real(z),   '-','Color',[1 1 1]*0.7,...\n");
    fprintf(fid,"       t(s),real(z(s)),'s','Color',[0 0.2 0.5],'MarkerSize',3);\n");
    fprintf(fid,"  axis([0 n -1.5 1.5]);\n");
    fprintf(fid,"  grid on;\n");
    fprintf(fid,"  ylabel('real');\n");
    fprintf(fid,"subplot(2,8,9:12),\n");
    fprintf(fid,"  plot(t,   imag(z),   '-','Color',[1 1 1]*0.7,...\n");
    fprintf(fid,"       t(s),imag(z(s)),'s','Color',[0 0.5 0.2],'MarkerSize',3);\n");
    fprintf(fid,"  axis([0 n -1.5 1.5]);\n");
    fprintf(fid,"  grid on;\n");
    fprintf(fid,"  ylabel('imag');\n");

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

    return 0;
}