1 //
2 // fecsoft_ber_test.c
3 //
4 // Simulate error rate using soft vs. hard decoding
5 //
6 
7 #include <stdio.h>
8 #include <stdlib.h>
9 #include <math.h>
10 #include <complex.h>
11 #include <time.h>
12 #include <getopt.h>
13 
14 #include "liquid.h"
15 
16 #define OUTPUT_FILENAME "fecsoft_ber_test.m"
17 
usage()18 void usage()
19 {
20     printf("fec_ber\n");
21     printf("  Simulates soft decoding\n");
22     printf("options:\n");
23     printf("  u/h   : print usage/help\n");
24     printf("  s     : SNR start [dB], default: -2\n");
25     printf("  x     : SNR max [dB], default: 13\n");
26     printf("  n     : number of SNR steps, default: 16\n");
27     printf("  t     : number of trials, default: 800\n");
28     printf("  f     : frame size, default: 64\n");
29     printf("  c     : coding scheme, (h74 default):\n");
30     liquid_print_fec_schemes();
31 }
32 
main(int argc,char * argv[])33 int main(int argc, char *argv[]) {
34     // set initial seed to random
35     srand(time(NULL));
36 
37     // options
38     unsigned int n = 64;                    // frame size (bytes)
39     float SNRdB_min = -2.0f;                // signal-to-noise ratio (minimum)
40     float SNRdB_max = 13.0f;                // signal-to-noise ratio (maximum)
41     unsigned int num_snr = 16;              // number of SNR steps
42     unsigned int num_trials=800;            // number of trials
43     fec_scheme fs = LIQUID_FEC_HAMMING74;   // error-correcting scheme
44 
45     // get command-line options
46     int dopt;
47     while((dopt = getopt(argc,argv,"uhs:x:n:t:f:c:")) != EOF){
48         switch (dopt) {
49         case 'h':
50         case 'u': usage(); return 0;
51         case 's': SNRdB_min = atof(optarg);     break;
52         case 'x': SNRdB_max = atof(optarg);     break;
53         case 'n': num_snr = atoi(optarg);       break;
54         case 't': num_trials = atoi(optarg);    break;
55         case 'f': n = atoi(optarg);             break;
56         case 'c':
57             fs = liquid_getopt_str2fec(optarg);
58             if (fs == LIQUID_FEC_UNKNOWN) {
59                 fprintf(stderr,"error: unknown/unsupported fec scheme \"%s\"\n\n",optarg);
60                 exit(1);
61             }
62             break;
63         default:
64             exit(1);
65         }
66     }
67 
68     unsigned int i;
69 
70     // create arrays
71     unsigned int n_enc = fec_get_enc_msg_length(fs,n);
72     printf("dec msg len : %u\n", n);
73     printf("enc msg len : %u\n", n_enc);
74     float rate = (float)n / (float)n_enc;
75     unsigned char msg_org[n];            // original data message
76     unsigned char msg_enc[n_enc];        // encoded data message
77     float complex sym_rec[8*n_enc];      // received BPSK symbols
78     unsigned char msg_cor_soft[8*n_enc]; // corrupted data message (soft bits)
79     unsigned char msg_cor_hard[n_enc];   // corrupted data message (hard bits)
80     unsigned char msg_dec_soft[n];       // decoded data message (soft bits)
81     unsigned char msg_dec_hard[n];       // decoded data message (soft bits)
82 
83     // create object
84     fec q = fec_create(fs,NULL);
85     fec_print(q);
86 
87     unsigned int bit_errors_soft[num_snr];
88     unsigned int bit_errors_hard[num_snr];
89 
90     //
91     // set up parameters
92     //
93     float SNRdB_step = (SNRdB_max - SNRdB_min) / (num_snr-1);
94 
95     //
96     // start trials
97     //
98 
99     printf("  %8s %8s [%8s] %8s %12s %8s %12s %12s\n",
100             "SNR [dB]", "Eb/N0", "trials", "soft", "(BER)", "hard", "(BER)", "uncoded");
101     unsigned int s;
102     for (s=0; s<num_snr; s++) {
103         // compute SNR for this level
104         float SNRdB = SNRdB_min + s*SNRdB_step; // SNR in dB for this round
105         float nstd = powf(10.0f, -SNRdB/20.0f); // noise standard deviation
106 
107         // reset results
108         bit_errors_soft[s] = 0;
109         bit_errors_hard[s] = 0;
110 
111         unsigned int t;
112         for (t=0; t<num_trials; t++) {
113             // generate data
114             for (i=0; i<n; i++)
115                 msg_org[i] = rand() & 0xff;
116 
117             // encode message
118             fec_encode(q, n, msg_org, msg_enc);
119 
120             // modulate with BPSK
121             for (i=0; i<n_enc; i++) {
122                 sym_rec[8*i+0] = (msg_enc[i] & 0x80) ? 1.0f : -1.0f;
123                 sym_rec[8*i+1] = (msg_enc[i] & 0x40) ? 1.0f : -1.0f;
124                 sym_rec[8*i+2] = (msg_enc[i] & 0x20) ? 1.0f : -1.0f;
125                 sym_rec[8*i+3] = (msg_enc[i] & 0x10) ? 1.0f : -1.0f;
126                 sym_rec[8*i+4] = (msg_enc[i] & 0x08) ? 1.0f : -1.0f;
127                 sym_rec[8*i+5] = (msg_enc[i] & 0x04) ? 1.0f : -1.0f;
128                 sym_rec[8*i+6] = (msg_enc[i] & 0x02) ? 1.0f : -1.0f;
129                 sym_rec[8*i+7] = (msg_enc[i] & 0x01) ? 1.0f : -1.0f;
130             }
131 
132             // add noise
133             for (i=0; i<8*n_enc; i++)
134                 sym_rec[i] += nstd*(randnf() + _Complex_I*randf())*M_SQRT1_2;
135 
136             // demodulate using LLR
137             for (i=0; i<8*n_enc; i++) {
138                 float LLR = 2.0f * crealf(sym_rec[i]);
139                 int soft_bit = (int) (16*LLR + 127);
140                 if (soft_bit > 255) soft_bit = 255;
141                 if (soft_bit <   0) soft_bit = 0;
142                 msg_cor_soft[i] = (unsigned char)(soft_bit);
143             }
144 
145             // convert to hard bits (hard decoding)
146             for (i=0; i<n_enc; i++) {
147                 msg_cor_hard[i] = 0x00;
148 
149                 msg_cor_hard[i] |= crealf(sym_rec[8*i+0]) > 0.0f ? 0x80 : 0x00;
150                 msg_cor_hard[i] |= crealf(sym_rec[8*i+1]) > 0.0f ? 0x40 : 0x00;
151                 msg_cor_hard[i] |= crealf(sym_rec[8*i+2]) > 0.0f ? 0x20 : 0x00;
152                 msg_cor_hard[i] |= crealf(sym_rec[8*i+3]) > 0.0f ? 0x10 : 0x00;
153                 msg_cor_hard[i] |= crealf(sym_rec[8*i+4]) > 0.0f ? 0x08 : 0x00;
154                 msg_cor_hard[i] |= crealf(sym_rec[8*i+5]) > 0.0f ? 0x04 : 0x00;
155                 msg_cor_hard[i] |= crealf(sym_rec[8*i+6]) > 0.0f ? 0x02 : 0x00;
156                 msg_cor_hard[i] |= crealf(sym_rec[8*i+7]) > 0.0f ? 0x01 : 0x00;
157             }
158 
159             // decode
160             fec_decode(     q, n, msg_cor_hard, msg_dec_hard);
161             fec_decode_soft(q, n, msg_cor_soft, msg_dec_soft);
162 
163             // tabulate results
164             bit_errors_soft[s] += count_bit_errors_array(msg_org, msg_dec_soft, n);
165             bit_errors_hard[s] += count_bit_errors_array(msg_org, msg_dec_hard, n);
166         }
167 
168         // print results for this SNR step
169         printf("  %8.3f %8.3f [%8u] %8u %12.4e %8u %12.4e %12.4e\n",
170                 SNRdB,
171                 SNRdB - 10*log10f(rate),
172                 8*n*num_trials,
173                 bit_errors_soft[s], (float)(bit_errors_soft[s]) / (float)(num_trials*n*8),
174                 bit_errors_hard[s], (float)(bit_errors_hard[s]) / (float)(num_trials*n*8),
175                 0.5f*erfcf(1.0f/nstd));
176     }
177 
178     // clean up objects
179     fec_destroy(q);
180 
181     //
182     // export output file
183     //
184     FILE * fid = fopen(OUTPUT_FILENAME, "w");
185     fprintf(fid,"%% %s : auto-generated file\n", OUTPUT_FILENAME);
186     fprintf(fid,"\n\n");
187     fprintf(fid,"clear all\n");
188     fprintf(fid,"close all\n");
189     fprintf(fid,"n = %u;    %% frame size [bytes]\n", n);
190     fprintf(fid,"k = %u;    %% encoded frame size [bytes]\n", n_enc);
191     fprintf(fid,"r = n / k; %% true rate\n");
192     fprintf(fid,"num_snr = %u;\n", num_snr);
193     fprintf(fid,"num_trials = %u;\n", num_trials);
194     fprintf(fid,"num_bit_trials = num_trials*n*8;\n");
195     for (i=0; i<num_snr; i++) {
196         fprintf(fid,"SNRdB(%4u) = %12.8f;\n",i+1, SNRdB_min + i*SNRdB_step);
197         fprintf(fid,"bit_errors_soft(%6u) = %u;\n", i+1, bit_errors_soft[i]);
198         fprintf(fid,"bit_errors_hard(%6u) = %u;\n", i+1, bit_errors_hard[i]);
199     }
200     fprintf(fid,"EbN0dB = SNRdB - 10*log10(r);\n");
201     fprintf(fid,"EbN0dB_bpsk = -15:0.5:40;\n");
202     fprintf(fid,"\n\n");
203     fprintf(fid,"figure;\n");
204     fprintf(fid,"semilogy(EbN0dB_bpsk, 0.5*erfc(sqrt(10.^[EbN0dB_bpsk/10]))+1e-12,'-x',\n");
205     fprintf(fid,"         EbN0dB,      bit_errors_soft / num_bit_trials + 1e-12,  '-x',\n");
206     fprintf(fid,"         EbN0dB,      bit_errors_hard / num_bit_trials + 1e-12,  '-x');\n");
207     fprintf(fid,"axis([%f (%f-10*log10(r)) 1e-6 1]);\n", SNRdB_min, SNRdB_max);
208     fprintf(fid,"legend('uncoded','soft','hard',1);\n");
209     fprintf(fid,"xlabel('E_b/N_0 [dB]');\n");
210     fprintf(fid,"ylabel('Bit Error Rate');\n");
211     fprintf(fid,"title('BER vs. E_b/N_0 for %s');\n", fec_scheme_str[fs][1]);
212     fprintf(fid,"grid on;\n");
213 
214     fprintf(fid,"\n\n");
215     fprintf(fid,"figure;\n");
216     fprintf(fid,"semilogy(EbN0dB_bpsk, 0.5*erfc(sqrt(10.^[EbN0dB_bpsk/10]))+1e-12,'-x',\n");
217     fprintf(fid,"         SNRdB,       bit_errors_soft / num_bit_trials + 1e-12,  '-x',\n");
218     fprintf(fid,"         SNRdB,       bit_errors_hard / num_bit_trials + 1e-12,  '-x');\n");
219     fprintf(fid,"axis([%f %f 1e-6 1]);\n", SNRdB_min, SNRdB_max);
220     fprintf(fid,"legend('uncoded','soft','hard',1);\n");
221     fprintf(fid,"xlabel('SNR [dB]');\n");
222     fprintf(fid,"ylabel('Bit Error Rate');\n");
223     fprintf(fid,"title('BER vs. SNR for %s');\n", fec_scheme_str[fs][1]);
224     fprintf(fid,"grid on;\n");
225 
226     fclose(fid);
227     printf("results written to %s\n", OUTPUT_FILENAME);
228 
229     printf("done.\n");
230     return 0;
231 }
232 
233