-
Notifications
You must be signed in to change notification settings - Fork 15
/
Copy pathsimplex_regression_test.cc
136 lines (114 loc) · 3.54 KB
/
simplex_regression_test.cc
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
/*
Regression Test for the Simplex code Encoder and soft Decoder
Copyright 2020 Ahmet Inan <inan@aicodix.de>
*/
#include <iostream>
#include <random>
#include <cmath>
#include <cassert>
#include <algorithm>
#include <functional>
#include "simplex_encoder.hh"
#include "simplex_decoder.hh"
template<typename TYPE>
int popcnt(TYPE x)
{
int cnt = 0;
while (x) {
++cnt;
x &= x-1;
}
return cnt;
}
#if 0
const int LOOPS = 320000;
const float QEF_SNR = 7.0;
const int DATA_LEN = 2;
#endif
#if 0
const int LOOPS = 160000;
const float QEF_SNR = 4.5;
const int DATA_LEN = 3;
#endif
#if 1
const int LOOPS = 80000;
const float QEF_SNR = 2.0;
const int DATA_LEN = 4;
#endif
#if 0
const int LOOPS = 40000;
const float QEF_SNR = -1.0;
const int DATA_LEN = 5;
#endif
#if 0
const int LOOPS = 20000;
const float QEF_SNR = -3.5;
const int DATA_LEN = 6;
#endif
int main()
{
const int CODE_LEN = (1 << DATA_LEN) - 1;
CODE::SimplexEncoder<DATA_LEN> encode;
CODE::SimplexDecoder<DATA_LEN> decode;
std::random_device rd;
std::default_random_engine generator(rd());
typedef std::uniform_int_distribution<int> uniform;
typedef std::normal_distribution<float> normal;
float min_SNR = 20;
for (float SNR = -10; SNR <= 10; SNR += 0.1) {
//float mean_signal = 0;
float sigma_signal = 1;
float mean_noise = 0;
float sigma_noise = std::sqrt(sigma_signal * sigma_signal / (2 * std::pow(10, SNR / 10)));
auto data = std::bind(uniform(0, (1 << DATA_LEN) - 1), generator);
auto awgn = std::bind(normal(mean_noise, sigma_noise), generator);
int awgn_errors = 0;
int quantization_erasures = 0;
int uncorrected_errors = 0;
int ambiguity_errors = 0;
for (int loop = 0; loop < LOOPS; ++loop) {
int8_t code[CODE_LEN], orig[CODE_LEN], noisy[CODE_LEN];
float symb[CODE_LEN];
int dat = data();
encode(code, dat);
for (int i = 0; i < CODE_LEN; ++i)
orig[i] = code[i];
for (int i = 0; i < CODE_LEN; ++i)
symb[i] = code[i];
for (int i = 0; i < CODE_LEN; ++i)
symb[i] += awgn();
// $LLR=log(\frac{p(x=+1|y)}{p(x=-1|y)})$
// $p(x|\mu,\sigma)=\frac{1}{\sqrt{2\pi}\sigma}}e^{-\frac{(x-\mu)^2}{2\sigma^2}}$
float DIST = 2; // BPSK
float fact = DIST / (sigma_noise * sigma_noise);
for (int i = 0; i < CODE_LEN; ++i)
code[i] = std::min<float>(std::max<float>(std::nearbyint(fact * symb[i]), -127), 127);
for (int i = 0; i < CODE_LEN; ++i)
noisy[i] = code[i];
int dec = decode(code);
for (int i = 0; i < CODE_LEN; ++i)
awgn_errors += noisy[i] * orig[i] < 0;
for (int i = 0; i < CODE_LEN; ++i)
quantization_erasures += !noisy[i];
uncorrected_errors += dec < 0 ? DATA_LEN : popcnt(dat^dec);
ambiguity_errors += dec < 0;
}
float bit_error_rate = (float)uncorrected_errors / (float)(DATA_LEN * LOOPS);
if (bit_error_rate < 0.0001)
min_SNR = std::min(min_SNR, SNR);
if (0) {
std::cerr << SNR << " Es/N0 => AWGN with standard deviation of " << sigma_noise << " and mean " << mean_noise << std::endl;
std::cerr << awgn_errors << " errors caused by AWGN." << std::endl;
std::cerr << quantization_erasures << " erasures caused by quantization." << std::endl;
std::cerr << ambiguity_errors << " ambiguity errors." << std::endl;
std::cerr << uncorrected_errors << " errors uncorrected." << std::endl;
std::cerr << bit_error_rate << " bit error rate." << std::endl;
} else {
std::cout << SNR << " " << bit_error_rate << std::endl;
}
}
std::cerr << "QEF at: " << min_SNR << " SNR" << std::endl;
assert(min_SNR < QEF_SNR);
std::cerr << "Simplex code regression test passed!" << std::endl;
return 0;
}