diff options
| author | drowe67 <[email protected]> | 2023-07-14 12:36:50 +0930 |
|---|---|---|
| committer | David Rowe <[email protected]> | 2023-07-14 12:36:50 +0930 |
| commit | b86e88413d4c6ec428aaedb147f7675f28882fe4 (patch) | |
| tree | ce360925856e25d4343d59a37e2e6bac142d3752 /src/interldpc.c | |
| parent | 0c2e969cfbe85548801eeb20ad8113969604892a (diff) | |
clang-format -i applied to src unittest misc
Diffstat (limited to 'src/interldpc.c')
| -rw-r--r-- | src/interldpc.c | 467 |
1 files changed, 244 insertions, 223 deletions
diff --git a/src/interldpc.c b/src/interldpc.c index b17e9b7..e498807 100644 --- a/src/interldpc.c +++ b/src/interldpc.c @@ -25,293 +25,314 @@ along with this program; if not, see <http://www.gnu.org/licenses/>. */ +#include "interldpc.h" + #include <assert.h> +#include <math.h> +#include <stdint.h> #include <stdio.h> #include <stdlib.h> -#include <stdint.h> #include <string.h> -#include <math.h> -#include "interldpc.h" -#include "ofdm_internal.h" -#include "mpdecode_core.h" #include "gp_interleaver.h" +#include "mpdecode_core.h" +#include "ofdm_internal.h" void freedv_pack(unsigned char *bytes, unsigned char *bits, int nbits); void freedv_unpack(unsigned char *bits, unsigned char *bytes, int nbits); unsigned short freedv_crc16_unpacked(unsigned char *bits, int nbits); -void set_up_ldpc_constants(struct LDPC *ldpc, int code_length, int parity_bits) { - /* following provided for convenience and to match Octave variable names */ +void set_up_ldpc_constants(struct LDPC *ldpc, int code_length, + int parity_bits) { + /* following provided for convenience and to match Octave variable names */ - /* these remain fixed */ - ldpc->ldpc_data_bits_per_frame = code_length - parity_bits; - ldpc->ldpc_coded_bits_per_frame = code_length; + /* these remain fixed */ + ldpc->ldpc_data_bits_per_frame = code_length - parity_bits; + ldpc->ldpc_coded_bits_per_frame = code_length; - /* in the case there are some unused data bits, these may be - modified to be less that ldpc->ldpc_xxx versions above. We - place known bits in the unused data bit positions, which make - the code stronger, and allow us to mess with different speech - codec bit allocations without designing new LDPC codes. */ + /* in the case there are some unused data bits, these may be + modified to be less that ldpc->ldpc_xxx versions above. We + place known bits in the unused data bit positions, which make + the code stronger, and allow us to mess with different speech + codec bit allocations without designing new LDPC codes. */ - ldpc->data_bits_per_frame = ldpc->ldpc_data_bits_per_frame; - ldpc->coded_bits_per_frame = ldpc->ldpc_coded_bits_per_frame; - ldpc->protection_mode = LDPC_PROT_2020; + ldpc->data_bits_per_frame = ldpc->ldpc_data_bits_per_frame; + ldpc->coded_bits_per_frame = ldpc->ldpc_coded_bits_per_frame; + ldpc->protection_mode = LDPC_PROT_2020; } void set_data_bits_per_frame(struct LDPC *ldpc, int new_data_bits_per_frame) { - ldpc->data_bits_per_frame = new_data_bits_per_frame; - ldpc->coded_bits_per_frame = ldpc->data_bits_per_frame + ldpc->NumberParityBits; + ldpc->data_bits_per_frame = new_data_bits_per_frame; + ldpc->coded_bits_per_frame = + ldpc->data_bits_per_frame + ldpc->NumberParityBits; } -/* 1' stuffing (code rate reduction) - tweak LDPC code setup for selected modes */ +/* 1' stuffing (code rate reduction) - tweak LDPC code setup for selected modes + */ void ldpc_mode_specific_setup(struct OFDM *ofdm, struct LDPC *ldpc) { - /* mode specific set up */ - if (!strcmp(ofdm->mode,"2020")) set_data_bits_per_frame(ldpc, 312); - if (!strcmp(ofdm->mode,"2020B")) { - set_data_bits_per_frame(ldpc, 156); - ldpc->protection_mode = LDPC_PROT_2020B; - } - if (!strcmp(ofdm->mode,"2020C")) set_data_bits_per_frame(ldpc, 156); - if (!strcmp(ofdm->mode,"datac4")) set_data_bits_per_frame(ldpc, 448); - if (!strcmp(ofdm->mode,"datac13")) set_data_bits_per_frame(ldpc, 128); + /* mode specific set up */ + if (!strcmp(ofdm->mode, "2020")) set_data_bits_per_frame(ldpc, 312); + if (!strcmp(ofdm->mode, "2020B")) { + set_data_bits_per_frame(ldpc, 156); + ldpc->protection_mode = LDPC_PROT_2020B; + } + if (!strcmp(ofdm->mode, "2020C")) set_data_bits_per_frame(ldpc, 156); + if (!strcmp(ofdm->mode, "datac4")) set_data_bits_per_frame(ldpc, 448); + if (!strcmp(ofdm->mode, "datac13")) set_data_bits_per_frame(ldpc, 128); } -/* LDPC encode frame - generate parity bits and a codeword, applying the selected - FEC protection scheme */ -void ldpc_encode_frame(struct LDPC *ldpc, int codeword[], unsigned char tx_bits_char[]) { - unsigned char pbits[ldpc->NumberParityBits]; - int codec_frame; - int i, j; +/* LDPC encode frame - generate parity bits and a codeword, applying the + selected FEC protection scheme */ +void ldpc_encode_frame(struct LDPC *ldpc, int codeword[], + unsigned char tx_bits_char[]) { + unsigned char pbits[ldpc->NumberParityBits]; + int codec_frame; + int i, j; - unsigned char tx_bits_char_padded[ldpc->ldpc_data_bits_per_frame]; + unsigned char tx_bits_char_padded[ldpc->ldpc_data_bits_per_frame]; - switch (ldpc->protection_mode) { + switch (ldpc->protection_mode) { case LDPC_PROT_EQUAL: - assert(ldpc->data_bits_per_frame == ldpc->ldpc_data_bits_per_frame); - /* we have enough data bits to fill the codeword */ - encode(ldpc, tx_bits_char, pbits); - break; - + assert(ldpc->data_bits_per_frame == ldpc->ldpc_data_bits_per_frame); + /* we have enough data bits to fill the codeword */ + encode(ldpc, tx_bits_char, pbits); + break; + case LDPC_PROT_2020: - /* not all data bits in codeword used, so set them to known values */ - memcpy(tx_bits_char_padded, tx_bits_char, ldpc->data_bits_per_frame); - for (i = ldpc->data_bits_per_frame; i < ldpc->ldpc_data_bits_per_frame; i++) - tx_bits_char_padded[i] = 1; - encode(ldpc, tx_bits_char_padded, pbits); - break; - + /* not all data bits in codeword used, so set them to known values */ + memcpy(tx_bits_char_padded, tx_bits_char, ldpc->data_bits_per_frame); + for (i = ldpc->data_bits_per_frame; i < ldpc->ldpc_data_bits_per_frame; + i++) + tx_bits_char_padded[i] = 1; + encode(ldpc, tx_bits_char_padded, pbits); + break; + case LDPC_PROT_2020B: - /* We only want to protect the stage 1 VQ data bits, 0..10 in - each 52 bit codec frame. There are 3 codec frames 3x52=156 - bits, and 56 parity bits. We only use 11*3 = 33 bits of - the LDPC codeword data bits, the rest are set to known - values. - */ - for(j=0,codec_frame=0; codec_frame<3; codec_frame++) - for(i=0; i<11; i++,j++) - tx_bits_char_padded[j] = tx_bits_char[codec_frame*52+i]; - assert(j == 33); - for (i = 33; i < ldpc->ldpc_data_bits_per_frame; i++) - tx_bits_char_padded[i] = 1; - encode(ldpc, tx_bits_char_padded, pbits); - - break; + /* We only want to protect the stage 1 VQ data bits, 0..10 in + each 52 bit codec frame. There are 3 codec frames 3x52=156 + bits, and 56 parity bits. We only use 11*3 = 33 bits of + the LDPC codeword data bits, the rest are set to known + values. + */ + for (j = 0, codec_frame = 0; codec_frame < 3; codec_frame++) + for (i = 0; i < 11; i++, j++) + tx_bits_char_padded[j] = tx_bits_char[codec_frame * 52 + i]; + assert(j == 33); + for (i = 33; i < ldpc->ldpc_data_bits_per_frame; i++) + tx_bits_char_padded[i] = 1; + encode(ldpc, tx_bits_char_padded, pbits); + + break; default: - assert(0); - } + assert(0); + } - /* output codeword is concatenation of (used) data bits and parity - bits, we don't bother sending unused (known) data bits */ - for (i = 0; i < ldpc->data_bits_per_frame; i++) codeword[i] = tx_bits_char[i]; - for (j = 0; j < ldpc->NumberParityBits; i++, j++) codeword[i] = pbits[j]; + /* output codeword is concatenation of (used) data bits and parity + bits, we don't bother sending unused (known) data bits */ + for (i = 0; i < ldpc->data_bits_per_frame; i++) codeword[i] = tx_bits_char[i]; + for (j = 0; j < ldpc->NumberParityBits; i++, j++) codeword[i] = pbits[j]; } void qpsk_modulate_frame(COMP tx_symbols[], int codeword[], int n) { - int s, i; - int dibit[2]; - complex float qpsk_symb; - - for (s = 0, i = 0; i < n; s += 2, i++) { - dibit[0] = codeword[s + 1] & 0x1; - dibit[1] = codeword[s] & 0x1; - qpsk_symb = qpsk_mod(dibit); - tx_symbols[i].real = crealf(qpsk_symb); - tx_symbols[i].imag = cimagf(qpsk_symb); - } + int s, i; + int dibit[2]; + complex float qpsk_symb; + + for (s = 0, i = 0; i < n; s += 2, i++) { + dibit[0] = codeword[s + 1] & 0x1; + dibit[1] = codeword[s] & 0x1; + qpsk_symb = qpsk_mod(dibit); + tx_symbols[i].real = crealf(qpsk_symb); + tx_symbols[i].imag = cimagf(qpsk_symb); + } } /* run LDPC decoder, taking into account the FEC protection scheme */ -void ldpc_decode_frame(struct LDPC *ldpc, int *parityCheckCount, int *iter, uint8_t out_char[], float llr[]) { - float llr_full_codeword[ldpc->ldpc_coded_bits_per_frame]; - int unused_data_bits = ldpc->ldpc_data_bits_per_frame - ldpc->data_bits_per_frame; - uint8_t out_char_ldpc[ldpc->coded_bits_per_frame]; - int i,j; - int codec_frame; - - switch (ldpc->protection_mode) { +void ldpc_decode_frame(struct LDPC *ldpc, int *parityCheckCount, int *iter, + uint8_t out_char[], float llr[]) { + float llr_full_codeword[ldpc->ldpc_coded_bits_per_frame]; + int unused_data_bits = + ldpc->ldpc_data_bits_per_frame - ldpc->data_bits_per_frame; + uint8_t out_char_ldpc[ldpc->coded_bits_per_frame]; + int i, j; + int codec_frame; + + switch (ldpc->protection_mode) { case LDPC_PROT_EQUAL: - /* Equal protection all data bits in codeword - (e.g. 700D/700E), works well with rate 0.5 codes */ - assert(ldpc->data_bits_per_frame == ldpc->ldpc_data_bits_per_frame); - *iter = run_ldpc_decoder(ldpc, out_char, llr, parityCheckCount); - break; + /* Equal protection all data bits in codeword + (e.g. 700D/700E), works well with rate 0.5 codes */ + assert(ldpc->data_bits_per_frame == ldpc->ldpc_data_bits_per_frame); + *iter = run_ldpc_decoder(ldpc, out_char, llr, parityCheckCount); + break; case LDPC_PROT_2020: - /* some data bits in codeword unused, effectively - decreasing code rate and making FEC more powerful - (without having to design a new code) */ - for (i = 0; i < ldpc->data_bits_per_frame; i++) - llr_full_codeword[i] = llr[i]; - // known bits ... so really likely - for (i = ldpc->data_bits_per_frame; i < ldpc->ldpc_data_bits_per_frame; i++) - llr_full_codeword[i] = -100.0f; - // parity bits at end - for (i = ldpc->ldpc_data_bits_per_frame; i < ldpc->ldpc_coded_bits_per_frame; i++) - llr_full_codeword[i] = llr[i - unused_data_bits]; - *iter = run_ldpc_decoder(ldpc, out_char, llr_full_codeword, parityCheckCount); - break; + /* some data bits in codeword unused, effectively + decreasing code rate and making FEC more powerful + (without having to design a new code) */ + for (i = 0; i < ldpc->data_bits_per_frame; i++) + llr_full_codeword[i] = llr[i]; + // known bits ... so really likely + for (i = ldpc->data_bits_per_frame; i < ldpc->ldpc_data_bits_per_frame; + i++) + llr_full_codeword[i] = -100.0f; + // parity bits at end + for (i = ldpc->ldpc_data_bits_per_frame; + i < ldpc->ldpc_coded_bits_per_frame; i++) + llr_full_codeword[i] = llr[i - unused_data_bits]; + *iter = + run_ldpc_decoder(ldpc, out_char, llr_full_codeword, parityCheckCount); + break; case LDPC_PROT_2020B: - /* 2020B waveform, with unequal error protection. Only the - stage1 VQ index of each LPCNet vocoder frames is - protected. In this case the FEC codeword is much smaller - than the payload data. */ - - // set up LDPC codeword - for(j=0,codec_frame=0; codec_frame<3; codec_frame++) - for(i=0; i<11; i++,j++) - llr_full_codeword[j] = llr[codec_frame*52+i]; - // set known LDPC codeword data bits - for (i = 33; i < ldpc->ldpc_data_bits_per_frame; i++) - llr_full_codeword[i] = -100; - // parity bits at end - for (i=0; i<ldpc->NumberParityBits; i++) - llr_full_codeword[ldpc->ldpc_data_bits_per_frame+i] = llr[ldpc->data_bits_per_frame+i]; - *iter = run_ldpc_decoder(ldpc, out_char_ldpc, llr_full_codeword, parityCheckCount); - - // pass through received data bits, replacing only decoded bits - for (i = 0; i < ldpc->data_bits_per_frame; i++) { - out_char[i] = llr[i] < 0; - } - for(j=0,codec_frame=0; codec_frame<3; codec_frame++) - for(i=0; i<11; i++,j++) - out_char[codec_frame*52+i] = out_char_ldpc[j]; - - break; + /* 2020B waveform, with unequal error protection. Only the + stage1 VQ index of each LPCNet vocoder frames is + protected. In this case the FEC codeword is much smaller + than the payload data. */ + + // set up LDPC codeword + for (j = 0, codec_frame = 0; codec_frame < 3; codec_frame++) + for (i = 0; i < 11; i++, j++) + llr_full_codeword[j] = llr[codec_frame * 52 + i]; + // set known LDPC codeword data bits + for (i = 33; i < ldpc->ldpc_data_bits_per_frame; i++) + llr_full_codeword[i] = -100; + // parity bits at end + for (i = 0; i < ldpc->NumberParityBits; i++) + llr_full_codeword[ldpc->ldpc_data_bits_per_frame + i] = + llr[ldpc->data_bits_per_frame + i]; + *iter = run_ldpc_decoder(ldpc, out_char_ldpc, llr_full_codeword, + parityCheckCount); + + // pass through received data bits, replacing only decoded bits + for (i = 0; i < ldpc->data_bits_per_frame; i++) { + out_char[i] = llr[i] < 0; + } + for (j = 0, codec_frame = 0; codec_frame < 3; codec_frame++) + for (i = 0; i < 11; i++, j++) + out_char[codec_frame * 52 + i] = out_char_ldpc[j]; + + break; default: - assert(0); - } + assert(0); + } } - /* Count uncoded (raw) bit errors over frame, note we don't include UW of txt bits as this is done after we dissassemmble the frame */ -int count_uncoded_errors(struct LDPC *ldpc, struct OFDM_CONFIG *config, COMP codeword_symbols_de[], int crc16) { - int i, Nerrs; - - int coded_syms_per_frame = ldpc->coded_bits_per_frame/config->bps; - int coded_bits_per_frame = ldpc->coded_bits_per_frame; - int data_bits_per_frame = ldpc->data_bits_per_frame; - int rx_bits_raw[coded_bits_per_frame]; - - /* generate test codeword from known payload data bits */ - - int test_codeword[coded_bits_per_frame]; - uint16_t r[data_bits_per_frame]; - uint8_t tx_bits[data_bits_per_frame]; - - ofdm_rand(r, data_bits_per_frame); - - for (i = 0; i < data_bits_per_frame; i++) { - tx_bits[i] = r[i] > 16384; - } - if (crc16) { - uint16_t tx_crc16 = freedv_crc16_unpacked(tx_bits, data_bits_per_frame - 16); - uint8_t tx_crc16_bytes[] = { tx_crc16 >> 8, tx_crc16 & 0xff }; - freedv_unpack(tx_bits + data_bits_per_frame - 16, tx_crc16_bytes, 16); - } - ldpc_encode_frame(ldpc, test_codeword, tx_bits); - - for (i = 0; i < coded_syms_per_frame; i++) { - int bits[2]; - complex float s = codeword_symbols_de[i].real + I * codeword_symbols_de[i].imag; - qpsk_demod(s, bits); - rx_bits_raw[config->bps * i] = bits[1]; - rx_bits_raw[config->bps * i + 1] = bits[0]; - } - - Nerrs = 0; - - for (i = 0; i < coded_bits_per_frame; i++) { - if (test_codeword[i] != rx_bits_raw[i]) Nerrs++; - } - - return Nerrs; +int count_uncoded_errors(struct LDPC *ldpc, struct OFDM_CONFIG *config, + COMP codeword_symbols_de[], int crc16) { + int i, Nerrs; + + int coded_syms_per_frame = ldpc->coded_bits_per_frame / config->bps; + int coded_bits_per_frame = ldpc->coded_bits_per_frame; + int data_bits_per_frame = ldpc->data_bits_per_frame; + int rx_bits_raw[coded_bits_per_frame]; + + /* generate test codeword from known payload data bits */ + + int test_codeword[coded_bits_per_frame]; + uint16_t r[data_bits_per_frame]; + uint8_t tx_bits[data_bits_per_frame]; + + ofdm_rand(r, data_bits_per_frame); + + for (i = 0; i < data_bits_per_frame; i++) { + tx_bits[i] = r[i] > 16384; + } + if (crc16) { + uint16_t tx_crc16 = + freedv_crc16_unpacked(tx_bits, data_bits_per_frame - 16); + uint8_t tx_crc16_bytes[] = {tx_crc16 >> 8, tx_crc16 & 0xff}; + freedv_unpack(tx_bits + data_bits_per_frame - 16, tx_crc16_bytes, 16); + } + ldpc_encode_frame(ldpc, test_codeword, tx_bits); + + for (i = 0; i < coded_syms_per_frame; i++) { + int bits[2]; + complex float s = + codeword_symbols_de[i].real + I * codeword_symbols_de[i].imag; + qpsk_demod(s, bits); + rx_bits_raw[config->bps * i] = bits[1]; + rx_bits_raw[config->bps * i + 1] = bits[0]; + } + + Nerrs = 0; + + for (i = 0; i < coded_bits_per_frame; i++) { + if (test_codeword[i] != rx_bits_raw[i]) Nerrs++; + } + + return Nerrs; } int count_errors(uint8_t tx_bits[], uint8_t rx_bits[], int n) { - int i; - int Nerrs = 0; + int i; + int Nerrs = 0; - for (i = 0; i < n; i++) - if (tx_bits[i] != rx_bits[i]) Nerrs++; + for (i = 0; i < n; i++) + if (tx_bits[i] != rx_bits[i]) Nerrs++; - return Nerrs; + return Nerrs; } - -/* for unequal protection modes, count coded errors only in those bits that have been protected */ -void count_errors_protection_mode(int protection_mode, int *pNerrs, int *pNcoded, uint8_t tx_bits[], +/* for unequal protection modes, count coded errors only in those bits that have + * been protected */ +void count_errors_protection_mode(int protection_mode, int *pNerrs, + int *pNcoded, uint8_t tx_bits[], uint8_t rx_bits[], int n) { - int i; - int Nerrs = 0; - int Ncoded = 0; + int i; + int Nerrs = 0; + int Ncoded = 0; - switch (protection_mode) { + switch (protection_mode) { case LDPC_PROT_EQUAL: case LDPC_PROT_2020: - for (i = 0; i < n; i++) { - if (tx_bits[i] != rx_bits[i]) Nerrs++; - Ncoded++; - } - break; + for (i = 0; i < n; i++) { + if (tx_bits[i] != rx_bits[i]) Nerrs++; + Ncoded++; + } + break; case LDPC_PROT_2020B: - /* We only protect bits 0..10 in each 52 bit LPCNet codec - frame. There are 3 codec frames 3x52=156 data bits, of - which only 11*3 = 33 bits are protected. - */ - for(int codec_frame=0; codec_frame<3; codec_frame++) { - for(i=0; i<11; i++) { - if (tx_bits[codec_frame*52+i] != rx_bits[codec_frame*52+i]) Nerrs++; - Ncoded++; - } + /* We only protect bits 0..10 in each 52 bit LPCNet codec + frame. There are 3 codec frames 3x52=156 data bits, of + which only 11*3 = 33 bits are protected. + */ + for (int codec_frame = 0; codec_frame < 3; codec_frame++) { + for (i = 0; i < 11; i++) { + if (tx_bits[codec_frame * 52 + i] != rx_bits[codec_frame * 52 + i]) + Nerrs++; + Ncoded++; } - break; + } + break; default: - assert(0); - } + assert(0); + } - *pNerrs = Nerrs; - *pNcoded = Ncoded; + *pNerrs = Nerrs; + *pNcoded = Ncoded; } /* Given an array of tx_bits, LDPC encodes, interleaves, and OFDM modulates */ -void ofdm_ldpc_interleave_tx(struct OFDM *ofdm, struct LDPC *ldpc, complex float tx_sams[], uint8_t tx_bits[], uint8_t txt_bits[]) { - int Npayloadsymsperpacket = ldpc->coded_bits_per_frame/ofdm->bps; - int Npayloadbitsperpacket = ldpc->coded_bits_per_frame; - int Nbitsperpacket = ofdm_get_bits_per_packet(ofdm); - int codeword[Npayloadbitsperpacket]; - COMP payload_symbols[Npayloadsymsperpacket]; - COMP payload_symbols_inter[Npayloadsymsperpacket]; - complex float tx_symbols[Nbitsperpacket/ ofdm->bps]; - - ldpc_encode_frame(ldpc, codeword, tx_bits); - qpsk_modulate_frame(payload_symbols, codeword, Npayloadsymsperpacket); - gp_interleave_comp(payload_symbols_inter, payload_symbols, Npayloadsymsperpacket); - ofdm_assemble_qpsk_modem_packet_symbols(ofdm, tx_symbols, payload_symbols_inter, txt_bits); - ofdm_txframe(ofdm, tx_sams, tx_symbols); +void ofdm_ldpc_interleave_tx(struct OFDM *ofdm, struct LDPC *ldpc, + complex float tx_sams[], uint8_t tx_bits[], + uint8_t txt_bits[]) { + int Npayloadsymsperpacket = ldpc->coded_bits_per_frame / ofdm->bps; + int Npayloadbitsperpacket = ldpc->coded_bits_per_frame; + int Nbitsperpacket = ofdm_get_bits_per_packet(ofdm); + int codeword[Npayloadbitsperpacket]; + COMP payload_symbols[Npayloadsymsperpacket]; + COMP payload_symbols_inter[Npayloadsymsperpacket]; + complex float tx_symbols[Nbitsperpacket / ofdm->bps]; + + ldpc_encode_frame(ldpc, codeword, tx_bits); + qpsk_modulate_frame(payload_symbols, codeword, Npayloadsymsperpacket); + gp_interleave_comp(payload_symbols_inter, payload_symbols, + Npayloadsymsperpacket); + ofdm_assemble_qpsk_modem_packet_symbols(ofdm, tx_symbols, + payload_symbols_inter, txt_bits); + ofdm_txframe(ofdm, tx_sams, tx_symbols); } |
