diff --git a/README.md b/README.md index e0aa7be..5c27865 100644 --- a/README.md +++ b/README.md @@ -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: diff --git a/decode.cc b/decode.cc index cb7626a..9577844 100644 --- a/decode.cc +++ b/decode.cc @@ -4,6 +4,7 @@ OFDM modem decoder Copyright 2021 Ahmet Inan */ +#include #include #include #include @@ -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 struct Decoder { typedef DSP::Const 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 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; diff --git a/encode.cc b/encode.cc index c564469..410a661 100644 --- a/encode.cc +++ b/encode.cc @@ -17,17 +17,19 @@ Copyright 2021 Ahmet Inan #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 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 crc1; CODE::BoseChaudhuriHocquenghemEncoder<255, 71> bchenc0; CODE::BoseChaudhuriHocquenghemEncoder<65535, 65343> bchenc1; + CODE::LDPCEncoder 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(); diff --git a/ldpc_tables.hh b/ldpc_tables.hh new file mode 100644 index 0000000..2ed7810 --- /dev/null +++ b/ldpc_tables.hh @@ -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 +*/ + +#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, + }; +}; +