www.pudn.com > opengpssim.zip > correlator.c
/* ************************************************************************ * * * GPS Simulation * * * * -------------------------------------------------------------------- * * * * Module: correlator.cpp * * * * Version: 0.1 * * * * Date: 02.03.02 * * * * Author: G. Beyerle * * * * -------------------------------------------------------------------- * * * * Copyright (C) 2002-2006 Georg Beyerle * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software * * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * * * -------------------------------------------------------------------- * * * * The files 'gpsfuncs.cpp', 'gpsrcvr.cpp' and 'gp2021.cpp' are modi- * * fied versions of the files with the same name from Clifford Kelley's * * OpenSourceGPS distribution. The unmodified files can be obtained * * from http://www.home.earthlink.net/~cwkelley * * * * -------------------------------------------------------------------- * * * * Software correlator (based on GP2021 chip) * * * ************************************************************************ */ /* ******************************* changes ******************************** dd.mm.yy - ************************************************************************ */ /* ******************************** to do ********************************* 02-06-02 : check chan[ch].prn <-> Regs[].prn ************************************************************************ */ /* -------------------------------- define -------------------------------- */ #undef OGSDEBUG /* ------------------------------- includes ------------------------------- */ #include#include #include #include #ifdef __TURBOC__ # include #endif #include #include "ogsdefine.h" #include "ogsstructs.h" #include "ogsextern.h" #include "ogsprototypes.h" #include "ogslibrary.h" /* ------------------------------- defines -------------------------------- */ /* ------------------------------- globals -------------------------------- */ static int Carrier_DCO_I[] = {-1,1,2, 2, 1,-1,-2,-2}; static int Carrier_DCO_Q[] = { 2,2,1,-1,-2,-2,-1, 1}; // somewhat better resolution ... //int Carrier_DCO_I[] = {25,71,106,126,126,106, 71, 25,-25,-71,-106,-126,-126,-106,-71,-25} // 16-phase 256 level //int Carrier_DCO_Q[] = {126,106, 71, 25,-25,-71,-106,-126,-126,-106,-71,-25,25,71,106,126} // 16-phase 256 level typedef struct { int active, inhibited; int satcntl, sourcesel, preset_update, // hi: preset, lo: update track_sel; // 0:early, 1:late, 2:dither, 3:early-minus-late int prn; // satellite id long i_prompt, // accumulation registers i_track, q_prompt, q_track; unsigned int samples_per_sum; unsigned long sample_counter; long carrier_cycle_counter; // # of positive going zero crossings of i_lo long code_phase_counter, code_slew_counter; // slew code_DCO by XXX half chips, 0,...,2047 long carrier_dco_incr, // 26 bit, frq res. is 42.57475 mHz carrier_dco_phase, // carrier cycle fraction / phase in 2pi/1024 increments code_dco_phase, code_dco_incr; int epoch_counter, epoch_1ms, // 0,...,19; 1 msec (1 C/A) code epoch epoch_20ms; // 0,...,49; 20 msec (20 C/A, 1 data bit) epoch } REGS; static REGS Regs[NOFCHAN]; typedef struct cntlregs { int test_control, system_setup, reset_control; } CNTLREGS; CNTLREGS CntlRegs; typedef struct accum_stat_a { int accum_int, new_accum_data; } ACCUM_STAT_A; ACCUM_STAT_A Accum_Status_A; typedef struct accum_stat_b { int tic, meas_int, missed_accum; } ACCUM_STAT_B; ACCUM_STAT_B Accum_Status_B; typedef struct accum_stat_c { int early_late; } ACCUM_STAT_C; ACCUM_STAT_C Accum_Status_C; typedef struct meas_stat_a { int tic, meas_int, missed_meas_data; } MEAS_STAT_A; MEAS_STAT_A Meas_Status_A; static long Carrier_Cycle[NOFCHAN], Code_Cycle[NOFCHAN]; static int HalfChip_Counter[NOFCHAN]; static long Tmp_I_Prompt[NOFCHAN], Tmp_I_Track[NOFCHAN], Tmp_Q_Prompt[NOFCHAN], Tmp_Q_Track[NOFCHAN]; // ------------ debugging ------------- //unsigned int Samples_Per_Sum[NOFCHAN]; //unsigned long Sample_Counter_Start[NOFCHAN]; //unsigned long Sample_Counter_End[NOFCHAN]; // ------------ debugging ------------- static double Carrier_DCO_Cycle[NOFCHAN]; extern char *Buffer; // data input buffer extern long BufEnd; // last position in data input buffer /* -------------------------- prototypes (global) ------------------------- */ void process_data( int); void update_readbuffer( void); /* ------------------------------ procedures ------------------------------ */ // // interface to software GP2021 // int g2load_to_prn( int g2_load) { int k, ret = 0; int g2_load_list[] = { 0x3f6,0x3ec,0x3d8,0x3b0, 0x4b, 0x96,0x2cb,0x196,0x32c,0x3ba, 0x374,0x1d0,0x3a0,0x340,0x280,0x100,0x113,0x226, 0x4c, 0x98, 0x130,0x260,0x267,0x338,0x270, 0xe0,0x1c0,0x380,0x22b, 0x56, 0xac, 0x158}; for ( k=0; k<32; k++) { if ( g2_load == g2_load_list[k]) { ret = k+1; break; } } if (!ret) { printf( "g2load_to_prn: unknown G2_LOAD 0x%x\n", g2_load); exit(-1); } return (ret); } void ch_carrier( char ch, long freq) { Regs[ch].carrier_dco_incr = freq; // gotoxy(1,24); // printf("ch_carrier: carrier_dco_incr = %x (nominal: 0x1f7b1b9)", freq); // getchar(); return; } void ch_code( char ch, long freq) { Regs[ch].code_dco_incr = freq; return; } // // write to GP2021 registers // void to_gps( int adr, int data) { int n, mask; long ldata; int g2_load; switch( adr) { case 0x0: case 0x8: case 0x10: case 0x18: case 0x20: case 0x28: case 0x30: case 0x38: case 0x40: case 0x48: case 0x50: case 0x58: n = (adr - 0x0) / 8; Regs[n].satcntl = data; Regs[n].sourcesel = (data & (0x1 << 10)) != 0; Regs[n].preset_update = (data & (0x1 << 12)) != 0; // hi: preset, lo: update Regs[n].track_sel = (data & (0x3 << 13)) >> 13; // 0:early, 1:late, 2:dither, 3:early-minus-late g2_load = data & 0x3ff; Regs[n].prn = g2load_to_prn( g2_load); // printf( "to_gps: Regs[%d].track_sel = %d\n", n, Regs[n].track_sel); // getchar(); break; // write only if test mode is selected // case 0x1, 0x9, 0x11, 0x19, 0x21, 0x29, 0x31, 0x39, 0x41, 0x49, 0x51, 0x59: // n = (adr - 0x1) / 8; // Regs[n].code_phase_counter = data; // break; case 0x3: case 0xb: case 0x13: case 0x1b: case 0x23: case 0x2b: case 0x33: case 0x3b: case 0x43: case 0x4b: case 0x53: case 0x5b: n = (adr - 0x3) / 8; ldata = data; Regs[n].carrier_dco_incr |= ((ldata << 16) & 0xf0000); break; case 0x4: case 0xc: case 0x14: case 0x1c: case 0x24: case 0x2c: case 0x34: case 0x3c: case 0x44: case 0x4c: case 0x54: case 0x5c: n = (adr - 0x4) / 8; Regs[n].carrier_dco_incr |= data; break; case 0x5: case 0xd: case 0x15: case 0x1d: case 0x25: case 0x2d: case 0x35: case 0x3d: case 0x45: case 0x4d: case 0x55: case 0x5d: n = (adr - 0x5) / 8; ldata = data; Regs[n].code_dco_incr |= ((ldata << 16) & 0xf0000); break; case 0x6: case 0xe: case 0x16: case 0x1e: case 0x26: case 0x2e: case 0x36: case 0x3e: case 0x46: case 0x4e: case 0x56: case 0x5e: n = (adr - 0x6) / 8; Regs[n].code_dco_incr |= data; break; case 0x7: case 0xf: case 0x17: case 0x1f: case 0x27: case 0x2f: case 0x37: case 0x3f: case 0x47: case 0x4f: case 0x57: case 0x5f: n = (adr - 0x7) / 8; Regs[n].epoch_1ms = data & 0x1f; // 0,...,19 Regs[n].epoch_20ms = (data >> 8) & 0x3f; // 0,...,49 break; case 0x7c: CntlRegs.test_control = data; printf( "to_gps: write %d (0x%x) to test_control\n", data, data); break; case 0x7e: CntlRegs.system_setup = data; printf( "to_gps: write %d (0x%x) to system_setup\n", data, data); break; case 0x7f: CntlRegs.reset_control = data; // printf( "to_gps: write %d (0x%x) to reset_control\n", data, data); break; case 0x80: // latch status of status flags into ACCUM_STATUS_x registers // printf( "to_gps: write %d (0x%x) to STATUS (0x80)\n", data, data); // getchar(); break; case 0x84: case 0x88: case 0x8c: case 0x90: case 0x94: case 0x98: case 0x9c: case 0xa0: case 0xa4: case 0xa8: case 0xac: case 0xb0: // code slew counter n = (adr - 0x84) / 4; // printf( "to_gps: write %d (0x%x) to CODE_SLEW_COUNTER (0x%x), channel %d\n", data, data, adr, n); Regs[n].code_slew_counter = data; break; case 0x85: case 0x89: case 0x8d: case 0x91: case 0x95: case 0x99: case 0x9d: case 0xa1: case 0xa5: case 0xa9: case 0xad: case 0xb1: // accumulator reset n = (adr - 0x85) / 4; // printf( "to_gps: write %d (0x%x) to ACCUM_RESET (0x%x), channel %d\n", data, data, adr, n); mask = ~(0x1 << n); Accum_Status_A.new_accum_data &= mask; // clear bit for that channel Accum_Status_B.missed_accum &= mask; Accum_Status_C.early_late &= mask; break; case 0xf0: // printf( "to_gps: write %d (0x%x) to IO_CONFIG (0xf0)\n", data, data); break; default: printf( "to_gps: attempt to write data %d (0x%x) to address %d (0x%x)\n", data, data, adr, adr); exit(-1); } return; } // // read from GP2021 registers // int from_gps( int adr) { int n, ret; switch( adr) { case 0x0: case 0x8: case 0x10: case 0x18: case 0x20: case 0x28: case 0x30: case 0x38: case 0x40: case 0x48: case 0x50: case 0x58: n = (adr - 0x0) / 8; ret = Regs[n].code_slew_counter; break; case 0x1: case 0x9: case 0x11: case 0x19: case 0x21: case 0x29: case 0x31: case 0x39: case 0x41: case 0x49: case 0x51: case 0x59: n = (adr - 0x1) / 8; ret = Regs[n].code_phase_counter; break; case 0x2: case 0xa: case 0x12: case 0x1a: case 0x22: case 0x2a: case 0x32: case 0x3a: case 0x42: case 0x4a: case 0x52: case 0x5a: n = (adr - 0x2) / 8; ret = Regs[n].carrier_cycle_counter & 0xffff; break; case 0x3: case 0xb: case 0x13: case 0x1b: case 0x23: case 0x2b: case 0x33: case 0x3b: case 0x43: case 0x4b: case 0x53: case 0x5b: n = (adr - 0x3) / 8; ret = Regs[n].carrier_dco_phase; break; case 0x4: case 0xc: case 0x14: case 0x1c: case 0x24: case 0x2c: case 0x34: case 0x3c: case 0x44: case 0x4c: case 0x54: case 0x5c: n = (adr - 0x4) / 8; ret = Regs[n].epoch_counter; break; case 0x5: case 0xd: case 0x15: case 0x1d: case 0x25: case 0x2d: case 0x35: case 0x3d: case 0x45: case 0x4d: case 0x55: case 0x5d: n = (adr - 0x5) / 8; ret = Regs[n].code_dco_phase; break; case 0x6: case 0xe: case 0x16: case 0x1e: case 0x26: case 0x2e: case 0x36: case 0x3e: case 0x46: case 0x4e: case 0x56: case 0x5e: n = (adr - 0x6) / 8; ret = (Regs[n].carrier_cycle_counter >> 16) & 0xf; break; // case 0x7: case 0xf: case 0x17: case 0x1f: case 0x27: case 0x2f: // case 0x37: case 0x3f: case 0x47: case 0x4f: case 0x57: case 0x5f: // n = (adr - 0x7) / 8; // break; // case 0x80: ret = Accum_Status_C.early_late; break; case 0x81: ret = (Meas_Status_A.tic << 13) | (Meas_Status_A.meas_int << 12) | Meas_Status_A.missed_meas_data; break; case 0x82: ret = (Accum_Status_A.accum_int << 15) | Accum_Status_A.new_accum_data; break; case 0x83: ret = (Accum_Status_B.tic << 13) | (Accum_Status_B.meas_int << 12) | Accum_Status_B.missed_accum; break; case 0x84: case 0x88: case 0x8c: case 0x90: case 0x94: case 0x98: case 0x9c: case 0xa0: case 0xa4: case 0xa8: case 0xac: case 0xb0: n = (adr - 0x84) / 4; ret = Regs[n].i_track; // if ( n == 0) // printf("ch = %d, Id = %d\n", n, ret); break; case 0x85: case 0x89: case 0x8d: case 0x91: case 0x95: case 0x99: case 0x9d: case 0xa1: case 0xa5: case 0xa9: case 0xad: case 0xb1: n = (adr - 0x85) / 4; ret = Regs[n].q_track; // if ( n == 0) // printf("ch = %d, Qd = %d\n", n, ret); break; case 0x86: case 0x8a: case 0x8e: case 0x92: case 0x96: case 0x9a: case 0x9e: case 0xa2: case 0xa6: case 0xaa: case 0xae: case 0xb2: n = (adr - 0x86) / 4; ret = Regs[n].i_prompt; // if ( n == 0) // printf("ch = %d, Ip = %d\n", n, ret); break; case 0x87: case 0x8b: case 0x8f: case 0x93: case 0x97: case 0x9b: case 0x9f: case 0xa3: case 0xa7: case 0xab: case 0xaf: case 0xb3: n = (adr - 0x87) / 4; ret = Regs[n].q_prompt; Accum_Status_A.new_accum_data &= ~(0x1 << n); // q_prompt should be read last, clears status bit break; default: printf( "from_gps: attempt to read from address %d (%x)\n", adr, adr); exit(-1); } return ret; } // // init software correlator // void init_software_correlator( void) { int i; long l; FILE *Fp; // activate channels for ( i=0; i > 22; // bits 22-31 cidx = carrier_counter >> 28; // bits 28-31 // printf("cidx = %d, didx = %d\n", cidx, didx); // getchar(); // assert( didx >= 0 && didx < 1023); // sgn = nav[nidx] * CACode[prn][didx] * Carrier_DCO_I[cidx]; // // values: -2,-1,1,2 // sgn = tmpnav * CACode[prn][didx] * Carrier_DCO_I[cidx]; // // Noise: Gaussian white noise, integer, zero mean, stddev 1000 // // sgn += Noise[ridx++] / 50; // stddev reduced 20 // ridx = ridx % NOISELEN; // sgn /= 4; // stddev reduced 5 if (sgn > 6) sgn = 6; if (sgn < -6) sgn = -6; // // increment by one time step // carrier_counter += carrier_counter_step; code_counter += code_counter_step; if ( carrier_counter & (0x1L << 31)) // if bit 31 set -> one cycle is completed carrier_counter &= 0x7fffffff; // clear bit 31 // code sequence finished? if ( (code_counter >> 22) == 1023) { code_counter &= 0x3fffff; // clear bits 22-31 epoch_counter += 1; // 1 msec } // message bit corresponds to 20 msec if ( epoch_counter == 20) { nidx += 1; epoch_counter = 0; } return sgn; } #ifdef OGSDEBUG int dbg_buf1[6000], dbg_buf2[6000], dbg_buf3[6000], dbg_buf4[6000]; #endif extern FILE *FpIn; // // run software correlator // int run_software_correlator( void) { int ch, j, loop = 1, res = 1, sgn, i_lo, q_lo, ca_prompt, ca_earlylate, didx, didxlate, didxearly, cidx; static long bufpos = 0L; static int sgnidx = -1, SavBuf; static int dump[NOFCHAN] = {0,0,0,0,0,0,0,0,0,0,0,0}; // // loop 'til next dump // time step is sampling frequency (5.714 MHz <-> 175 nsec) // while ( loop) { if ( sgnidx < 0) { SavBuf = Buffer[bufpos++]; sgnidx = 3; } if ( bufpos >= BufEnd) { printf("fill data buffer... \n"); update_readbuffer(); bufpos = 0L; } if ( !FpIn) return (0); // extract 2 bits from 32 bit long and map from [0,1,2,3] to [-3,-1,1,3] sgn = ((SavBuf >> 2*sgnidx) & 0x3) * 2 - 3; sgnidx -= 1; // dbg_nof_smpl += 1; #ifdef OGSDEBUG dbg_buf1[dbg_bufidx] = sgn; #endif // BUFFERPTR += 1; // global variable - debug only // if ( bufpos >= BufferLen) // return (0); // // loop over all 12 channels // for ( ch=0; ch dump! HalfChip_Counter[ch] = 0; #ifdef OGSDEBUG FILE* dbgfp = fopen( "c:/tmp/testdata.dat","w"); if ( !dbgfp) { printf( "ru_vrt_cr: error opening data file c:/tmp/testdata.dat\n"); exit(-1); } fwrite( &dbg_bufidx, sizeof( int), 1, dbgfp); fwrite( dbg_buf1, sizeof( int), dbg_bufidx, dbgfp); fwrite( &dbg_bufidx, sizeof( int), 1, dbgfp); fwrite( dbg_buf2, sizeof( int), dbg_bufidx, dbgfp); fwrite( &dbg_bufidx, sizeof( int), 1, dbgfp); fwrite( dbg_buf3, sizeof( int), dbg_bufidx, dbgfp); fwrite( &dbg_bufidx, sizeof( int), 1, dbgfp); fwrite( dbg_buf4, sizeof( int), dbg_bufidx, dbgfp); fclose( dbgfp); printf( "file closed!\n"); dbg_bufidx = 0; getchar(); #endif } // --- if ( HalfChip_Counter[ch] == 2046) --- // // index in sin/cos look-up table (8-phase) // cidx = (Carrier_Cycle[ch] >> 24) & 0x7; didx = HalfChip_Counter[ch]; // now 0,...,2046 didxearly = didx + 2046 + 1; // 1/2 chip (avoid neg numbers) didxlate = didx + 2046 - 1; didx = (didx % 2046) / 2; didxearly = (didxearly % 2046) / 2; didxlate = (didxlate % 2046) / 2; // code // ca_prompt = CACode[prn][didx]; // i=0,...,1022 ca_prompt = CACode[chan[ch].prn][didx]; // i=0,...,1022 #ifdef OGSDEBUG dbg_buf2[dbg_bufidx] = ca_prompt; #endif // // code transition from index 1022 to 0 -> DUMP event // actually DUMP event occurs only if Regs[ch].code_slew_counter != 2047; // we ignore that // if ( Accum_Status_C.early_late & (0x1 << ch)) { // ca_earlylate = CACode[prn][didxlate]; ca_earlylate = CACode[chan[ch].prn][didxlate]; printf( "late track!\n"); getchar(); } else { // ca_earlylate = CACode[prn][didxearly]; ca_earlylate = CACode[chan[ch].prn][didxearly]; // printf( "early track!\n"); // getchar(); } // // dump event! // if ( dump[ch]) { dump[ch] = 0; // adjust code cycle // Code_DCO_Cycle[ch] += Regs[ch].code_slew_counter / 2046; // 1 cycle = 2046 half chips HalfChip_Counter[ch] += Regs[ch].code_slew_counter; // value valid just for one DUMP period Regs[ch].code_slew_counter = 0; // dump sum to accumulator registers ... Regs[ch].i_prompt = Tmp_I_Prompt[ch]; Regs[ch].i_track = Tmp_I_Track[ch]; Regs[ch].q_prompt = Tmp_Q_Prompt[ch]; Regs[ch].q_track = Tmp_Q_Track[ch]; // --------- debugging ----- // Regs[ch].samples_per_sum = Samples_Per_Sum[ch]; // Sample_Counter_Start[ch] = Sample_Counter_End[ch]+1; // Sample_Counter_End[ch] += Samples_Per_Sum[ch]; // Regs[ch].sample_counter = Sample_Counter_End[ch]; // --------- debugging ----- // ... and clear Tmp_I_Prompt[ch] = 0; Tmp_I_Track[ch] = 0; Tmp_Q_Prompt[ch] = 0; Tmp_Q_Track[ch] = 0; // --------- debugging ----- // Samples_Per_Sum[ch] = 0; // --------- debugging ----- // new accumulator data available Accum_Status_A.new_accum_data |= (0x1 << ch); Accum_Status_A.accum_int = 1; loop = 0; } // --- if ( dump[ch]) --- Regs[ch].carrier_dco_phase = (long)( Carrier_DCO_Cycle[ch] * 1024); // resolution is 1/1024 cycles i_lo = Carrier_DCO_I[cidx]; q_lo = Carrier_DCO_Q[cidx]; #ifdef OGSDEBUG dbg_buf3[dbg_bufidx] = i_lo; dbg_buf4[dbg_bufidx] = q_lo; dbg_bufidx += 1; #endif // values // sgn : +/-1, +/-3 // i_lo,q_lo : +/-1, +/-2 // ca_prompt : +/-1 // ca_earlylate : +/-1 or +/-2, 0 // product : +/-1, +/-2, +/-3, +/-6 Tmp_I_Prompt[ch] += sgn * i_lo * ca_prompt; Tmp_I_Track[ch] += sgn * i_lo * ca_earlylate; Tmp_Q_Prompt[ch] += sgn * q_lo * ca_prompt; Tmp_Q_Track[ch] += sgn * q_lo * ca_earlylate; // --- debugging --- // Samples_Per_Sum[ch] += 1; // --- debugging --- } // --- if ( Regs[ch].active) --- } // --- for ( ch=0; ch