uint8_t packet[BYTES_PER_PACKET+CRC_BYTES];
uint8_t abyte;
uint16_t tx_checksum, rx_checksum, packet_errors, packets;
- int CodeLength, iter;
+ int CodeLength, iter, parityCheckCount;
struct LDPC ldpc;
assert(sizeof(uw) == UW_BITS);
/* now LDPC decode */
sd_to_llr(llr, symbol_buf_no_rs232, CodeLength);
- iter = run_ldpc_decoder(&ldpc, unpacked_packet, llr);
+ iter = run_ldpc_decoder(&ldpc, unpacked_packet, llr, &parityCheckCount);
/* pack into bytes */
/* 2 FSK -d/2, +d/2 */
/* 4 FSK -3*d/2, -d/2, +d/2, 3*d/2 */
+ /* note: drive is inverted, a higher tone drives VCO voltage lower */
+
float symf = sym;
- float level = d*(symf - ((float)m-1)*0.5);
+ float level = d*(((float)m-1)*0.5 - symf);
assert(level <= 32767.0);
assert(level >= -32768.0);
short level_short = (short)level;
int main(int argc, char *argv[])\r
{ \r
int CodeLength, NumberParityBits;\r
- int i, r, num_ok, num_runs, codename;\r
+ int i, r, num_ok, num_runs, codename, parityCheckCount, mute, state, next_state, frame;\r
char out_char[CODELENGTH], *adetected_data;\r
struct LDPC ldpc;\r
double *ainput;\r
fprintf(stderr, "usage: %s InOneSymbolPerDouble OutOneBitPerByte [--sd] [--half] [--code CodeName]\n\n", argv[0]);\r
fprintf(stderr, " InOneSymbolPerDouble Input file of double LLRs, use - for the \n"); \r
fprintf(stderr, " file names to use stdin/stdout\n");\r
- fprintf(stderr, " --code Treat input file samples as Soft Decision\n");\r
- fprintf(stderr, " demod outputs rather than LLRs\n");\r
+ fprintf(stderr, " --code Use LDPC code CodeName\n");\r
fprintf(stderr, " --sd Treat input file samples as Soft Decision\n");\r
fprintf(stderr, " demod outputs rather than LLRs\n");\r
fprintf(stderr, " --half Load framesize/2 input samples for each decode\n");\r
fprintf(stderr, " attempt, only output decoded bits if decoder\n");\r
fprintf(stderr, " converges. Form of frame sync.\n");\r
+ fprintf(stderr, " --mute Only output frames with < 10%% parity check fails\n");\r
fprintf(stderr, "\n");\r
exit(0);\r
}\r
\r
for(r=0; r<num_runs; r++) {\r
\r
- run_ldpc_decoder(&ldpc, out_char, ainput);\r
+ run_ldpc_decoder(&ldpc, out_char, ainput, &parityCheckCount);\r
\r
int ok = 0;\r
for (i=0; i<CodeLength; i++) {\r
\r
sdinput = 0;\r
readhalfframe = 0;\r
+ mute = 0; state = 0; frame = 0;\r
if (opt_exists(argv, argc, "--sd")) {\r
sdinput = 1;\r
}\r
if (opt_exists(argv, argc, "--half")) {\r
readhalfframe = 1;\r
}\r
+ if (opt_exists(argv, argc, "--mute")) {\r
+ mute = 1;\r
+ }\r
\r
double *input_double = calloc(CodeLength, sizeof(double));\r
\r
sd_to_llr(input_double, input_double, CodeLength);\r
}\r
\r
- iter = run_ldpc_decoder(&ldpc, out_char, input_double);\r
- fprintf(stderr, "%4d ", iter);\r
-\r
- // output data bits if decoder converged\r
-\r
- if (iter != MAX_ITER) {\r
- fwrite(out_char, sizeof(char), ldpc.NumberRowsHcols, fout);\r
+ iter = run_ldpc_decoder(&ldpc, out_char, input_double, &parityCheckCount);\r
+\r
+ if (mute) {\r
+\r
+ // Output data bits if decoder converged, or was\r
+ // within 10% of all parity checks converging (10% est\r
+ // BER). usefule for real world operation as it can\r
+ // resync and won't send crappy packets to the decoder\r
+ \r
+ float ber_est = (float)(ldpc.NumberParityBits - parityCheckCount)/ldpc.NumberParityBits;\r
+ //fprintf(stderr, "iter: %4d parityCheckErrors: %4d ber: %3.2f\n", iter, ldpc.NumberParityBits - parityCheckCount, ber_est);\r
+ if (ber_est < 0.1) {\r
+ fwrite(out_char, sizeof(char), ldpc.NumberRowsHcols, fout);\r
+ }\r
+\r
+ } else {\r
+ \r
+ // Output all data packets, based on initial FEC sync\r
+ // estimate. Useful for testing with cohpsk_put_bits,\r
+ // as it maintains sync with test bits state machine.\r
+ \r
+ next_state = state;\r
+ switch(state) {\r
+ case 0:\r
+ if (iter < MAX_ITER) {\r
+ /* OK we've found which frame to sync on */\r
+ next_state = 1;\r
+ frame = 0;\r
+ }\r
+ break;\r
+ case 1:\r
+ frame++;\r
+ if ((frame % 2) == 0) {\r
+ /* write decoded packets every second input frame */\r
+ fwrite(out_char, sizeof(char), ldpc.NumberRowsHcols, fout);\r
+ }\r
+ break;\r
+ }\r
+ state = next_state;\r
+ //fprintf(stderr, "state: %d iter: %d\n", state, iter);\r
}\r
\r
for(i=0; i<offset; i++) {\r
}
}
-static float correction(
- float xinput )
+static float correction(float xinput )
{
if (xinput > 2.625 )
return( 0 );
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,
/* Convenience function to call LDPC decoder from C programs */
-int run_ldpc_decoder(struct LDPC *ldpc, char out_char[], double input[]) {
+int run_ldpc_decoder(struct LDPC *ldpc, char out_char[], double input[], int *parityCheckCount) {
int max_iter, dec_type;
float q_scale_factor, r_scale_factor;
int max_row_weight, max_col_weight;
int iter = extract_output(out_char, DecodedBits, ParityCheckCount, max_iter, CodeLength, NumberParityBits);
+ *parityCheckCount = ParityCheckCount[iter-1];
+
/* Clean up memory */
free(ParityCheckCount);
}
+/*
+ output[] is symbol likelihood
+
+ Note we assume fading[] is real, it is also possible to compute
+ with complex fading.
+*/
+
+void Demod2D(float symbol_likelihood[], /* output, M*number_symbols */
+ COMP r[], /* received QPSK symbols, number_symbols */
+ COMP S_matrix[], /* constellation of size M */
+ float EsNo,
+ float fading[], /* real fading values, number_symbols */
+ int number_symbols)
+{
+ int M=4;
+ int i,j;
+ float tempsr, tempsi, Er, Ei;
+
+ /* determine output */
+
+ for (i=0;i<number_symbols;i++) { /* go through each received symbol */
+ for (j=0;j<M;j++) { /* each postulated symbol */
+ tempsr = fading[i]*S_matrix[j].real;
+ tempsi = fading[i]*S_matrix[j].imag;
+ Er = r[i].real - tempsr;
+ Ei = r[i].imag - tempsi;
+ symbol_likelihood[i*M+j] = -EsNo*(Er*Er+Ei*Ei);
+ }
+ }
+
+}
+
+
+void Somap(float bit_likelihood[], /* number_bits, bps*number_symbols */
+ float symbol_likelihood[], /* M*number_symbols */
+ int number_symbols)
+{
+ int M=2, bps = 2;
+ int n,i,j,k,mask;
+ float num[bps], den[bps];
+ float metric;
+
+ for (n=0; n<number_symbols; n++) { /* loop over symbols */
+ for (k=0;k<bps;k++) {
+ /* initialize */
+ num[k] = -1000000;
+ den[k] = -1000000;
+ }
+
+ for (i=0;i<M;i++) {
+ metric = symbol_likelihood[n*M+i]; /* channel metric for this symbol */
+
+ mask = 1 << bps - 1;
+ for (j=0;j<bps;j++) {
+ mask = mask >> 1;
+ }
+ mask = 1 << bps - 1;
+
+ for (k=0;k<bps;k++) { /* loop over bits */
+ if (mask&i) {
+ /* this bit is a one */
+ num[k] = max_star0( num[k], metric );
+ } else {
+ /* this bit is a zero */
+ den[k] = max_star0( den[k], metric );
+ }
+ mask = mask >> 1;
+ }
+ }
+ for (k=0;k<bps;k++) {
+ bit_likelihood[bps*n+k] = num[k] - den[k];
+ }
+ }
+}
+
int extract_output(char out_char[], int DecodedBits[], int ParityCheckCount[], int max_iter, int CodeLength, int NumberParityBits) {
int i, j;
#ifndef __MPDECODE_CORE__
#define __MPDECODE_CORE__
+#include "comp.h"
+
struct LDPC {
int max_iter;
int dec_type;
double *H_cols;
};
-int run_ldpc_decoder(struct LDPC *ldpc, char out_char[], double input[]);
+int run_ldpc_decoder(struct LDPC *ldpc, char out_char[], double input[], int *parityCheckCount);
void sd_to_llr(double llr[], double sd[], int n);
+void Demod2D(float symbol_likelihood[], COMP r[], COMP S_matrix[], float EsNo, float fading[], int number_symbols);
+void SomapDemod2D(float bit_likelihood[], float symbol_likelihood[]);
+
struct v_node {
int degree;
float initial_value;