added LDPC forward error correction

This commit is contained in:
Ahmet Inan 2021-06-10 14:51:25 +02:00
commit 7ba95fb000
4 changed files with 182 additions and 25 deletions

View file

@ -3,10 +3,10 @@
Quick start:
Create file ```uncoded.dat``` with ```64576``` bits of random data:
Create file ```uncoded.dat``` with ```42976``` bits of random data:
```
dd if=/dev/urandom of=uncoded.dat bs=1 count=8072
dd if=/dev/urandom of=uncoded.dat bs=1 count=5372
```
Encode file ```uncoded.dat``` to ```encoded.wav``` [WAV](https://en.wikipedia.org/wiki/WAV) audio file with 8000 Hz sample rate, 16 bits and only 1 (real) channel:

View file

@ -4,6 +4,7 @@ OFDM modem decoder
Copyright 2021 Ahmet Inan <inan@aicodix.de>
*/
#include <algorithm>
#include <iostream>
#include <cassert>
#include <cmath>
@ -25,6 +26,8 @@ namespace DSP { using std::abs; using std::min; using std::cos; using std::sin;
#include "crc.hh"
#include "osd.hh"
#include "psk.hh"
#include "ldpc_tables.hh"
#include "ldpc_decoder.hh"
#include "galois_field.hh"
#include "bose_chaudhuri_hocquenghem_decoder.hh"
@ -152,12 +155,12 @@ template <typename value, typename cmplx, int rate>
struct Decoder
{
typedef DSP::Const<value> Const;
typedef PhaseShiftKeying<8, cmplx, value> Mod;
typedef PhaseShiftKeying<8, cmplx, int8_t> Mod;
static const int symbol_len = (1280 * rate) / 8000;
static const int filter_len = (((21 * rate) / 8000) & ~3) | 1;
static const int guard_len = symbol_len / 8;
static const int code_bits = 64800;
static const int data_bits = code_bits - 32 - 12 * 16;
static const int data_bits = code_bits - 32 - 12 * 16 - 21600;
static const int code_cols = 432;
static const int code_rows = code_bits / code_cols / Mod::BITS;
static const int code_off = -216;
@ -183,7 +186,9 @@ struct Decoder
GF gf;
CODE::BoseChaudhuriHocquenghemDecoder<24, 1, 65343, GF> bchdec1;
CODE::OrderedStatisticsDecoder<255, 71, 4> osddec;
CODE::LDPCDecoder<DVB_T2_TABLE_A3, 1> ldpcdec;
int8_t genmat[255*71];
int8_t code[code_bits];
cmplx head[symbol_len], tail[symbol_len];
cmplx fdom[symbol_len], tdom[buffer_len], resam[buffer_len];
value phase[symbol_len/2];
@ -331,21 +336,22 @@ struct Decoder
for (int i = 0; i < buffer_len; ++i)
tdom[i] = resam[i] * osc();
value precision = 16;
cmplx *cur = tdom + symbol_pos - (code_rows + 1) * (symbol_len + guard_len);
fwd(fdom, cur);
for (int j = 0; j < code_rows; ++j) {
for (int i = 0; i < code_cols; ++i)
head[bin(i+code_off)] = fdom[bin(i+code_off)];
fwd(fdom, cur += symbol_len+guard_len);
for (int i = 0; i < code_cols; ++i) {
value tmp[Mod::BITS];
Mod::hard(tmp, fdom[bin(i+code_off)] / head[bin(i+code_off)]);
for (int k = 0; k < Mod::BITS; ++k) {
int l = Mod::BITS * (code_cols * j + i) + k;
CODE::set_le_bit(out, l, tmp[k] < 0);
}
}
for (int i = 0; i < code_cols; ++i)
Mod::soft(code+Mod::BITS*(code_cols*j+i), fdom[bin(i+code_off)]/head[bin(i+code_off)], precision);
}
int count = ldpcdec(code, code+data_bits+32+12*16);
if (count < 0)
std::cerr << "payload LDPC decoding did not converge." << std::endl;
for (int i = 0; i < data_bits+32+12*16; ++i)
CODE::set_le_bit(out, i, code[i] < 0);
int ret = bchdec1(out, out+(data_bits+32)/8, 0, 0, data_bits+32);
if (ret < 0) {
std::cerr << "payload BCH error." << std::endl;
@ -411,7 +417,7 @@ int main(int argc, char **argv)
std::cerr << "Couldn't open file \"" << output_name << "\" for writing." << std::endl;
return 1;
}
const int data_len = code_len - (32 + 12 * 16) / 8;
const int data_len = code_len - (32 + 12 * 16 + 21600) / 8;
for (int i = 0; i < data_len; ++i)
output_file.put(output_data[i]);
delete []output_data;

View file

@ -17,17 +17,19 @@ Copyright 2021 Ahmet Inan <inan@aicodix.de>
#include "mls.hh"
#include "crc.hh"
#include "psk.hh"
#include "ldpc_tables.hh"
#include "ldpc_encoder.hh"
#include "galois_field.hh"
#include "bose_chaudhuri_hocquenghem_encoder.hh"
template <typename value, typename cmplx, int rate>
struct Encoder
{
typedef PhaseShiftKeying<8, cmplx, value> Mod;
typedef PhaseShiftKeying<8, cmplx, int8_t> Mod;
static const int symbol_len = (1280 * rate) / 8000;
static const int guard_len = symbol_len / 8;
static const int code_bits = 64800;
static const int data_bits = code_bits - 32 - 12 * 16;
static const int data_bits = code_bits - 32 - 12 * 16 - 21600;
static const int code_cols = 432;
static const int code_rows = code_bits / code_cols / Mod::BITS;
static const int mls0_len = 127;
@ -41,6 +43,8 @@ struct Encoder
CODE::CRC<uint32_t> crc1;
CODE::BoseChaudhuriHocquenghemEncoder<255, 71> bchenc0;
CODE::BoseChaudhuriHocquenghemEncoder<65535, 65343> bchenc1;
CODE::LDPCEncoder<DVB_T2_TABLE_A3> ldpcenc;
int8_t code[code_bits];
cmplx fdom[symbol_len];
cmplx tdom[symbol_len];
cmplx guard[guard_len];
@ -87,7 +91,7 @@ struct Encoder
for (int i = 0; i < symbol_len; ++i)
fdom[i] = 0;
for (int i = code_off; i < code_off + code_cols; ++i) {
value tmp[Mod::BITS];
int8_t tmp[Mod::BITS];
for (int k = 0; k < Mod::BITS; ++k)
tmp[k] = 1 - 2 * seq2();
fdom[bin(i)] = code_fac * Mod::map(tmp);
@ -159,15 +163,12 @@ struct Encoder
for (int i = 0; i < 4; ++i)
inp[data_bits/8+i] = (crc1() >> (8*i)) & 255;
bchenc1(inp, inp+(data_bits+32)/8, data_bits+32);
for (int i = 0; i < data_bits+32+12*16; ++i)
code[i] = 1 - 2 * CODE::get_le_bit(inp, i);
ldpcenc(code, code+data_bits+32+12*16);
for (int j = 0; j < code_rows; ++j) {
for (int i = 0; i < code_cols; ++i) {
value tmp[Mod::BITS];
for (int k = 0; k < Mod::BITS; ++k) {
int l = Mod::BITS * (code_cols * j + i) + k;
tmp[k] = 1 - 2 * CODE::get_le_bit(inp, l);
}
fdom[bin(i+code_off)] *= Mod::map(tmp);
}
for (int i = 0; i < code_cols; ++i)
fdom[bin(i+code_off)] *= Mod::map(code+Mod::BITS*(code_cols*j+i));
symbol();
}
schmidl_cox();
@ -239,7 +240,7 @@ int main(int argc, char **argv)
return 1;
}
const int code_len = 64800 / 8;
const int data_len = code_len - (32 + 12 * 16) / 8;
const int data_len = code_len - (32 + 12 * 16 + 21600) / 8;
uint8_t *input_data = new uint8_t[code_len];
for (int i = 0; i < data_len; ++i)
input_data[i] = input_file.get();

150
ldpc_tables.hh Normal file
View file

@ -0,0 +1,150 @@
/*
LDPC tables
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>
*/
#pragma once
struct DVB_T2_TABLE_A3
{
static const int M = 360;
static const int N = 64800;
static const int K = 43200;
static const int LINKS_MIN_CN = 9;
static const int LINKS_MAX_CN = 10;
static const int LINKS_TOTAL = 215999;
static const int DEG_MAX = 13;
static constexpr int DEG[] = {
13, 3, 0
};
static constexpr int LEN[] = {
12, 108, 0
};
static constexpr int POS[] = {
317, 2255, 2324, 2723, 3538, 3576, 6194, 6700, 9101, 10057, 12739, 17407, 21039,
1958, 2007, 3294, 4394, 12762, 14505, 14593, 14692, 16522, 17737, 19245, 21272, 21379,
127, 860, 5001, 5633, 8644, 9282, 12690, 14644, 17553, 19511, 19681, 20954, 21002,
2514, 2822, 5781, 6297, 8063, 9469, 9551, 11407, 11837, 12985, 15710, 20236, 20393,
1565, 3106, 4659, 4926, 6495, 6872, 7343, 8720, 15785, 16434, 16727, 19884, 21325,
706, 3220, 8568, 10896, 12486, 13663, 16398, 16599, 19475, 19781, 20625, 20961, 21335,
4257, 10449, 12406, 14561, 16049, 16522, 17214, 18029, 18033, 18802, 19062, 19526, 20748,
412, 433, 558, 2614, 2978, 4157, 6584, 9320, 11683, 11819, 13024, 14486, 16860,
777, 5906, 7403, 8550, 8717, 8770, 11436, 12846, 13629, 14755, 15688, 16392, 16419,
4093, 5045, 6037, 7248, 8633, 9771, 10260, 10809, 11326, 12072, 17516, 19344, 19938,
2120, 2648, 3155, 3852, 6888, 12258, 14821, 15359, 16378, 16437, 17791, 20614, 21025,
1085, 2434, 5816, 7151, 8050, 9422, 10884, 12728, 15353, 17733, 18140, 18729, 20920,
856, 1690, 12787,
6532, 7357, 9151,
4210, 16615, 18152,
11494, 14036, 17470,
2474, 10291, 10323,
1778, 6973, 10739,
4347, 9570, 18748,
2189, 11942, 20666,
3868, 7526, 17706,
8780, 14796, 18268,
160, 16232, 17399,
1285, 2003, 18922,
4658, 17331, 20361,
2765, 4862, 5875,
4565, 5521, 8759,
3484, 7305, 15829,
5024, 17730, 17879,
7031, 12346, 15024,
179, 6365, 11352,
2490, 3143, 5098,
2643, 3101, 21259,
4315, 4724, 13130,
594, 17365, 18322,
5983, 8597, 9627,
10837, 15102, 20876,
10448, 20418, 21478,
3848, 12029, 15228,
708, 5652, 13146,
5998, 7534, 16117,
2098, 13201, 18317,
9186, 14548, 17776,
5246, 10398, 18597,
3083, 4944, 21021,
13726, 18495, 19921,
6736, 10811, 17545,
10084, 12411, 14432,
1064, 13555, 17033,
679, 9878, 13547,
3422, 9910, 20194,
3640, 3701, 10046,
5862, 10134, 11498,
5923, 9580, 15060,
1073, 3012, 16427,
5527, 20113, 20883,
7058, 12924, 15151,
9764, 12230, 17375,
772, 7711, 12723,
555, 13816, 15376,
10574, 11268, 17932,
15442, 17266, 20482,
390, 3371, 8781,
10512, 12216, 17180,
4309, 14068, 15783,
3971, 11673, 20009,
9259, 14270, 17199,
2947, 5852, 20101,
3965, 9722, 15363,
1429, 5689, 16771,
6101, 6849, 12781,
3676, 9347, 18761,
350, 11659, 18342,
5961, 14803, 16123,
2113, 9163, 13443,
2155, 9808, 12885,
2861, 7988, 11031,
7309, 9220, 20745,
6834, 8742, 11977,
2133, 12908, 14704,
10170, 13809, 18153,
13464, 14787, 14975,
799, 1107, 3789,
3571, 8176, 10165,
5433, 13446, 15481,
3351, 6767, 12840,
8950, 8974, 11650,
1430, 4250, 21332,
6283, 10628, 15050,
8632, 14404, 16916,
6509, 10702, 16278,
15900, 16395, 17995,
8031, 18420, 19733,
3747, 4634, 17087,
4453, 6297, 16262,
2792, 3513, 17031,
14846, 20893, 21563,
17220, 20436, 21337,
275, 4107, 10497,
3536, 7520, 10027,
14089, 14943, 19455,
1965, 3931, 21104,
2439, 11565, 17932,
154, 15279, 21414,
10017, 11269, 16546,
7169, 10161, 16928,
10284, 16791, 20655,
36, 3175, 8475,
2605, 16269, 19290,
8947, 9178, 15420,
5687, 9156, 12408,
8096, 9738, 14711,
4935, 8093, 19266,
2667, 10062, 15972,
6389, 11318, 14417,
8800, 18137, 18434,
5824, 5927, 15314,
6056, 13168, 15179,
3284, 13138, 18919,
13115, 17259, 17332,
};
};