mirror of
https://github.com/aicodix/code.git
synced 2026-04-27 22:35:44 +00:00
added LDPC encoder and layered decoder
lifted from my LDPC project: https://github.com/xdsopl/LDPC
This commit is contained in:
parent
e51425e121
commit
199a988def
4 changed files with 536 additions and 0 deletions
|
|
@ -48,6 +48,15 @@ Implemented are the following Encoders and Decoders:
|
|||
* [bose_chaudhuri_hocquenghem_encoder.hh](bose_chaudhuri_hocquenghem_encoder.hh)
|
||||
* [bose_chaudhuri_hocquenghem_decoder.hh](bose_chaudhuri_hocquenghem_decoder.hh)
|
||||
|
||||
|
||||
### [ldpc_encoder.hh](ldpc_encoder.hh)
|
||||
|
||||
[Low-density parity-check](https://en.wikipedia.org/wiki/Low-density_parity-check_code) encoder
|
||||
|
||||
### [ldpc_decoder.hh](ldpc_decoder.hh)
|
||||
|
||||
[Low-density parity-check](https://en.wikipedia.org/wiki/Low-density_parity-check_code) layered decoder
|
||||
|
||||
### [exclusive_reduce.hh](exclusive_reduce.hh)
|
||||
|
||||
Reduce N times while excluding ith input element
|
||||
|
|
|
|||
220
ldpc_decoder.hh
Normal file
220
ldpc_decoder.hh
Normal file
|
|
@ -0,0 +1,220 @@
|
|||
/*
|
||||
LDPC SISO layered decoder
|
||||
|
||||
Copyright 2018 Ahmet Inan <inan@aicodix.de>
|
||||
*/
|
||||
|
||||
#ifndef LDPC_DECODER_HH
|
||||
#define LDPC_DECODER_HH
|
||||
|
||||
#include <algorithm>
|
||||
#include "exclusive_reduce.hh"
|
||||
|
||||
namespace CODE {
|
||||
|
||||
template <typename TABLE, int BETA>
|
||||
class LDPCDecoder
|
||||
{
|
||||
static const int M = TABLE::M;
|
||||
static const int N = TABLE::N;
|
||||
static const int K = TABLE::K;
|
||||
static const int R = N-K;
|
||||
static const int q = R/M;
|
||||
static const int CNC = TABLE::LINKS_MAX_CN - 2;
|
||||
static const int LT = TABLE::LINKS_TOTAL;
|
||||
|
||||
int8_t bnl[LT];
|
||||
int8_t pty[R];
|
||||
uint16_t pos[R * CNC];
|
||||
uint8_t cnc[R];
|
||||
|
||||
static int8_t sqadd(int8_t a, int8_t b)
|
||||
{
|
||||
int16_t x = int16_t(a) + int16_t(b);
|
||||
x = std::min<int16_t>(std::max<int16_t>(x, -128), 127);
|
||||
return x;
|
||||
}
|
||||
static int8_t sqsub(int8_t a, int8_t b)
|
||||
{
|
||||
int16_t x = int16_t(a) - int16_t(b);
|
||||
x = std::min<int16_t>(std::max<int16_t>(x, -128), 127);
|
||||
return x;
|
||||
}
|
||||
static uint8_t sqsubu(uint8_t a, uint8_t b)
|
||||
{
|
||||
int16_t x = int16_t(a) - int16_t(b);
|
||||
x = std::max<int16_t>(x, 0);
|
||||
return x;
|
||||
}
|
||||
static int8_t smin(int8_t a, int8_t b)
|
||||
{
|
||||
return std::min(a, b);
|
||||
}
|
||||
static int8_t sclamp(int8_t x, int8_t a, int8_t b)
|
||||
{
|
||||
return std::min(std::max(x, a), b);
|
||||
}
|
||||
static int8_t seor(int8_t a, int8_t b)
|
||||
{
|
||||
return a ^ b;
|
||||
}
|
||||
static int8_t sqabs(int8_t a)
|
||||
{
|
||||
return std::abs(std::max<int8_t>(a, -127));
|
||||
}
|
||||
static int8_t ssign(int8_t a, int8_t b)
|
||||
{
|
||||
return ((b > 0) - (b < 0)) * a;
|
||||
}
|
||||
|
||||
bool bad(int8_t *data, int8_t *parity)
|
||||
{
|
||||
{
|
||||
int cnt = cnc[0];
|
||||
{
|
||||
int8_t cnv = ssign(1, parity[0]);
|
||||
for (int c = 0; c < cnt; ++c)
|
||||
cnv = ssign(cnv, data[pos[c]]);
|
||||
if (cnv <= 0)
|
||||
return true;
|
||||
}
|
||||
for (int j = 1; j < M; ++j) {
|
||||
int8_t cnv = ssign(ssign(1, parity[j+(q-1)*M-1]), parity[j]);
|
||||
for (int c = 0; c < cnt; ++c)
|
||||
cnv = ssign(cnv, data[pos[CNC*j+c]]);
|
||||
if (cnv <= 0)
|
||||
return true;
|
||||
}
|
||||
}
|
||||
for (int i = 1; i < q; ++i) {
|
||||
int cnt = cnc[i];
|
||||
for (int j = 0; j < M; ++j) {
|
||||
int8_t cnv = ssign(ssign(1, parity[M*(i-1)+j]), parity[M*i+j]);
|
||||
for (int c = 0; c < cnt; ++c)
|
||||
cnv = ssign(cnv, data[pos[CNC*(M*i+j)+c]]);
|
||||
if (cnv <= 0)
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
void finalp(int8_t *links, int cnt)
|
||||
{
|
||||
int8_t mags[cnt], mins[cnt];
|
||||
for (int i = 0; i < cnt; ++i)
|
||||
mags[i] = sqsubu(sqabs(links[i]), BETA);
|
||||
exclusive_reduce(mags, mins, cnt, smin);
|
||||
|
||||
int8_t signs[cnt];
|
||||
exclusive_reduce(links, signs, cnt, seor);
|
||||
for (int i = 0; i < cnt; ++i)
|
||||
signs[i] |= 127;
|
||||
|
||||
for (int i = 0; i < cnt; ++i)
|
||||
links[i] = ssign(mins[i], signs[i]);
|
||||
}
|
||||
void update(int8_t *data, int8_t *parity)
|
||||
{
|
||||
int8_t *bl = bnl;
|
||||
{
|
||||
int cnt = cnc[0];
|
||||
{
|
||||
int deg = cnt + 1;
|
||||
int8_t inp[deg], out[deg];
|
||||
for (int c = 0; c < cnt; ++c)
|
||||
inp[c] = out[c] = sqsub(data[pos[c]], bl[c]);
|
||||
inp[cnt] = out[cnt] = sqsub(parity[0], bl[cnt]);
|
||||
finalp(out, deg);
|
||||
for (int c = 0; c < cnt; ++c)
|
||||
data[pos[c]] = sqadd(inp[c], out[c]);
|
||||
parity[0] = sqadd(inp[cnt], out[cnt]);
|
||||
for (int d = 0; d < deg; ++d)
|
||||
*bl++ = sclamp(out[d], -32, 31);
|
||||
}
|
||||
int deg = cnt + 2;
|
||||
for (int j = 1; j < M; ++j) {
|
||||
int8_t inp[deg], out[deg];
|
||||
for (int c = 0; c < cnt; ++c)
|
||||
inp[c] = out[c] = sqsub(data[pos[CNC*j+c]], bl[c]);
|
||||
inp[cnt] = out[cnt] = sqsub(parity[j+(q-1)*M-1], bl[cnt]);
|
||||
inp[cnt+1] = out[cnt+1] = sqsub(parity[j], bl[cnt+1]);
|
||||
finalp(out, deg);
|
||||
for (int c = 0; c < cnt; ++c)
|
||||
data[pos[CNC*j+c]] = sqadd(inp[c], out[c]);
|
||||
parity[j+(q-1)*M-1] = sqadd(inp[cnt], out[cnt]);
|
||||
parity[j] = sqadd(inp[cnt+1], out[cnt+1]);
|
||||
for (int d = 0; d < deg; ++d)
|
||||
*bl++ = sclamp(out[d], -32, 31);
|
||||
}
|
||||
}
|
||||
for (int i = 1; i < q; ++i) {
|
||||
int cnt = cnc[i];
|
||||
int deg = cnt + 2;
|
||||
for (int j = 0; j < M; ++j) {
|
||||
int8_t inp[deg], out[deg];
|
||||
for (int c = 0; c < cnt; ++c)
|
||||
inp[c] = out[c] = sqsub(data[pos[CNC*(M*i+j)+c]], bl[c]);
|
||||
inp[cnt] = out[cnt] = sqsub(parity[M*(i-1)+j], bl[cnt]);
|
||||
inp[cnt+1] = out[cnt+1] = sqsub(parity[M*i+j], bl[cnt+1]);
|
||||
finalp(out, deg);
|
||||
for (int c = 0; c < cnt; ++c)
|
||||
data[pos[CNC*(M*i+j)+c]] = sqadd(inp[c], out[c]);
|
||||
parity[M*(i-1)+j] = sqadd(inp[cnt], out[cnt]);
|
||||
parity[M*i+j] = sqadd(inp[cnt+1], out[cnt+1]);
|
||||
for (int d = 0; d < deg; ++d)
|
||||
*bl++ = sclamp(out[d], -32, 31);
|
||||
}
|
||||
}
|
||||
}
|
||||
public:
|
||||
LDPCDecoder()
|
||||
{
|
||||
for (int i = 0; i < R; ++i)
|
||||
cnc[i] = 0;
|
||||
int bit_pos = 0;
|
||||
const int *row_ptr = TABLE::POS;
|
||||
for (int g = 0; TABLE::LEN[g]; ++g) {
|
||||
int bit_deg = TABLE::DEG[g];
|
||||
for (int r = 0; r < TABLE::LEN[g]; ++r) {
|
||||
int acc_pos[bit_deg];
|
||||
for (int d = 0; d < bit_deg; ++d)
|
||||
acc_pos[d] = row_ptr[d];
|
||||
row_ptr += bit_deg;
|
||||
for (int j = 0; j < M; ++j) {
|
||||
for (int d = 0; d < bit_deg; ++d) {
|
||||
int n = acc_pos[d];
|
||||
pos[CNC*n+cnc[n]++] = bit_pos;
|
||||
}
|
||||
++bit_pos;
|
||||
for (int d = 0; d < bit_deg; ++d)
|
||||
acc_pos[d] = (acc_pos[d] + q) % R;
|
||||
}
|
||||
}
|
||||
}
|
||||
uint16_t tmp[R * CNC];
|
||||
for (int i = 0; i < q; ++i)
|
||||
for (int j = 0; j < M; ++j)
|
||||
for (int c = 0; c < CNC; ++c)
|
||||
tmp[CNC*(M*i+j)+c] = pos[CNC*(q*j+i)+c];
|
||||
for (int i = 0; i < R * CNC; ++i)
|
||||
pos[i] = tmp[i];
|
||||
}
|
||||
int operator()(int8_t *data, int8_t *parity, int trials = 25)
|
||||
{
|
||||
for (int i = 0; i < LT; ++i)
|
||||
bnl[i] = 0;
|
||||
for (int i = 0; i < q; ++i)
|
||||
for (int j = 0; j < M; ++j)
|
||||
pty[M*i+j] = parity[q*j+i];
|
||||
while (bad(data, pty) && --trials >= 0)
|
||||
update(data, pty);
|
||||
for (int i = 0; i < q; ++i)
|
||||
for (int j = 0; j < M; ++j)
|
||||
parity[q*j+i] = pty[M*i+j];
|
||||
return trials;
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
63
ldpc_encoder.hh
Normal file
63
ldpc_encoder.hh
Normal file
|
|
@ -0,0 +1,63 @@
|
|||
/*
|
||||
LDPC SISO encoder
|
||||
|
||||
Copyright 2018 Ahmet Inan <inan@aicodix.de>
|
||||
*/
|
||||
|
||||
#ifndef LDPC_ENCODER_HH
|
||||
#define LDPC_ENCODER_HH
|
||||
|
||||
namespace CODE {
|
||||
|
||||
template <typename TABLE>
|
||||
class LDPCEncoder
|
||||
{
|
||||
static const int M = TABLE::M;
|
||||
static const int N = TABLE::N;
|
||||
static const int K = TABLE::K;
|
||||
static const int R = N-K;
|
||||
static const int q = R/M;
|
||||
static const int CNC = TABLE::LINKS_MAX_CN - 2;
|
||||
|
||||
uint16_t pos[R * CNC];
|
||||
uint8_t cnc[R];
|
||||
public:
|
||||
LDPCEncoder()
|
||||
{
|
||||
for (int i = 0; i < R; ++i)
|
||||
cnc[i] = 0;
|
||||
int bit_pos = 0;
|
||||
const int *row_ptr = TABLE::POS;
|
||||
for (int g = 0; TABLE::LEN[g]; ++g) {
|
||||
int bit_deg = TABLE::DEG[g];
|
||||
for (int r = 0; r < TABLE::LEN[g]; ++r) {
|
||||
int acc_pos[bit_deg];
|
||||
for (int d = 0; d < bit_deg; ++d)
|
||||
acc_pos[d] = row_ptr[d];
|
||||
row_ptr += bit_deg;
|
||||
for (int j = 0; j < M; ++j) {
|
||||
for (int d = 0; d < bit_deg; ++d) {
|
||||
int n = acc_pos[d];
|
||||
pos[CNC*n+cnc[n]++] = bit_pos;
|
||||
}
|
||||
++bit_pos;
|
||||
for (int d = 0; d < bit_deg; ++d)
|
||||
acc_pos[d] = (acc_pos[d] + q) % R;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
void operator()(int8_t *data, int8_t *parity)
|
||||
{
|
||||
int8_t tmp = 1;
|
||||
for (int i = 0; i < R; ++i) {
|
||||
for (int j = 0; j < cnc[i]; ++j)
|
||||
tmp *= data[pos[CNC*i+j]];
|
||||
parity[i] = tmp;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
244
tests/ldpc_regression_test.cc
Normal file
244
tests/ldpc_regression_test.cc
Normal file
|
|
@ -0,0 +1,244 @@
|
|||
/*
|
||||
Regression Test for the Low-density parity-check Encoder and Decoder
|
||||
|
||||
Table entries below copied from:
|
||||
https://www.etsi.org/deliver/etsi_en/302700_302799/302755/01.04.01_60/en_302755v010401p.pdf
|
||||
|
||||
Copyright 2018 Ahmet Inan <inan@aicodix.de>
|
||||
*/
|
||||
|
||||
#include <iostream>
|
||||
#include <random>
|
||||
#include <cmath>
|
||||
#include <cassert>
|
||||
#include <chrono>
|
||||
#include <algorithm>
|
||||
#include <functional>
|
||||
#include "ldpc_encoder.hh"
|
||||
#include "ldpc_decoder.hh"
|
||||
|
||||
struct DVB_T2_TABLE_A1
|
||||
{
|
||||
static const int M = 360;
|
||||
static const int N = 64800;
|
||||
static const int K = 32400;
|
||||
static const int LINKS_MIN_CN = 6;
|
||||
static const int LINKS_MAX_CN = 7;
|
||||
static const int LINKS_TOTAL = 226799;
|
||||
static const int DEG_MAX = 8;
|
||||
static constexpr int DEG[] = {
|
||||
8, 3, 0
|
||||
};
|
||||
static constexpr int LEN[] = {
|
||||
36, 54, 0
|
||||
};
|
||||
static constexpr int POS[] = {
|
||||
54, 9318, 14392, 27561, 26909, 10219, 2534, 8597,
|
||||
55, 7263, 4635, 2530, 28130, 3033, 23830, 3651,
|
||||
56, 24731, 23583, 26036, 17299, 5750, 792, 9169,
|
||||
57, 5811, 26154, 18653, 11551, 15447, 13685, 16264,
|
||||
58, 12610, 11347, 28768, 2792, 3174, 29371, 12997,
|
||||
59, 16789, 16018, 21449, 6165, 21202, 15850, 3186,
|
||||
60, 31016, 21449, 17618, 6213, 12166, 8334, 18212,
|
||||
61, 22836, 14213, 11327, 5896, 718, 11727, 9308,
|
||||
62, 2091, 24941, 29966, 23634, 9013, 15587, 5444,
|
||||
63, 22207, 3983, 16904, 28534, 21415, 27524, 25912,
|
||||
64, 25687, 4501, 22193, 14665, 14798, 16158, 5491,
|
||||
65, 4520, 17094, 23397, 4264, 22370, 16941, 21526,
|
||||
66, 10490, 6182, 32370, 9597, 30841, 25954, 2762,
|
||||
67, 22120, 22865, 29870, 15147, 13668, 14955, 19235,
|
||||
68, 6689, 18408, 18346, 9918, 25746, 5443, 20645,
|
||||
69, 29982, 12529, 13858, 4746, 30370, 10023, 24828,
|
||||
70, 1262, 28032, 29888, 13063, 24033, 21951, 7863,
|
||||
71, 6594, 29642, 31451, 14831, 9509, 9335, 31552,
|
||||
72, 1358, 6454, 16633, 20354, 24598, 624, 5265,
|
||||
73, 19529, 295, 18011, 3080, 13364, 8032, 15323,
|
||||
74, 11981, 1510, 7960, 21462, 9129, 11370, 25741,
|
||||
75, 9276, 29656, 4543, 30699, 20646, 21921, 28050,
|
||||
76, 15975, 25634, 5520, 31119, 13715, 21949, 19605,
|
||||
77, 18688, 4608, 31755, 30165, 13103, 10706, 29224,
|
||||
78, 21514, 23117, 12245, 26035, 31656, 25631, 30699,
|
||||
79, 9674, 24966, 31285, 29908, 17042, 24588, 31857,
|
||||
80, 21856, 27777, 29919, 27000, 14897, 11409, 7122,
|
||||
81, 29773, 23310, 263, 4877, 28622, 20545, 22092,
|
||||
82, 15605, 5651, 21864, 3967, 14419, 22757, 15896,
|
||||
83, 30145, 1759, 10139, 29223, 26086, 10556, 5098,
|
||||
84, 18815, 16575, 2936, 24457, 26738, 6030, 505,
|
||||
85, 30326, 22298, 27562, 20131, 26390, 6247, 24791,
|
||||
86, 928, 29246, 21246, 12400, 15311, 32309, 18608,
|
||||
87, 20314, 6025, 26689, 16302, 2296, 3244, 19613,
|
||||
88, 6237, 11943, 22851, 15642, 23857, 15112, 20947,
|
||||
89, 26403, 25168, 19038, 18384, 8882, 12719, 7093,
|
||||
0, 14567, 24965,
|
||||
1, 3908, 100,
|
||||
2, 10279, 240,
|
||||
3, 24102, 764,
|
||||
4, 12383, 4173,
|
||||
5, 13861, 15918,
|
||||
6, 21327, 1046,
|
||||
7, 5288, 14579,
|
||||
8, 28158, 8069,
|
||||
9, 16583, 11098,
|
||||
10, 16681, 28363,
|
||||
11, 13980, 24725,
|
||||
12, 32169, 17989,
|
||||
13, 10907, 2767,
|
||||
14, 21557, 3818,
|
||||
15, 26676, 12422,
|
||||
16, 7676, 8754,
|
||||
17, 14905, 20232,
|
||||
18, 15719, 24646,
|
||||
19, 31942, 8589,
|
||||
20, 19978, 27197,
|
||||
21, 27060, 15071,
|
||||
22, 6071, 26649,
|
||||
23, 10393, 11176,
|
||||
24, 9597, 13370,
|
||||
25, 7081, 17677,
|
||||
26, 1433, 19513,
|
||||
27, 26925, 9014,
|
||||
28, 19202, 8900,
|
||||
29, 18152, 30647,
|
||||
30, 20803, 1737,
|
||||
31, 11804, 25221,
|
||||
32, 31683, 17783,
|
||||
33, 29694, 9345,
|
||||
34, 12280, 26611,
|
||||
35, 6526, 26122,
|
||||
36, 26165, 11241,
|
||||
37, 7666, 26962,
|
||||
38, 16290, 8480,
|
||||
39, 11774, 10120,
|
||||
40, 30051, 30426,
|
||||
41, 1335, 15424,
|
||||
42, 6865, 17742,
|
||||
43, 31779, 12489,
|
||||
44, 32120, 21001,
|
||||
45, 14508, 6996,
|
||||
46, 979, 25024,
|
||||
47, 4554, 21896,
|
||||
48, 7989, 21777,
|
||||
49, 4972, 20661,
|
||||
50, 6612, 2730,
|
||||
51, 12742, 4418,
|
||||
52, 29194, 595,
|
||||
53, 19267, 20113,
|
||||
};
|
||||
};
|
||||
|
||||
constexpr int DVB_T2_TABLE_A1::DEG[];
|
||||
constexpr int DVB_T2_TABLE_A1::LEN[];
|
||||
constexpr int DVB_T2_TABLE_A1::POS[];
|
||||
typedef DVB_T2_TABLE_A1 TABLE;
|
||||
|
||||
int main()
|
||||
{
|
||||
const int TRIALS = 25;
|
||||
const int FACTOR = 2;
|
||||
const int BETA = 1;
|
||||
|
||||
const int CODE_LEN = TABLE::N;
|
||||
const int DATA_LEN = TABLE::K;
|
||||
|
||||
CODE::LDPCEncoder<TABLE> encode;
|
||||
CODE::LDPCDecoder<TABLE, BETA> decode;
|
||||
|
||||
std::random_device rd;
|
||||
std::default_random_engine generator(rd());
|
||||
typedef std::uniform_int_distribution<int> uniform;
|
||||
typedef std::normal_distribution<float> normal;
|
||||
|
||||
int8_t *code = new int8_t[CODE_LEN];
|
||||
int8_t *orig = new int8_t[CODE_LEN];
|
||||
int8_t *noisy = new int8_t[CODE_LEN];
|
||||
float *symb = new float[CODE_LEN];
|
||||
|
||||
float min_SNR = 20, min_mbs = 1000, max_mbs = 0;
|
||||
|
||||
for (float SNR = -5; SNR <= 15; SNR += 0.1) {
|
||||
float mean = 1;
|
||||
float sigma = std::sqrt(mean * mean / (2 * std::pow(10, SNR / 10)));
|
||||
|
||||
auto data = std::bind(uniform(0, 1), generator);
|
||||
auto awgn = std::bind(normal(0.0, sigma), generator);
|
||||
|
||||
for (int i = 0; i < DATA_LEN; ++i)
|
||||
code[i] = 1 - 2 * data();
|
||||
|
||||
encode(code, code + DATA_LEN);
|
||||
|
||||
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 * FACTOR / (sigma * sigma);
|
||||
for (int i = 0; i < CODE_LEN; ++i)
|
||||
code[i] = std::min<float>(std::max<float>(std::nearbyint(fact * symb[i]), -128), 127);
|
||||
|
||||
for (int i = 0; i < CODE_LEN; ++i)
|
||||
noisy[i] = code[i];
|
||||
|
||||
auto start = std::chrono::system_clock::now();
|
||||
int count = decode(code, code + DATA_LEN, TRIALS);
|
||||
auto end = std::chrono::system_clock::now();
|
||||
auto usec = std::chrono::duration_cast<std::chrono::microseconds>(end - start);
|
||||
float mbs = (float)DATA_LEN / usec.count();
|
||||
int iters = count < 0 ? TRIALS : TRIALS - count;
|
||||
|
||||
int awgn_errors = 0;
|
||||
for (int i = 0; i < CODE_LEN; ++i)
|
||||
awgn_errors += noisy[i] * orig[i] < 0;
|
||||
int quantization_erasures = 0;
|
||||
for (int i = 0; i < CODE_LEN; ++i)
|
||||
quantization_erasures += !noisy[i];
|
||||
int uncorrected_errors = 0;
|
||||
for (int i = 0; i < CODE_LEN; ++i)
|
||||
uncorrected_errors += code[i] * orig[i] <= 0;
|
||||
int decoder_errors = 0;
|
||||
for (int i = 0; i < CODE_LEN; ++i)
|
||||
decoder_errors += code[i] * orig[i] <= 0 && orig[i] * noisy[i] > 0;
|
||||
float bit_error_rate = (float)uncorrected_errors / (float)(CODE_LEN);
|
||||
|
||||
if (!uncorrected_errors)
|
||||
min_SNR = std::min(min_SNR, SNR);
|
||||
min_mbs = std::min(min_mbs, mbs);
|
||||
max_mbs = std::max(max_mbs, mbs);
|
||||
|
||||
if (0) {
|
||||
std::cerr << SNR << " Es/N0 => standard deviation of " << sigma << " with mean " << mean << std::endl;
|
||||
std::cerr << awgn_errors << " errors caused by AWGN." << std::endl;
|
||||
std::cerr << quantization_erasures << " erasures caused by quantization." << std::endl;
|
||||
std::cerr << decoder_errors << " errors caused by decoder." << std::endl;
|
||||
std::cerr << uncorrected_errors << " errors uncorrected." << std::endl;
|
||||
std::cerr << bit_error_rate << " bit error rate." << std::endl;
|
||||
if (count < 0) {
|
||||
std::cerr << "decoder failed at converging to a code word!" << std::endl;
|
||||
} else {
|
||||
std::cerr << iters << " iterations were needed." << std::endl;
|
||||
}
|
||||
std::cerr << usec.count() << " microseconds to decode." << std::endl;
|
||||
std::cerr << mbs << " megabit per second." << std::endl;
|
||||
} else {
|
||||
std::cout << SNR << " " << bit_error_rate << " " << iters << " " << mbs << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
delete[] code;
|
||||
delete[] orig;
|
||||
delete[] noisy;
|
||||
delete[] symb;
|
||||
|
||||
std::cerr << "QEF at: " << min_SNR << " SNR, speed min: " << min_mbs << " Mb/s and speed max: " << max_mbs << " Mb/s." << std::endl;
|
||||
assert(min_SNR < -1.8);
|
||||
std::cerr << "Low-density parity-check code regression test passed!" << std::endl;
|
||||
return 0;
|
||||
}
|
||||
|
||||
Loading…
Add table
Add a link
Reference in a new issue