/* FILE...: mpdecode_core.c AUTHOR.: Matthew C. Valenti, Rohit Iyer Seshadri, David Rowe CREATED: Sep 2016 C-callable core functions moved from MpDecode.c, so they can be used for Octave and C programs. */ #include #include #include #include "mpdecode_core.h" #define QPSK_CONSTELLATION_SIZE 4 #define QPSK_BITS_PER_SYMBOL 2 /* QPSK constellation for symbol likelihood calculations */ static COMP S_matrix[] = { { 1.0f, 0.0f}, { 0.0f, 1.0f}, { 0.0f, -1.0f}, {-1.0f, 0.0f} }; int extract_output(char out_char[], int DecodedBits[], int ParityCheckCount[], int max_iter, int CodeLength, int NumberParityBits); void encode(struct LDPC *ldpc, unsigned char ibits[], unsigned char pbits[]) { unsigned int p, i, tmp, par, prev=0; int ind; double *H_rows = ldpc->H_rows; for (p=0; pNumberParityBits; p++) { par = 0; for (i=0; imax_row_weight; i++) { ind = (int)H_rows[p + i*ldpc->NumberParityBits]; par = par + ibits[ind-1]; } tmp = par + prev; tmp &= 1; // only retain the lsb prev = tmp; pbits[p] = tmp; } } /* Phi function */ static float phi0( float x ) { float z; if (x>10) return( 0 ); else if (x< 9.08e-5 ) return( 10 ); else if (x > 9) return( 1.6881e-4 ); /* return( 1.4970e-004 ); */ else if (x > 8) return( 4.5887e-4 ); /* return( 4.0694e-004 ); */ else if (x > 7) return( 1.2473e-3 ); /* return( 1.1062e-003 ); */ else if (x > 6) return( 3.3906e-3 ); /* return( 3.0069e-003 ); */ else if (x > 5) return( 9.2168e-3 ); /* return( 8.1736e-003 ); */ else { z = (float) exp(x); return( (float) log( (z+1)/(z-1) ) ); } } static float correction(float xinput ) { if (xinput > 2.625 ) return( 0 ); else if (xinput < 1 ) return( -0.375*xinput + 0.6825 ); else return( -0.1875*xinput + 0.5 ); } static float LambdaAPPstar( float mag1, float mag2 ) { if (mag1 > mag2) return( fabs( mag2 + correction( mag1 + mag2 ) - correction( mag1 - mag2 ) ) ); else return( fabs( mag1 + correction( mag1 + mag2 ) - correction( mag2 - mag1 ) ) ); } /* Values for linear approximation (DecoderType=5) */ #define AJIAN -0.24904163195436 #define TJIAN 2.50681740420944 /* The linear-log-MAP algorithm */ static float max_star0( float delta1, float delta2 ) { register float diff; diff = delta2 - delta1; if ( diff > TJIAN ) return( delta2 ); else if ( diff < -TJIAN ) return( delta1 ); else if ( diff > 0 ) return( delta2 + AJIAN*(diff-TJIAN) ); else return( delta1 - AJIAN*(diff+TJIAN) ); } void init_c_v_nodes(struct c_node *c_nodes, int shift, int NumberParityBits, int max_row_weight, double *H_rows, int H1, int CodeLength, struct v_node *v_nodes, int NumberRowsHcols, double *H_cols, int max_col_weight, int dec_type, double *input) { int i, j, k, count, cnt, c_index, v_index; /* first determine the degree of each c-node */ if (shift ==0){ for (i=0;i 0 ) { count++; } } c_nodes[i].degree = count; if (H1){ if (i==0){ c_nodes[i].degree=count+1; } else{ c_nodes[i].degree=count+2; } } } } else{ cnt=0; for (i=0;i<(NumberParityBits/shift);i++) { for (k=0;k 0 ) { count++; } } c_nodes[cnt].degree = count; if ((i==0)||(i==(NumberParityBits/shift)-1)){ c_nodes[cnt].degree=count+1; } else{ c_nodes[cnt].degree=count+2; } cnt++; } } } if (H1){ if (shift ==0){ for (i=0;i0){ cnt=0; for (i=0;i<(NumberParityBits/shift);i++){ for (k =0;k 0 ) { count++; } } v_nodes[i].degree = count; } for(i=CodeLength-NumberParityBits+shift;i 0 ) { count++; } } v_nodes[i].degree = count; } } if (shift>0){ v_nodes[CodeLength-1].degree =v_nodes[CodeLength-1].degree+1; } /* set up v_nodes */ for (i=0;i=CodeLength-NumberParityBits+shift)){ v_nodes[i].index[j]=i-(CodeLength-NumberParityBits+shift)+count; if (shift ==0){ count=count+1; } else{ count=count+shift; } } else { v_nodes[i].index[j] = (int) (H_cols[i+j*NumberRowsHcols] - 1); } /* search the connected c-node for the proper message value */ for (c_index=0;c_index 0) v_nodes[i].sign[j] = 0; else v_nodes[i].sign[j] = 1; } } /* detect errors */ if (BitErrors[iter] == 0) break; } } /* function for doing the MP decoding */ void MinSum( int BitErrors[], int DecodedBits[], struct c_node c_nodes[], struct v_node v_nodes[], int CodeLength, int NumberParityBits, int max_iter, float r_scale_factor, float q_scale_factor, int data[] ) { int i,j, iter, i_prime; float min_beta; int sign; float temp_sum; float Qi; for (iter=0;iter 0) v_nodes[i].sign[j] = 0; else v_nodes[i].sign[j] = 1; } } /* count data bit errors, assuming that it is systematic */ for (i=0;i 0) v_nodes[i].sign[j] = 0; else v_nodes[i].sign[j] = 1; } } /* count data bit errors, assuming that it is systematic */ for (i=0;imax_iter; dec_type = ldpc->dec_type; q_scale_factor = ldpc->q_scale_factor; r_scale_factor = ldpc->r_scale_factor; CodeLength = ldpc->CodeLength; /* length of entire codeword */ NumberParityBits = ldpc->NumberParityBits; NumberRowsHcols = ldpc->NumberRowsHcols; int *DecodedBits = calloc( max_iter*CodeLength, sizeof( int ) ); int *ParityCheckCount = calloc( max_iter, sizeof(int) ); /* derive some parameters */ shift = (NumberParityBits + NumberRowsHcols) - CodeLength; if (NumberRowsHcols == CodeLength) { H1=0; shift=0; } else { H1=1; } max_row_weight = ldpc->max_row_weight; max_col_weight = ldpc->max_col_weight; /* c_nodes = calloc( NumberParityBits, sizeof( struct c_node ) ); v_nodes = calloc( CodeLength, sizeof( struct v_node)); */ /* initialize c-node and v-node structures */ c_nodes = calloc( NumberParityBits, sizeof( struct c_node ) ); v_nodes = calloc( CodeLength, sizeof( struct v_node)); init_c_v_nodes(c_nodes, shift, NumberParityBits, max_row_weight, ldpc->H_rows, H1, CodeLength, v_nodes, NumberRowsHcols, ldpc->H_cols, max_col_weight, dec_type, input); int DataLength = CodeLength - NumberParityBits; int *data_int = calloc( DataLength, sizeof(int) ); /* need to clear these on each call */ for(i=0; i 0.0) - (sd[i] < 0.0); x = (sd[i] - sign); sum += x; sumsq += x*x; } mean = sum/n; estvar = sumsq/n - mean*mean; estEsN0 = 1.0/(2.0 * estvar + 1E-3); for(i=0; i> 1; } mask = 1 << (bps - 1); for (k=0;k> 1; } } for (k=0;k