/* * File: tc-8psk-sect.c * Date: January 8, 1998 * Description: Suboptimal trellis decoder using sector information. */ // ------------------------------------------------------------------------ // 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 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; char name1[40], name2[40]; FILE *fp; /* Pointer for trellis data file */ #define MAX_RANDOM LONG_MAX /* Maximum value of random() */ long NUM_SECT; //#define DELTA 1000 //#define SHOW_PROGRESS /* Print simulation progress, */ FILE *fp; /* Pointer for trellis data file */ // unsigned int g2[n2][k2] = { /* rate-1/2 memory=6 */ // 0x4f, /* REVERSE ORDER */ // 0x6d }; /* */ unsigned int g2[10][10]; unsigned int memory2, output; /* Memory,output transmit encoder */ unsigned int memory, output2; /* Memory,output receive encoder */ unsigned int data2; /* Data */ unsigned long seed; /* Seed for random generator */ unsigned int data_symbol[1024]; /* 1-bit data sequence */ unsigned int data_symbol2[1024]; /* 1-bit data sequence */ unsigned long indxx; /* Simulation index */ double psk_I[8], psk_Q[8]; /* Coordinated of 8-PSK signals */ int transmitted; /* index of transmitted signal */ double transmitted_I; /* Transmitted signals/branch */ double transmitted_Q; /* Transmitted signals/branch */ int reconstructed; /* Decoded coset index */ int estimate_data2; /* Estimate of uncoded info. bit */ double snr, amp; double received_I; /* Received signals/branch */ double received_Q; /* Received signals/branch */ double received_angle; double angle_inc; int sector; int buffer_sector[1024]; double branch_metric[512][8]; /* int fflush(); /* */ /* Data structures used for trellis sections and survivors */ struct trel { int init; /* initial state */ int data; /* data symbol */ int final; /* final state */ int output; /* index of output coded symbols */ }; 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 k2-bit input data. The values that can be read are the final state and the index of the output symbols */ struct trel trellis[1024][64]; /* 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 in transmitter */ void encoder(void); /* Encoder in receiver */ int random_data(void); /* Random data generator */ void transmit(void); /* Encoder & BPSK modulator */ void awgn(void); /* AWGN generator */ void find_sect(void); /* Cartesian to polar conversion */ void viterbi(void); /* Viterbi decoder */ void re_encode(void); /* Reencoder of decoded information bit */ void sector_table(); /* Construct branch metric look-up table */ 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; FILE *fp_ber; /* Pointer for overall BER data file */ double RATE; double ii, reference_I[512], reference_Q[512]; // Command line processing if (argc != 10) { printf("Usage %s file_input file_output NUM_SECT truncation snr_init snr_final snr_inc num_sim seed\n", argv[0]); exit(0); } sscanf(argv[1],"%s", name1); sscanf(argv[2],"%s", name2); sscanf(argv[3],"%ld", &NUM_SECT); sscanf(argv[4],"%ld", &TRUNC_LENGTH); sscanf(argv[5],"%lf", &INIT_SNR); sscanf(argv[6],"%lf", &FINAL_SNR); sscanf(argv[7],"%lf", &SNR_INC); sscanf(argv[8],"%ld", &NUMSIM); sscanf(argv[9],"%ld", &seed); printf("\nSimulation of TCM decoding with 8-PSK modulation 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 = (2.0 / (double) n2)*3.0; // 2 bits per symbol if encoder is rate 1/2 fscanf(fp, "%d %d %d", &NUM_STATES, &OUT_SYM, &NUM_TRANS); for (j=0; j>1) & 1 ); /* */ #ifdef PRINT printf("Transmitted data sequence:\n"); printf("%2d %x ",(indxx % TRUNC_LENGTH), data_symbol[indxx % TRUNC_LENGTH]); for (i=0; i NUM_SECT/2) estimate_data2 = 1; #else if ( ( pow((cos(buffer_sector[indxx%TRUNC_LENGTH]*angle_inc) - psk_I[reconstructed]),2.0) + pow((sin(buffer_sector[indxx%TRUNC_LENGTH]*angle_inc) - psk_Q[reconstructed]),2.0)) > ( pow((cos(buffer_sector[indxx%TRUNC_LENGTH]*angle_inc) - psk_I[reconstructed+4]),2.0) + pow((sin(buffer_sector[indxx%TRUNC_LENGTH]*angle_inc) - psk_Q[reconstructed+4]),2.0)) ) estimate_data2 = 1; #endif #ifdef ABS estimate_data2 = 0; if ( ( fabs(cos(buffer_sector[indxx%TRUNC_LENGTH]*angle_inc) - psk_I[reconstructed]) + fabs(sin(buffer_sector[indxx%TRUNC_LENGTH]*angle_inc) - psk_Q[reconstructed])) > ( fabs(cos(buffer_sector[indxx%TRUNC_LENGTH]*angle_inc) - psk_I[reconstructed+4]) + fabs(sin(buffer_sector[indxx%TRUNC_LENGTH]*angle_inc) - psk_Q[reconstructed+4])) ) estimate_data2 = 1; #endif #ifdef PRINT printf("Sector buffer:\n"); for (i=0; i> 5) & 3 ); } void encoder2() { /* * --------------------------------------------------------------------- * Conventional convolutional encoder, rate 1/n2 (fixed k_2=1) * --------------------------------------------------------------------- */ register int i, j, result, temp; temp = memory2; output = 0; temp = (temp<<1) ^ data_symbol[indxx % TRUNC_LENGTH]; for (i=0; i=0; j--) result ^= ( ( temp & g2[i][0] ) >> j ) & 1; output = ( output<<1 ) ^ result; } memory2 = temp ; } void encoder() { /* * --------------------------------------------------------------------- * Conventional convolutional encoder, rate 1/n2 (fixed k_2=1) * --------------------------------------------------------------------- */ register int i, j, result, temp; temp = memory; output2 = 0; temp = (temp<<1) ^ survivor[0].data[indxx % TRUNC_LENGTH]; for (i=0; i=0; j--) result ^= ( ( temp & g2[i][0] ) >> j ) & 1; output2 = ( output2<<1 ) ^ result; } memory = temp ; } void transmit() { /* * --------------------------------------------------------------------- * Encode and modulate a 1-bit data sequence * --------------------------------------------------------------------- */ int i; encoder2(); /* */ #ifdef DEB printf("memory2 = %x\n", memory2); #endif transmitted = output + 4*data_symbol2[indxx % TRUNC_LENGTH]; } void re_encode() { /* Re-encode decoded information bit to obtain coset index */ encoder(); reconstructed = output2; } void awgn() { /* * --------------------------------------------------------------------- * Add AWGN to transmitted sequence * --------------------------------------------------------------------- */ double u1,u2,s,noise,randmum; int i; #ifdef PRINT printf("Received = "); #endif do { randmum = (double)(random())/MAX_RANDOM; u1 = randmum*2.0 - 1.0; randmum = (double)(random())/MAX_RANDOM; u2 = randmum*2.0 - 1.0; s = u1*u1 + u2*u2; } while( s >= 1); noise = u1 * sqrt( (-2.0*log(s))/s )/amp; #ifdef NO_NOISE noise = 0.0; #endif received_I = psk_I[transmitted] + noise; do { randmum = (double)(random())/MAX_RANDOM; u1 = randmum*2.0 - 1.0; randmum = (double)(random())/MAX_RANDOM; u2 = randmum*2.0 - 1.0; s = u1*u1 + u2*u2; } while( s >= 1); noise = u1 * sqrt( (-2.0*log(s))/s )/amp; #ifdef NO_NOISE noise = 0.0; #endif received_Q = psk_Q[transmitted] + noise; #ifdef PRINT printf("%4.2lf %4.2lf ", received_I, received_Q); #endif #ifdef PRINT printf("\n"); #endif } void find_sect() { /* --------------------------------------------------------------------- * Determine the sector in which the received point lies * --------------------------------------------------------------------- */ register int i; double ii, phase1, phase2; received_angle = atan2(received_Q, received_I); #ifdef SECTOR printf("atan2(%lf,%lf)=%lf \t",received_I, received_Q, (180.0/3.0)*received_angle); #endif for (i=0; i M_PI ) phase1 = phase1 - 2.0*M_PI; phase2 = (ii+1.0)*angle_inc; if ( phase2 > M_PI ) phase2 = phase2 - 2.0*M_PI; if ( (received_angle > phase1) && (received_angle < phase2) ) sector = i; } #ifdef SECTOR printf("--> \tsector = %d\n", sector); #endif } void viterbi() { /* * --------------------------------------------------------------------- * Viterbi decoder * --------------------------------------------------------------------- */ double aux_metric, surv_metric[NUM_STATES]; register int i,j,k; for (i=0; i ",i); for (k=0; k