www.pudn.com > opengpssim.zip > ogsxmit.c


/* ************************************************************************ 
   *                                                                      *
   *                          GPS Simulation                              *
   *                                                                      *
   * -------------------------------------------------------------------- *
   *                                                                      *
   *    Module:   ogsxmit.cpp                                             *
   *                                                                      *
   *   Version:   0.1                                                     *
   *                                                                      *
   *      Date:   17.02.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                         *
   *                                                                      *
   * -------------------------------------------------------------------- *
   *                                                                      *
   *                       GPS signal transmitter                         *
   *                                                                      *
   ************************************************************************ */

/* ******************************* changes ********************************

   dd.mm.yy -

   ************************************************************************ */

// to do:
// - fill struct iono_data und struct UTC_data   / 17.2.02
// - parity bits
// - check calc of parity in parity_check()

/* ------------------------------- includes ------------------------------- */

#include 
#include 
#include 
#include 
#include 
#include 

#include "ogsdefine.h"
#include "ogsstructs.h"
#include "ogsprototypes.h"
#include "ogslibrary.h"
#include "boxmuller.h"

#define MAIN
#include "ogsextern.h"
#undef MAIN

/* ------------------------------- defines -------------------------------- */

//#define XMTRBUFLEN 500000
#define XMTRBUFLEN 150000
//#define XMTRBUFLEN 1000

/* ------------------------------- structs -------------------------------- */

typedef struct
{
   int    active,
          inhibited; 
   int    prn;                    // satellite id
   long   carrier_cycle_counter;  // # of positive going zero crossings of i_lo
   long   code_phase_counter;
   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
} XMTRINFO;

XMTRINFO XmtrInfo[NOFSAT+1];

/* ------------------------------- globals -------------------------------- */

//static double const SampleFrq = 5.714e6;

//static double const CarrierFrq = 1.405396825e6;
//static double const CodeFrq    = 1.023e6;

static double SampleTime = 0;

char *NavFrame[NOFSAT+1];

static int HalfChip_Counter[NOFSAT+1];

//  phase counters
static unsigned long Carrier_Cycle[NOFSAT+1],
                     Code_Cycle[NOFSAT+1],
                     CACode_Counter[NOFSAT+1];   // 0,...,20*1500-1

static double Carrier_DCO_Cycle[NOFSAT+1];

//static int Carrier_DCO_I[] = {-1,1,2, 2, 1,-1,-2,-2};
static int Carrier_DCO_I[] = {2, 2, 1, -1, -2, -2, -1, 1};

static unsigned char XmtrBuf[XMTRBUFLEN];
static char *NavBit[NOFSAT+1];

static float QuantThresh,     // quantization theshold
             Noise_dB,        // noise added to signal
             Noise_Ampl,      // noise added to signal
             MaxTime;

static float Latitude, Longitude;  // receiver location

char ProgramName[] = "ogsxmit";
static char Version[] = "0.1.1";

extern char *OutputFileName;
extern char *NavFilePattern;
extern int OverWrite;
extern long CounterStartValue;

/* -------------------------- prototypen (global) ------------------------- */

void getargs( int argc, char *argv[]);

/* ------------------------------ procedures ------------------------------ */

void usage( void)
{
  printf( "usage: %s [options]\n", ProgramName);
  printf( "version %s (compiled %s %s) \n", Version, __DATE__, __TIME__);
  printf( " options:\n");
  printf( "   -h        : print this message                           \n");
  printf( "   -v        : verbose                                      \n");
  printf( "   -f        : overwrite existing files                     \n");
  printf( "   -n   : navigation file pattern                 \n");
  printf( "   -o  : write data to  'data/'  ['ogsraw.dat'] \n");
  exit(0);
}

void check_options( void)
{
  if ( !NavFilePattern)
  {
    printf( "No navigation file selected (option -n).");
    exit(-1);
  }
  return;
}


//
//  read parameters from file
//  adapted from read_rcvr_par()  (c) Clifford Kelley
//
static void read_xmit_par( void)
{

  char infile[] = "xmit_par.dat", *tmpstr;
  FILE *in;

  tmpstr = conmalloc( strlen( OGSBinDir) + strlen( infile) + 1);
  strcpy( tmpstr, OGSBinDir);
  strcat( tmpstr, infile);

  if (( in = fopen( tmpstr, "rt")) == NULL)
  {
    printf( "Error opening parameter file '%s'.\n", tmpstr);
    perror( NULL);
    exit( 0);
  }
  else
  {

#define SPSIZE 200
    int loop = 1, ret;
    char buf[SPSIZE];
    char sep[] = ":";  /* list of token separators */
    char *token;
             
    printf( "Read parameter from file '%s' ...\n", tmpstr);

    while ( !feof( in) && loop)
    {
      fgets( buf, SPSIZE, in);

      if ( buf[0] == '#')
        continue;

      token = strtok( buf, sep);   // format is   : 

      if ( token)
      {
        ret = read_key_value_pair_float( token, "Quantiz. Threshold", &QuantThresh, sep);

        if ( !ret)
          ret = read_key_value_pair_float( token, "Noise [dB]", &Noise_dB, sep);

        if ( !ret)
          ret = read_key_value_pair_float( token, "Max. Time [sec]", &MaxTime, sep);

        if ( !ret)
          ret = read_key_value_pair_float( token, "latitude [deg]", &Latitude, sep);

        if ( !ret)
          ret = read_key_value_pair_float( token, "longitude [deg]", &Longitude, sep);

        if ( !ret)
        {
          token = strtok( NULL, sep);
          if ( token)
          {
            printf( "unkown keyword >%s< in file %s\n", buf, tmpstr);
            exit( -1);
          }  
        }
      } 
      else
// --- token is NULL ---      
        loop = 0;

    } // --- while ( !feof( in) && loop) ---
  }
  fclose( in);

  if ( Verbose)
  {
    printf( "Finished reading parameter file %s.\n", tmpstr);
    printf( "Press ENTER\n");
    getchar();
  }  

  if ( tmpstr)
    free( tmpstr);

  return;
}

//
//  initialize carrier and code counter increments
//
static void init_struct_xmitter( void)
{
  int i;
  
  for ( i=1; i<=NOFSAT; i++)
  {
    XmtrInfo[i].carrier_dco_incr = 0x1f7b1b9L;      // 33010105 * 42.57475 mHz = 1405396.968 Hz
    XmtrInfo[i].code_dco_incr    = 0x16ea4a8L;      // 24028328 * 42.57475 mHz = 1023000.058 Hz

//  start nav message at bit position CounterStartValue (out of 1500)
    CACode_Counter[i] = 20 * CounterStartValue;
  }  
  return;
}


//
//  calculate GPS C/A signal
//
static int calc_raw_sgn( void)
{
  int i, j, cidx, didx, nidx, prn;
  int sgn = 0;
  int savsgn;
  short int ca_prompt;
  char navbit;
  float sgnflt;
  char d;
//  float tmp, savtmp;

//  nofprn = 0;
  
  for ( prn=1; prn<=NOFSAT; prn++)
  {

    if ( NavBit[prn])
    {

//
//  increment carrier and code cycle counter
//
      Carrier_Cycle[prn] += XmtrInfo[prn].carrier_dco_incr;
      Code_Cycle[prn]    += XmtrInfo[prn].code_dco_incr;

//      printf(" Carrier_Cycle[%d] = %d\n", prn, Carrier_Cycle[prn]);
//      printf(" Code_Cycle[%d]    = %d\n", prn, Code_Cycle[prn]);
        
//
//  carrier DCO: 2^27 = 0x8000000 corresponds to 1 carrier cycle (1.4 MHz)
//
      if ( Carrier_Cycle[prn] & (0x1 << 27))
      {
        Carrier_Cycle[prn] &= ~(0x1f << 27);   // clear top 5 bits
        XmtrInfo[prn].carrier_cycle_counter += 1; 
      }

//
//  code DCO: 2^26 = 0x4000000 corresponds to 1/2 chip (2*1.023 MHz)
//            2^27 = 0x8000000 corresponds to 1 chip (1.023 MHz)
//
      if ( Code_Cycle[prn] & (0x1 << 26))
      {
        Code_Cycle[prn] &= ~(0x3f << 26);   // clear top 6 bits
        HalfChip_Counter[prn] += 1;
      }

      if ( HalfChip_Counter[prn] == 2046)
      {
        HalfChip_Counter[prn] = 0;
        CACode_Counter[prn] += 1;
//        printf("CACode_Counter[%d] = %d\n", prn, CACode_Counter[prn]);
//        getchar();
      }

// wrap around after 1 frame (5 subframes, 5x300 bits)
      CACode_Counter[prn] = CACode_Counter[prn] % (20*NAVMSGLEN);  

//
//  index in sin/cos look-up table (8-phase)
//
      cidx = (Carrier_Cycle[prn] >> 24) & 0x7;

      didx      = HalfChip_Counter[prn];             // now 0,...,2046     
      didx      = (didx % 2046) / 2;

//  C/A code
//      assert( didx >= 0 && didx < 1023);
//      assert( prn >= 1 && prn < 32);

      ca_prompt = CACode[prn][didx];   // didx=0,...,1022

//  for (i=1;i<=32;i++)
//    for (j=0;j<1023;j++)
//    {
//      if ( abs( CACode[i][j]) != 1)
//        printf("CACode[%d][%d] = %d\n", i,j,CACode[i][j]);
//    }    
//  getchar();


//      if (!( ca_prompt == 1 || ca_prompt == -1))
//      {
//        printf( "ca_prompt = %d\n", ca_prompt);
//        printf("CACode[%d][%d] = %d\n", prn,didx,CACode[prn][didx]);
//        getchar();
//      }

//  C/A code
      nidx      = CACode_Counter[prn] / 20;   // 20 C/A periods <-> 1 bit
//      assert( nidx >= 0 && nidx < NAVMSGLEN);
      navbit    = NavBit[prn][nidx%NAVMSGLEN];   // nidx=0,...,1499

//      printf("navbit = %d\n", navbit);

//  resolution is 1/1024 cycles
      XmtrInfo[prn].carrier_dco_phase = (long)( Carrier_DCO_Cycle[prn] * 1024);  

      sgn += Carrier_DCO_I[cidx] * ca_prompt * navbit;     

//      assert( sgn == 0);
//      sgn += Carrier_DCO_I[cidx] * ca_prompt;
      
#if 0
      if ( 0)
      {
        static int ii;
        
        printf( "cidx = %d", cidx);
        printf( " ca = %d", ca_prompt);
        printf( " carcyc = %.4f", (double)(Carrier_Cycle[prn]) / (double)(0x1L<<27)); // 24+3!
        printf( " CACode1 = %d", CACode[prn][ii]);
        printf( " DCO = %d", Carrier_DCO_I[ii%8]);
        printf( " sgn = %d\n", sgn);
        
        if (ii > 20)
          getchar();
        ii += 1;
      }
#endif

//      printf("sgn = %d\n", sgn);
//      printf("Carrier_DCO_I = %d, cidx=%d\n", Carrier_DCO_I[cidx], cidx);
//      printf("ca_prompt = %d, didx = %d\n", ca_prompt, didx);
//      printf("navbit = %d\n", navbit);
//      printf("cidx=%d, didx=%d, nidx = %d\n", cidx, didx, nidx);
//      getchar();
//      nofprn += 1;

    }  // --- if ( NavBit[prn]) ---
  }  // --- for ( prn=1; prn <= NOFSAT; prn++) ---
  
// add white noise  
  if ( Noise_Ampl > 0)
  {

    sgnflt = (float)( sgn) + Noise_Ampl * randn( 0.0, 1.0);

//    printf("sgn=%d, sgnflt=%e (Noise_Ampl=%e)\n", sgn, sgnflt, Noise_Ampl);
//    getchar();  

//    printf( "noise = %e\n", tmp);
//    getchar();
//    printf("sgn = %d, noise = %e, sum = %e \n", sgn, tmp, sgnflt);
//    printf("sizeof( float) = %d \n", sizeof( float));
//    getchar();  

  }  
  else  
    sgnflt = (float)( sgn);

// quantize and map to [0,1,2,3]
  sgn = ( sgnflt >= 0.0) ? 1 : -1;
  if ( fabs( sgnflt) > QuantThresh)
    sgn *= 3;

// map -3,-1,1,3 to 0,1,2,3
  sgn = (sgn+3) / 2; 

  return (sgn);
}

//
//  main function
//
int main( int argc, char *argv[])
{
  int j, nof, sgn, ofs;
  long i, nofwritten;
  unsigned long cntMSB;
//  char outfile[] = "ogsraw.dat";   // default output file name
//       navfilefmt[] = "navmsg-in-%02d.dat",
//       navfile[sizeof(navfilefmt)];      // d <= 2 digits!
  char *outpath, *navpath, *ptr, *navfilefmt, *navfile;
  float t, dt;  // 30 sec <-> 1500 nav bits
  double samplfrq = 40e6 / 7.0;               // sampling frequency
  double nofsamples = 0.0;
  FILE *Fp, *FpNav;

  set_directories( argv[0]);

//  process options
  getargs( argc, argv);

  check_options();

//  if ( OutputFileName)
//    ptr = OutputFileName;
//  else  
//    ptr = outfile;

  outpath = conmalloc( strlen( OGSDataDir) + strlen( OutputFileName) + 1);
  strcpy( outpath, OGSDataDir);
  strcat( outpath, OutputFileName);

//  welcome
  printf("-------------------------------- OpenGPSSim ---------------------------------\n");
  printf("ogsxmit   version %s\n", Version);
  printf("Copyright (C) 2001-2006 G. Beyerle, A. Tabernero, C. Kelley and others.      \n");
  printf("ogsxmit comes with ABSOLUTELY NO WARRANTY; for details see file 'warranty'.\n");
  printf("This is free software, and you are welcome to redistribute it under          \n");
  printf("certain conditions; see file 'copying' for details.                          \n");
  printf("-----------------------------------------------------------------------------\n");

//  initialize
  init_struct_xmitter();

//  read parameter controlling signal transmission
  read_xmit_par();

  if ( Noise_dB > -1000.0)
    Noise_Ampl = pow( 10.0, (double)( Noise_dB)/20.0);
  else
    Noise_Ampl = 0.0;
  
  srand(1);        // initialize random generator
  
// calculate C/A-code and store in global CACode[1,...,NOFSATS][1,..,NOFCHIPS]
  calc_cacode();

  if ( !OverWrite)
  {
    Fp = fopen( outpath, "rb");
    if ( Fp)
    {
      printf("Data file '%s' already exists.\nPlease remove it and try again.\n", 
        outpath);
      exit(0);
    }
  }

  Fp = fopen( outpath, "wb");
  if ( !Fp)
  {
    printf( "error opening file '%s'\n", outpath);
    perror( NULL);
    exit(-1);
  }


//  FILE *TmpFp;
//  TmpFp = fopen( "C:/home/Src/osgpsim/data/osgraw-c-chr.dat", "w");
//  if ( !TmpFp)
//  {
//    perror( NULL);
//    exit(-1);
//  }
//  printf( "*** opened C:/home/Src/osgpsim/data/osgraw-c-chr.dat\n");

  printf( "\nRead navigation data bits from file(s) ...\n");

//  printf( "NavFilePattern = %s\n", NavFilePattern);
//  getchar();

  ptr = strstr( NavFilePattern, "PRN");
  if ( !ptr)
  {
    printf( "Substring 'PRN' not found in %s.\n", NavFilePattern);
    exit(-1);    
  }
  
  ofs = ptr - NavFilePattern; 

  navfilefmt = conmalloc( strlen( NavFilePattern) + 4);
  navfile    = conmalloc( strlen( NavFilePattern) + 4);
  
  strcpy( navfilefmt, NavFilePattern);
  strcpy( navfilefmt + ofs, "%02d");
  strcpy( navfilefmt + ofs + 4, ptr + 3);

//  printf( "navfilefmt = %s\n", navfilefmt);
//  getchar();
  
  navpath = conmalloc( strlen( OGSDataDir) + strlen( navfilefmt) + 1);

  for ( i=1; i<=NOFSAT; i++)
  {

    sprintf( navfile, navfilefmt, i);

    strcpy( navpath, OGSDataDir);
    strcat( navpath, navfile);

    FpNav = fopen( navpath, "rb");
    if ( FpNav)
    {
      printf( " '%s'.\n", navpath);

      NavBit[i] = (char*) malloc( NAVMSGLEN);
      if ( !NavBit[i])
      {
        printf( "malloc() failed in %s at line %d\n", __FILE__, __LINE__);
        exit(-1);
      }

      nof = fread( NavBit[i], sizeof( char), NAVMSGLEN, FpNav);
      if ( nof < NAVMSGLEN)
      {
        printf( "read only %d bytes from file '%s'.\n", nof, navpath);
        exit(-1);
      }
//      else
//        printf( "read %d bytes from file '%s'.\n", nof, navpath);
      
      fclose( FpNav);
      
//  re-write: 0 -> -1, 1 -> 1
      for ( j=0; j 0) ? 1 : -1;
      
    }
  }


  int foundone = 0;

  for ( i=1; i<=NOFSAT; i++)
  {
    if ( NavBit[i])
      foundone = 1;
  }

  if ( !foundone)
  {
    printf("Not a single file found for pattern >%s<.\n", NavFilePattern);
    exit(-1);
  }

//  for (i=1;i<=32;i++)
//    for (j=0;j<1023;j++)
//    {
//      if ( abs( CACode[i][j]) != 1)
//        printf("CACode[%d][%d] = %d\n", i,j,CACode[i][j]);
//    }    

//  TmpFP = fopen( "c:/tmp/testdata.dat", "w");
//  if ( !TmpFP)
//  {
//    printf( "Error opening file 'c:/tmp/testdata.dat'\n");
//    perror( NULL);
//    exit(-1);
//  }

  printf( "\n");
  printf( "construct GPS signal, add noise, quantize\n");
  printf( "and write to file '%s' ...\n", outpath);

//  we store 4 times 2 bit (4 level) signal samples into one byte,
//  fill XmtrBuf[XMTRBUFLEN] and write to file

// 4 samples per byte
  dt = XMTRBUFLEN * 4.0 / samplfrq;

  for ( t=0; t