/* 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 #include #include "mpdecode_core.h" #ifndef USE_ORIGINAL_PHI0 #include "phi0.h" #endif #include "debug_alloc.h" #ifdef __EMBEDDED__ #include "machdep.h" #endif #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} }; // c_nodes will be an array of NumberParityBits of struct c_node // Each c_node contains an array of c_sub_node elements // This structure reduces the indexing caluclations in SumProduct() struct c_sub_node { // Order is important here to keep total size small. uint16_t index; // Values from H_rows (except last 2 entries) uint16_t socket; // The socket number at the v_node float message; // modified during operation! }; struct c_node { int degree; // A count of elements in the following arrays struct c_sub_node *subs; }; // v_nodes will be an array of CodeLength of struct v_node struct v_sub_node { uint16_t index; // the index of a c_node it is connected to // Filled with values from H_cols (except last 2 entries) uint16_t socket; // socket number at the c_node float message; // Loaded with input data // modified during operation! uint8_t sign; // 1 if input is negative // modified during operation! }; struct v_node { int degree; // A count of ??? float initial_value; struct v_sub_node *subs; }; void encode(struct LDPC *ldpc, unsigned char ibits[], unsigned char pbits[]) { unsigned int p, i, tmp, par, prev=0; int ind; uint16_t *H_rows = ldpc->H_rows; for (p=0; pNumberParityBits; p++) { par = 0; for (i=0; imax_row_weight; i++) { ind = 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; } } #ifdef USE_ORIGINAL_PHI0 /* 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) ) ); } } #endif /* 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, uint16_t *H_rows, int H1, int CodeLength, struct v_node *v_nodes, int NumberRowsHcols, uint16_t *H_cols, int max_col_weight, int dec_type, float *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].subs[j].index=i-(CodeLength-NumberParityBits+shift)+count; if (shift ==0){ count=count+1; } else{ count=count+shift; } } else { v_nodes[i].subs[j].index = (H_cols[i+j*NumberRowsHcols] - 1); } /* search the connected c-node for the proper message value */ for (c_index=0;c_indexindex ].subs[ cp->socket ]; phi_sum += vp->message; sign ^= vp->sign; } if (sign==0) ssum++; for (i=0;iindex ].subs[ cp->socket ]; if ( sign ^ vp->sign ) { cp->message = -phi0( phi_sum - vp->message ); // *r_scale_factor; } else cp->message = phi0( phi_sum - vp->message ); // *r_scale_factor; } } /* update q */ for (i=0;iindex ].subs[ vp->socket ].message; } /* make hard decision */ if (Qi < 0) { DecodedBits[i] = 1; } /* now subtract to get the extrinsic information */ for (j=0;jindex ].subs[ vp->socket ].message; vp->message = phi0( fabs( temp_sum ) ); // *q_scale_factor; if (temp_sum > 0) vp->sign = 0; else vp->sign = 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; char *DecodedBits = CALLOC( CodeLength, sizeof( char ) ); assert(DecodedBits); /* 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; /* initialize c-node and v-node structures */ c_nodes = CALLOC( NumberParityBits, sizeof( struct c_node ) ); assert(c_nodes); v_nodes = CALLOC( CodeLength, sizeof( struct v_node)); assert(v_nodes); 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.0L) - (sd[i] < 0.0L); x = (sd[i]/mean - sign); sum += x; sumsq += x*x; } estvar = (n * sumsq - sum * sum) / (n * (n - 1)); //fprintf(stderr, "mean: %f var: %f\n", mean, estvar); estEsN0 = 1.0/(2.0L * estvar + 1E-3); for(i=0; i> 1; } mask = 1 << (bps - 1); for (k=0;k> 1; } } for (k=0;kmax_iter = %d\n", ldpc->max_iter); fprintf(stderr, "ldpc->dec_type = %d\n", ldpc->dec_type); fprintf(stderr, "ldpc->q_scale_factor = %d\n", ldpc->q_scale_factor); fprintf(stderr, "ldpc->r_scale_factor = %d\n", ldpc->r_scale_factor); fprintf(stderr, "ldpc->CodeLength = %d\n", ldpc->CodeLength); fprintf(stderr, "ldpc->NumberParityBits = %d\n", ldpc->NumberParityBits); fprintf(stderr, "ldpc->NumberRowsHcols = %d\n", ldpc->NumberRowsHcols); fprintf(stderr, "ldpc->max_row_weight = %d\n", ldpc->max_row_weight); fprintf(stderr, "ldpc->max_col_weight = %d\n", ldpc->max_col_weight); fprintf(stderr, "ldpc->data_bits_per_frame = %d\n", ldpc->data_bits_per_frame); fprintf(stderr, "ldpc->coded_bits_per_frame = %d\n", ldpc->coded_bits_per_frame); fprintf(stderr, "ldpc->coded_syms_per_frame = %d\n", ldpc->coded_syms_per_frame); } /* vi:set ts=4 et sts=4: */