Exemplo n.º 1
0
/// param localReplica the code/carrier that this object is to track
/// param codeSpacing the correlator spacing (in sec) that will be used for
/// the code. This class will quantize this value to the closest number
/// of ticks.
EMLTracker::EMLTracker(CCReplica& localReplica, double codeSpacing) :
    GenericTracker(localReplica),
    ticksPerChip(static_cast<unsigned>(1.0/localReplica.chipsPerTick)),
    eplSpacing(static_cast<unsigned>((codeSpacing / localReplica.tickSize))),pllError(0), pllAlpha(/*0.2*/0.1), pllBeta(/*0.05*/0.025),
    dllError(0), dllAlpha(/*6*/3), dllBeta(/*0.01*/0.005),
    iadCount(0), nav(false), baseGain(1.0/(0.1767*1.404)),
    inSumSq(0), lrSumSq(0),iadThreshold(0.02),
    dllMode(dmFar), pllMode(pmUnlocked), navChange(true), prevNav(true),periodCount(10),prn(0)
{
    early.setDelay(2*eplSpacing);
    prompt.setDelay(eplSpacing);
    late.setDelay(0);

    // Since our 'prompt' code is really a late code we should really advance
    // our local replica by this amount but not have it count as part of our
    // code phase offset.
    correlatorBias = eplSpacing * localReplica.chipsPerTick;
    localReplica.moveCodePhase(correlatorBias);
    localReplica.codePhaseOffset -= correlatorBias;

    // Walk the code by the correlator spacing
    searchSize = eplSpacing * localReplica.tickSize/localReplica.codeChipLen;

    iadCountMax = static_cast<unsigned long>(
                      localReplica.codeGenPtr->getSyncIndex() / localReplica.chipsPerTick);
    iadCountDefault = iadCountMax;
};
Exemplo n.º 2
0
bool RxSim::initialize(int argc, char *argv[]) throw()
{
   using namespace gpstk::StringUtils;

   CommandOptionWithAnyArg
      codeOpt('c', "code",
              "The code/carrier to track. ARG takes the form of "
              "code:carrier:prn:offset:doppler. Code is either c or p. "
              "Carrier is either 1 or 2. Prn is an integer between 1 and 32. "
              "Offset is a number in us, Doppler is a number in Hz. Currently, "
              "only one signal can be specified. For example, to track P code "
              "on L2 for PRN 3, with no initial time or doppler offset, "
              "specify -c p:2:3:0:0"),

      dllAlphaOpt('\0', "dllAlpha",
                  "The gain on the phase update for the code tracker. The "
                  "default is 1e-5 chips/tick"),

      dllBetaOpt('\0', "dllBeta",
                 "The gain on the frequency update for the code tracker. The "
                 "default is 1e-12 chips/tick"),

      pllAlphaOpt('\0', "pllAlpha",
                  "The gain on the phase update for the carrier tracker. The "
                  "default is 0.4 cycles/tick"),

      pllBetaOpt('\0', "pllBeta",
                 "The gain on the frequency update for the carrier tracker. "
                 "The default is 0.1 cycles / iad_period"),

      sampleRateOpt('r',"sample-rate",
                    "Specifies the nominal sample rate, in MHz.  The "
                    "default is 20 MHz."),

      interFreqOpt('x',"inter-freq",
                   "Specifies the intermediate frequency of the receiver,"
                   " in MHz.  Default is 0.42 MHz. If there is no down-"
                   "conversion, the IF should be the L1 or L2 carrier"
                   " frequency" ),

      quantizationOpt('q', "quantization",
                      "They quantization applied to the data. 1, 2 or f. "
                      "The default is f."),

      gainOpt('g', "gain",
              "Gain to apply to the if prior to digitization, in dB. Default is 0."),

      timeLimitOpt('t', "time-limit",
                  "Limit the amount of data to process. Specify time in ms. Defaults to all data."),

      inputOpt('i', "input",
               "Where to get the IQ samples from. The default is to use stdin.");

   CommandOptionWithNumberArg
      bandsOpt('b', "bands",
               "The number of complex samples per epoch. The default is 2.");

   if (!BasicFramework::initialize(argc,argv))
      return false;

   if (timeLimitOpt.getCount())
      timeLimit = asDouble(timeLimitOpt.getValue()[0]) * 1e-3;

   if (!codeOpt.getCount())
   {
      cout << "Must specify a code/carrier to track. Bye." << endl;
      return false;
   }

   string val=codeOpt.getValue()[0];
   const char delim(':');
   if (numWords(val, delim) != 5)
   {
      cout << "Error in code parameter:" << val << endl;
      return false;
   }

   string code =   lowerCase(word(val, 0, delim));
          band =       asInt(word(val, 1, delim));
   int    prn =        asInt(word(val, 2, delim));
   double offset =  asDouble(word(val, 3, delim)) * 1e-6;
   double doppler = asDouble(word(val, 4, delim));

   CodeGenerator* codeGenPtr;
   double chipFreq;
   switch (code[0])
   {
      case 'c':
         codeGenPtr = new CACodeGenerator(prn);
         chipFreq = CA_CHIP_FREQ_GPS;
         break;
      case 'p':
         codeGenPtr = new PCodeGenerator(prn);
         chipFreq = PY_CHIP_FREQ_GPS;
         break;
      default:
         cout << "Unsupported code: " << code << endl;
         return false;
   }

   if (sampleRateOpt.getCount())
      timeStep = 1/(asDouble(sampleRateOpt.getValue().front()) * 1e6 );

   if (interFreqOpt.getCount())
      interFreq = asDouble(interFreqOpt.getValue().front()) * 1e6;

   // Note that this object is responsible for destroying
   // the codeGenPtr object
   cc = new CCReplica(timeStep, chipFreq, interFreq, codeGenPtr);

   double chips = offset / cc->codeChipLen;
   cc->moveCodePhase(chips);

   cc->setCodeFreqOffsetHz(doppler);
   cc->setCarrierFreqOffsetHz(doppler);

   double spacing = 0.5 * cc->codeChipLen;
   if (spacing < timeStep)
      spacing = timeStep;

   tr = new EMLTracker(*cc, spacing);

   if (dllAlphaOpt.getCount())
      tr->dllAlpha = asDouble(dllAlphaOpt.getValue()[0]);

   if (dllBetaOpt.getCount())
      tr->dllBeta = asDouble(dllBetaOpt.getValue()[0]);

   if (pllAlphaOpt.getCount())
      tr->pllAlpha = asDouble(pllAlphaOpt.getValue()[0]);

   if (pllBetaOpt.getCount())
      tr->pllBeta = asDouble(pllBetaOpt.getValue()[0]);

   tr->debugLevel = debugLevel;

   char quantization='f';
   if (quantizationOpt.getCount())
      quantization = quantizationOpt.getValue()[0][0];

   switch (quantization)
   {
      case '1': input = new IQ1Stream(); break;
      case '2': input = new IQ2Stream(); break;
      case 'f':
      default:  input = new IQFloatStream(); break;
   }

   if (inputOpt.getCount())
   {
      input->open(inputOpt.getValue()[0].c_str());
   }
   else
   {
      using std::basic_ios;
      input->copyfmt(std::cin);
      input->clear(std::cin.rdstate());
      input->basic_ios<char>::rdbuf(std::cin.rdbuf());
      input->filename = "<stdin>";
   }

   if (bandsOpt.getCount())
      input->bands = asInt(bandsOpt.getValue()[0]);

   if (gainOpt.getCount())
   {
      double gainDb = StringUtils::asDouble(gainOpt.getValue()[0]);
      gain = exp10(gainDb/10.);
   }

   if (verboseLevel)
   {
      cout << "# Taking input from " << input->filename
           << " (" << input->bands << " samples/epoch)" << endl
           << "# Rx gain level: " << gain << endl;
      tr->dump(cout, 1);
   }

   return true;
}
Exemplo n.º 3
0
//-----------------------------------------------------------------------------
void Acquire::process()
{
// Set up all arrays:
// fftw_complex data type is a double[2] where the 0 element is the real
// part and the 1 element is the imaginary part.

// Local code replicas in time domain
   vector< fftw_complex* > l(bins);
   for(int i=0;i<bins;i++)
   {
      fftw_complex* v;
      v = (fftw_complex*) fftw_malloc(sizeof(fftw_complex) * numSamples);
      l[i] = v;
   }
// Input data in time domain
   fftw_complex* in;
   in = (fftw_complex*) fftw_malloc(sizeof(fftw_complex) * numSamples);
// Local code replicas in frequency domain
   vector< fftw_complex* > L(bins);
   for(int i=0;i<bins;i++)
   {
      fftw_complex* v2;
      v2 = (fftw_complex*) fftw_malloc(sizeof(fftw_complex) * numSamples);
      L[i] = v2;
   }
// Input data in frequency domain
   fftw_complex* IN;
   IN = (fftw_complex*) fftw_malloc(sizeof(fftw_complex) * numSamples);
   
   fftw_complex* I;
   fftw_complex* O;
   
// Input * local replica in frequency domain.
   vector< fftw_complex* > MULT(bins);
   for(int i=0;i<bins;i++)
   {
      fftw_complex* v3;
      v3 = (fftw_complex*) fftw_malloc(sizeof(fftw_complex) * numSamples);
      MULT[i] = v3;
   }
// Final results in time domain
   vector< fftw_complex* > fin(bins);
   for(int i=0;i<bins;i++)
   {
      fftw_complex* v4;
      v4 = (fftw_complex*) fftw_malloc(sizeof(fftw_complex) * numSamples);
      fin[i] = v4;
   }
// -------------------------------------------------------------------
   
   // Get input code
   int sample = 0;  
   complex<float> s;
   while (*input >> s && sample < numSamples)
   {
      in[sample][0] = real(s); 
      in[sample][1] = imag(s);
      sample ++;
      for(int i = 1; i < bands; i++)
      {*input >> s;} // gpsSim outputs 2 bands (L1 and L2), 
         //one after the other.
         // This program currently supports L1 only, this loop throws away
         // the input from L2, or any other bands.
   }

   int count; 
   if(prn == 0)  // Check if we are tracking all prns or just one.
   {
      count = 32;
      prn = 1;
   }
   else 
      count = 1;
   
   while(count > 0)
   {
      count--;
      CACodeGenerator* codeGenPtr = new CACodeGenerator(prn);
      float chipFreq = gpstk::CA_CHIP_FREQ;

      // Convert input code to frequency domain.
      fftw_plan p;
      p = fftw_plan_dft_1d(numSamples, in, IN, FFTW_FORWARD, FFTW_ESTIMATE);
      fftw_execute(p);

      // Create local code replicas for each frequency bin.
      float f = -(freqSearchWidth/2); // initial doppler offset
      for(int i = 0; i < bins; i++)  
      {
         cc = new CCReplica(1/sampleRate, chipFreq, interFreq+f, codeGenPtr);
         cc->reset();
         for(int k = 0; k < numSamples; k++)
         {
            complex<double> carrier = cc->getCarrier();
            complex<double> code = cc->getCode() ? 1 : -1;
            l[i][k][0] = real((complex<double>)((code) * (carrier))); 
            l[i][k][1] = imag((complex<double>)((code) * (carrier))); 
            cc->tick();
         }
         f += freqBinWidth;
      }

      // Convert local code replicas to frequency domain.
      fftw_plan plans[bins];
      pthread_t thread_id[bins];
      vector<Par> par(bins);
      int rc;
      for(int i = 0; i < bins; i++)
      {
         plans[i] = fftw_plan_dft_1d
            (numSamples, l[i], L[i], FFTW_FORWARD, FFTW_ESTIMATE);
         par[i].plan = plans[i];
      }
      
      // Execute FFTs
      for(int i = 0; i < bins; i++)
      {
         rc = pthread_create( &thread_id[i], NULL, compute, &par[i] ) ;
         if (rc)
         {
            printf("ERROR; return code from pthread_create() is %d\n", rc);
            exit(-1);
         }
      }
   
      for(int i = 0; i < bins; i++)
      {
         rc = pthread_join( thread_id[i], NULL) ;
         if (rc)
         {
            printf("ERROR; return code from pthread_join() is %d\n", rc);
            exit(-1);
         }
      }

         // above code replaces following block which = no multithreading.
      /*for(int i = 0; i < bins ; i++)
      {
         fftw_execute(plans[i]);
      } */
   
      // NOTE: may want to put following  multiplication into the pthread 
      // function.
      // Will need to pass #bins, #samples and pointers to vectors in a Par.

      // Right now we're only using pthreads to compute FFT's of local codes 
      // in parallel, and there is hardly any performance increase.

   // Multiply conjugate of input frequency samples by 
   // local frequency samples (point by point).
      complex<double> lo;
      complex<double> input;
      complex<double> temp;
      for(int i = 0; i < bins; i++)
      {
         for(int k = 0; k < numSamples; k++)
         {
            lo = (complex<double>(L[i][k][0],L[i][k][1]))
               /(double)sqrt(numSamples);
            input = conj(complex<double>(IN[k][0],IN[k][1]))
               /(double)sqrt(numSamples);
            temp = lo * input;  
            MULT[i][k][0] = real(temp);
            MULT[i][k][1] = imag(temp);
         }
      }
      // Convert back to time domain and find peak.
      for(int i = 0; i < bins; i++)
      {
         p = fftw_plan_dft_1d(numSamples, MULT[i], fin[i], 1, FFTW_ESTIMATE);
         fftw_execute(p);
      }
      double max = 0.0;
      int bin, shift;
      for(int i = 0; i < bins; i++)
      {
         for(int k = 0; k < numSamples; k++)
         { 
            fin[i][k][0] = abs(complex<double>
                               (fin[i][k][0],fin[i][k][1])
                               / (double)sqrt(numSamples));
            if(real(complex<double>(fin[i][k][0],fin[i][k][1])) > max) 
            {
               max = real(complex<double>(fin[i][k][0],fin[i][k][1]));
               shift = k;
               bin = i;
            }
         }
      }

         // Adjust code phase value for multiple periods in time domain. 
      while(shift > (sampleRate*1e-3))
      {
         shift = shift - (sampleRate*1e-3);
      }
   
      // Dump Information.
      if(max < height)
         cout << "PRN: " << prn << " - Unable to acquire." << endl;
      if(max >= height)
      {
         cout << "PRN: " << prn << " - Doppler: " 
              << (bin*1e3)/(1000/freqBinWidth) - (freqSearchWidth/2)
              << " Offset: " << shift*1000/(sampleRate*1e-3)
              << " Height: " << max << endl;
         cout << "       - Tracker Input: -c c:1:" << prn << ":" 
              <<  shift*1000/(sampleRate*1e-3)-5 << ":" 
               // Subtracting 5 right now to make sure the tracker starts 
               // on the "left side" of the peak.
              << (bin*1e3)/(1000/freqBinWidth) - (freqSearchWidth/2) << endl;
      }
      // At some point need to add a more sophisticated check for successful 
      // acquisition like a snr measure, although a simple cutoff works well.
  

      // Output correlation curve for graphing purposes.
      /*for(int k = 0; k < numSamples; k++)
      {
         cout << float((k/16.368)*1.023) << " " << (fin[bin][k][0]) << endl;
      }*/
      prn++;
      fftw_destroy_plan(p);
   } //while
   fftw_free(IN); fftw_free(in); 
}
Exemplo n.º 4
0
//-----------------------------------------------------------------------------
void Corltr::process()
{
   const unsigned windowTicks = static_cast<unsigned>(window / timeStep);
   const unsigned maxSamp=windowTicks+1;
   const double stepSize = cc->codeChipLen/4;
   vector< complex<double> > in(maxSamp);
   unsigned numSamp = 0;
   complex<float> s;
   double sumSq = 0.0;
   while (*input >> s && numSamp < maxSamp)
   {
      in[numSamp] = s;
      sumSq += s.real()*s.real() + s.imag()*s.imag();
      for (int i=1; i<bands; i++)
         *input >> s;
      numSamp++;
   }

   if (numSamp != maxSamp)
   {
      cout << "Insufficient samples for specified window size. Exiting." << endl;
      exit(-1);
   }

   if (verboseLevel)
      cout << "# numSamp:" << numSamp << endl
           << "# timeStep:" << timeStep * 1e9 << " nsec" << endl
           << "# window:" << windowTicks << " samples" << endl
           << "# doppler:" << doppler << " Hz" << endl
           << "# freqErr:" << freqErr * 1e6 << " ppm" << endl
           << "# offset:" << offset*1e6 << " usec" << endl
           << "# Input sumSq: " << sumSq << endl;


   cc->setCodeFreqOffsetHz(doppler);
   cc->setCarrierFreqOffsetHz(doppler);

   if (verboseLevel)
      cc->dump(cout);

   if (verboseLevel)
      cout << "#h delay sum r snr " << endl
           << "#u us cnt cnt dBc-Hz" << endl;

   double maxSnr=0, maxR=0, maxDelay=0;

   for (int i=0; i<steps; i++)
   {
      double delay = i * stepSize + offset;
      cc->reset();
      cc->moveCodePhase(delay / cc->codeChipLen);
      cc->setCodeFreqOffsetHz(doppler);
      cc->setCarrierFreqOffsetHz(doppler);

      SimpleCorrelator<double> sum;
      double mySumSq=0;
      for (int j=0; j<windowTicks; j++)
      {
         cc->tick();
         complex<double> carrier = cc->getCarrier();
         complex<double> m0 = in[j] * conj(carrier);
         complex<double> code = cc->getCode() ? plusOne : minusOne;
         complex<double> cc = conj(carrier) * conj(code);
         mySumSq += cc.real()*cc.real() + cc.imag()*cc.imag();
         sum.process(m0, conj(code));
      }
      double r = abs(sum()) / sqrt(sumSq)/sqrt(mySumSq);
      double snr= 10*log10(r*r/timeStep);
      if (snr>maxSnr)
      {
         maxSnr = snr;
         maxR=r;
         maxDelay=delay;
      }

      if (!peakOnly)
         cout << setprecision(9) << delay*1e6
              << " " << setprecision(4) << abs(sum())
              << " " << r << " " << snr << endl;
      }
   if (peakOnly)
      cout << setprecision(9) << maxDelay*1e6
           << setprecision(4) << " " << maxR << " " << maxSnr << endl;
}