/* * File: tc-8psk-iq.c * Date: January 8, 1998 * Description: Two-stage decoding of TC-8PSK * * The I and Q components of the received 8-PSK symbols are mapped into * a two-dimensional space with a QPSK constellation whose points represent * cosets of BPSK sets in the original 8-PSK constellation. * */ // ------------------------------------------------------------------------ // 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]; #define MAX_RANDOM LONG_MAX //#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 */ double qpsk_I[4], qpsk_Q[4]; /* Coordinated of 4-PSK signals */ int s[4]; /* Coset-sector look-up table */ 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 */ int sector; double transf_I; /* I-coordinate of sector */ double transf_Q; /* Q-coordinate of sector */ double buffer_I[1024]; double buffer_Q[1024]; int buffer_sector[1024]; /* 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 build_sector_table(void); /* Sector look-up table */ 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 transform(void); /* Find coordinates QPSK sector */ void viterbi(void); /* Viterbi decoder */ void re_encode(void); /* Reencoder of decoded information bit */ void sector_table(void); /* 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, error_count_1, error_count_2; FILE *fp_ber; /* Pointer for overall BER data file */ double ii; // Command line processing if (argc != 9) { printf("Usage %s file_input file_output 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", &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); sscanf(argv[8],"%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 ); /* BIT 2 */ #ifdef PRINT printf("Transmitted data sequence:\n"); printf("%2d %x ",(indxx % TRUNC_LENGTH), data_symbol[indxx % TRUNC_LENGTH]); for (i=0; i>buffer_sector[indxx % TRUNC_LENGTH]) & 0x01; #ifdef PRINT printf("buffer_I:\n"); for (i=0; i> 5) & 0x03 ); } void encoder2() { /* * --------------------------------------------------------------------- * 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() { /* * --------------------------------------------------------------------- * Convolutional encoder, rate 1/n2 (fixed k_2=1) * NOTE: Used in re-encoding coset indexes * --------------------------------------------------------------------- */ 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 2-bit data sequence * --------------------------------------------------------------------- */ int i; /* Encode BIT 1 */ encoder2(); /* Transmitted is an index. BIT 2 determines opposite 8-PSK symbols */ transmitted = output + 4*data_symbol2[indxx % TRUNC_LENGTH]; } void re_encode() { /* * ---------------------------------------------------------------------- * Re-encode information bit (BIT 1) from Viterbi decoder to obtain coset * ---------------------------------------------------------------------- */ 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); printf("\n"); #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 2.0*M_PI-M_PI/8 ) || (received_angle < M_PI/8.0) ) sector = 0; else for (i=1; ( (i<8) && (!flag)); i++) { ii = (double) i; phase1 = (ii*M_PI/4.0) - (M_PI/8.0); phase2 = (ii*M_PI/4.0) + (M_PI/8.0); #ifdef DEBUG printf("phase1, phase2 = %lf %lf\n", (180./M_PI)*phase1,(180./M_PI)*phase2); #endif if ( (received_angle > phase1) && (received_angle <= phase2) ) { flag = 1; sector = i; } } #ifdef SECTOR printf("---\nrec_I, rec_Q = %lf, %lf\nangle = %lf, sector = %d\n", received_I, received_Q, (180./M_PI)*received_angle, sector); #endif } void transform() { double amplitude, phase; amplitude = sqrt (received_I*received_I + received_Q*received_Q); phase = 2.0*atan(received_Q/received_I); transf_I = amplitude * cos(phase); transf_Q = amplitude * sin(phase); #ifdef IQ printf("rec_I, rec_Q = (%lf, %lf) \ntransf_I, transf_Q = (%lf, %lf)\n", received_I,received_Q,transf_I,transf_Q); #endif }