/* ldpc interface to decoder * * It is expected that the switch to ldpc will give a 60% speed improvement * over golay code, with no loss of performance over white noise - the use of * soft-bit detection and longer codewords compensating for the expected 2dB loss * from reducing the number of parity bits. * * Golay code can reliably correct a 10% BER, equivalent to a 20% loss of signal * during deep fading. It is not clear how well ldpc will cope with deep fading, * but the shorter packers are bound to be more badly affected. */ #include #include "math.h" #include "string.h" #include "mpdecode_core.h" #include "horus_l2.h" #include "H_128_384_23.h" #include "H_256_768_22.h" #define MAX_ITER 20 /* Scramble and interleave are 8bit lsb, but bitstream is sent msb */ #define LSB2MSB(X) (X + 7 - 2 * (X & 7) ) /* Invert bits - ldpc expects negative floats for high hits */ void soft_unscramble(float *in, float* out, int nbits) { int i, ibit; uint16_t scrambler = 0x4a80; /* init additive scrambler at start of every frame */ uint16_t scrambler_out; for ( i = 0; i < nbits; i++ ) { scrambler_out = ( (scrambler >> 1) ^ scrambler) & 0x1; /* modify i-th bit by xor-ing with scrambler output sequence */ ibit = LSB2MSB(i); if ( scrambler_out ) { out[ibit] = in[ibit]; } else { out[ibit] = -in[ibit]; } scrambler >>= 1; scrambler |= scrambler_out << 14; } } // soft bit deinterleave void soft_deinterleave(float *in, float* out, int mode) { int n, i, j, bits_per_packet, coprime; if (mode == 1) { // 256_768 bits_per_packet = H_256_768_22_BITS_PER_PACKET; coprime = H_256_768_22_COPRIME; } else { bits_per_packet = H_128_384_23_BITS_PER_PACKET; coprime = H_128_384_23_COPRIME; } for ( n = 0; n < bits_per_packet; n++ ) { i = LSB2MSB(n); j = LSB2MSB( (coprime * n) % bits_per_packet); out[i] = in[j]; } } // // packed bit deinterleave - same as Golay version , but different Coprime // void bitwise_deinterleave(uint8_t *inout, int nbytes) // { // uint16_t nbits = (uint16_t)nbytes*8; // uint32_t i, j, ibit, ibyte, ishift, jbyte, jshift; // uint8_t out[nbytes]; // memset(out, 0, nbytes); // for(j = 0; j < nbits; j++) { // i = (COPRIME * j) % nbits; // /* read bit i */ // ibyte = i>>3; // ishift = i&7; // ibit = (inout[ibyte] >> ishift) & 0x1; // /* write bit i to bit j position */ // jbyte = j>>3; // jshift = j&7; // out[jbyte] |= ibit << jshift; // } // memcpy(inout, out, nbytes); // } // /* Compare detected bits to corrected bits */ // void ldpc_errors( const uint8_t *outbytes, uint8_t *rx_bytes ) { // int length = DATA_BYTES + PARITY_BYTES; // uint8_t temp[length]; // int i, percentage, count = 0; // memcpy(temp, rx_bytes, length); // scramble(temp, length); // use scrambler from Golay code // bitwise_deinterleave(temp, length); // // count bits changed during error correction // for(i = 0; i < BITS_PER_PACKET; i++) { // int x, y, offset, shift; // shift = i & 7; // offset = i >> 3; // x = temp[offset] >> shift; // y = outbytes[offset] >> shift; // count += (x ^ y) & 1; // } // // scale errors against a maximum of 20% BER // percentage = (count * 5 * 100) / BITS_PER_PACKET; // if (percentage > 100) // percentage = 100; // set_error_count( percentage ); // } /* LDPC decode */ void horus_ldpc_decode(uint8_t *payload, float *sd, int mode) { float sum, mean, sumsq, estEsN0, x; int bits_per_packet; if(mode == 1){ bits_per_packet = H_256_768_22_BITS_PER_PACKET; } else { bits_per_packet = H_128_384_23_BITS_PER_PACKET; } float llr[bits_per_packet]; float temp[bits_per_packet]; uint8_t outbits[bits_per_packet]; int b, i, parityCC; struct LDPC ldpc; /* normalise bitstream to log-like */ sum = 0.0; for ( i = 0; i < bits_per_packet; i++ ) sum += fabs(sd[i]); mean = sum / bits_per_packet; sumsq = 0.0; for ( i = 0; i < bits_per_packet; i++ ) { x = fabs(sd[i]) / mean - 1.0; sumsq += x * x; } estEsN0 = 2.0 * bits_per_packet / (sumsq + 1.0e-3) / mean; for ( i = 0; i < bits_per_packet; i++ ) llr[i] = estEsN0 * sd[i]; /* reverse whitening and re-order bits */ soft_unscramble(llr, temp, bits_per_packet); soft_deinterleave(temp, llr, mode); /* correct errors */ if (mode == 1){ // 32-byte mode H_256_768_22 ldpc.max_iter = H_256_768_22_MAX_ITER; ldpc.dec_type = 0; ldpc.q_scale_factor = 1; ldpc.r_scale_factor = 1; ldpc.CodeLength = H_256_768_22_CODELENGTH; ldpc.NumberParityBits = H_256_768_22_NUMBERPARITYBITS; ldpc.NumberRowsHcols = H_256_768_22_NUMBERROWSHCOLS; ldpc.max_row_weight = H_256_768_22_MAX_ROW_WEIGHT; ldpc.max_col_weight = H_256_768_22_MAX_COL_WEIGHT; ldpc.H_rows = (uint16_t *)H_256_768_22_H_rows; ldpc.H_cols = (uint16_t *)H_256_768_22_H_cols; } else { // 16-byte mode ldpc.max_iter = H_128_384_23_MAX_ITER; ldpc.dec_type = 0; ldpc.q_scale_factor = 1; ldpc.r_scale_factor = 1; ldpc.CodeLength = H_128_384_23_CODELENGTH; ldpc.NumberParityBits = H_128_384_23_NUMBERPARITYBITS; ldpc.NumberRowsHcols = H_128_384_23_NUMBERROWSHCOLS; ldpc.max_row_weight = H_128_384_23_MAX_ROW_WEIGHT; ldpc.max_col_weight = H_128_384_23_MAX_COL_WEIGHT; ldpc.H_rows = (uint16_t *)H_128_384_23_H_rows; ldpc.H_cols = (uint16_t *)H_128_384_23_H_cols; } i = run_ldpc_decoder(&ldpc, outbits, llr, &parityCC); /* convert MSB bits to a packet of bytes */ for (b = 0; b < (bits_per_packet/8); b++) { uint8_t rxbyte = 0; for(i=0; i<8; i++) rxbyte |= outbits[b*8+i] << (7 - i); payload[b] = rxbyte; } }