// ------------------------------------------------------------------------ // File: viterbi_binary_nsc.c // Date: April 1, 2002 // Description: Viterbi decoder, maximum likelihood decoding. For a // rate-1/n convolutional code. Correlation metric. // // NOTE: The generator polynomials are given in hexadecimal and in // reversed order. For example, the rate-1/2 standard code // has generator polynomials (octal) (g1,g2)=(133,171). Then // // Base 8 Reverse Base 16 // 133 = 1011011 ---> 1101101 = 6d // 171 = 1111001 ---> 1001111 = 4f // // These values can be found in file "trellis_64states.data" // // Also, the order in the file is (g2,g1). That is, the last // generator in the first row, down to the first generator in // the last row. // // With this format, the software implementation of the // algorithm is simplified. // // NOTE: Maximum of 1024 states; max. truncation length = 1024 // // ------------------------------------------------------------------------ // This program is complementary material for the book: // // R.H. Morelos-Zaragoza, The Art of Error Correcting Coding, Wiley, 2002. // // ISBN 0471 49581 6 // // This and other programs are available at http://the-art-of-ecc.com // // You may use this program for academic and personal purposes only. // If this program is used to perform simulations whose results are // published in a journal or book, please refer to the book above. // // The use of this program in a commercial product requires explicit // written permission from the author. The author is not responsible or // liable for damage or loss that may be caused by the use of this program. // // Copyright (c) 2002. Robert H. Morelos-Zaragoza. All rights reserved. // ------------------------------------------------------------------------ #include #include #include #include #include #define MAX_RANDOM LONG_MAX // Use the compiling directive -DSHOW_PROGRESS to see how the decoder // converges to the decoded sequence by monitoring the survivor memory #ifdef SHOW_PROGRESS #define DELTA 1 #endif int k2=1, n2, m2; int NUM_STATES, OUT_SYM, NUM_TRANS; long TRUNC_LENGTH; double RATE; double INIT_SNR, FINAL_SNR, SNR_INC; long NUMSIM; FILE *fp, *fp_ber; int g2[10][10]; unsigned int memory2, output; /* Memory and output */ unsigned int data2; /* Data */ unsigned long seed; /* Seed for random generator */ unsigned int data_symbol[1024]; /* 1-bit data sequence */ long index; /* Index for memory management*/ double transmitted[10]; /* Transmitted signals/branch */ double snr, amp; double received[10]; /* Received signals/branch */ int fflush(); // Data structures used for trellis sections and survivors struct trel { int init; /* initial state */ int data; /* data symbol */ int final; /* final state */ double output[10]; /* output coded symbols (branch label) */ }; struct surv { double metric; /* metric */ int data[1024]; /* estimated data symbols */ int state[1024]; /* state sequence */ }; // A trellis section is an array of branches, indexed by an initial // state and a k_2-bit input data. The values read // are the final state and the output symbols struct trel trellis[1024][100]; /* A survivor is a sequence of states and estimated data, of length equal to TRUNC_LENGTH, together with its corresponding metric. A total of NUM_STATES survivors are needed */ struct surv survivor[1024], surv_temp[1024]; /* Function prototypes */ void encoder2(void); /* Encoder for C_{O2} */ int random_data(void); /* Random data generator */ void transmit(void); /* Encoder & BPSK modulator */ void awgn(void); /* Add AWGN */ void viterbi(void); /* Viterbi decoder */ double comp_metric(double rec, double ref); /* Metric calculator */ void open_files(void); /* Open files for output */ void close_files(void); /* Close files */ main(int argc, char *argv[]) { register int i, j, k; int init, data, final, output; register int error; unsigned long error_count; char name1[40], name2[40]; // Command line processing if (argc != 8) { printf("Usage %s file_input file_output truncation snr_init snr_final snr_inc num_sim\n", argv[0]); exit(0); } sscanf(argv[1],"%s", name1); sscanf(argv[2],"%s", name2); sscanf(argv[3],"%ld", &TRUNC_LENGTH); sscanf(argv[4],"%lf", &INIT_SNR); sscanf(argv[5],"%lf", &FINAL_SNR); sscanf(argv[6],"%lf", &SNR_INC); sscanf(argv[7],"%ld", &NUMSIM); printf("\nSimulation of Viterbi decoding over an AWGN channel\n"); printf("%ld simulations per Eb/No (dB) point\n", NUMSIM); fp_ber = fopen(name2,"w"); /* Open file with trellis data */ if (!(fp = fopen(name1,"r"))) { printf("Error opening file!\n"); exit(1); } fscanf(fp, "%d %d", &n2, &m2); RATE = 1.0 / (double) n2; fscanf(fp, "%d %d %d", &NUM_STATES, &OUT_SYM, &NUM_TRANS); for (j=0; j> 5) & 1 ); } void transmit() { /* Encode and modulate a 1-bit data sequence */ int i; encoder2(); /* */ /* Modulate: {0,1} --> {+1,-1} */ for (i=(OUT_SYM-1); i >=0; i--) if ( (output >> i) & 0x01 ) transmitted[OUT_SYM-1-i] = -1.0; /* if bit = 1 */ else transmitted[OUT_SYM-1-i] = 1.0; /* if bit = 0 */ } void encoder2() { // Binary convolutional encoder, rate 1/n2 register int i, j, result, temp; temp = memory2; output = 0; temp = (temp<<1) ^ data_symbol[index % TRUNC_LENGTH]; for (i=0; i=0; j--) result ^= ( ( temp & g2[i][0] ) >> j ) & 1; output = ( output<<1 ) ^ result; } memory2 = temp ; } void awgn() { /* Add AWGN to transmitted sequence */ double u1,u2,s,noise,randmum; int i; for (i=0; i= 1); noise = u1 * sqrt( (-2.0*log(s))/s ); received[i] = transmitted[i] + noise/amp; } } void viterbi() { double aux_metric, surv_metric[NUM_STATES]; register int i,j,k; for (i=0; i=0; k--) aux_metric += comp_metric(received[k],trellis[i][j].output[k]); aux_metric += survivor[i].metric; /* compare with survivor metric at final state */ /* We compare CORRELATIONS */ if ( aux_metric > surv_metric[trellis[i][j].final] ) { /* Good candidate found */ surv_metric[trellis[i][j].final] = aux_metric; /* Update data and state paths */ for (k=0; k