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