mirror of
https://github.com/aicodix/modem.git
synced 2026-04-27 14:30:34 +00:00
added LDPC forward error correction
This commit is contained in:
parent
1e0b2199af
commit
7ba95fb000
4 changed files with 182 additions and 25 deletions
|
|
@ -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:
|
||||
|
|
|
|||
28
decode.cc
28
decode.cc
|
|
@ -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;
|
||||
|
|
|
|||
25
encode.cc
25
encode.cc
|
|
@ -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
150
ldpc_tables.hh
Normal 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,
|
||||
};
|
||||
};
|
||||
|
||||
Loading…
Add table
Add a link
Reference in a new issue