Esempio n. 1
0
/** Simulates real observations for the current position and the satellite almanac and week
* given in simulator_data.
*
* NOTES:
*
* - This simulates the pseudorange as the true distance to the satellite + noise.
* - This simulates the carrier phase as the true distance in wavelengths + bais + noise.
* - The bias is an integer multiple of 10 for easy debugging.
* - The satellite SNR/CN0 is proportional to the elevation of the satellite.
*
* USES:
* - Pipe observations into internals for testing
* - For integration testing with other devices that has to carry the radio signal.
*
* \param elapsed Number of seconds elapsed since last simulation step.
*/
void simulation_step_tracking_and_observations(double elapsed)
{
  (void)elapsed;

  u8 week = -1;
  double t = sim_state.noisy_solution.time.tow;

  /* First we calculate all the current sat positions, velocities */
  for (u8 i=0; i<simulation_num_almanacs; i++) {
    calc_sat_state_almanac(&simulation_almanacs[i], t, week,
      simulation_sats_pos[i], simulation_sats_vel[i]);
  }


  /* Calculate the first sim_settings.num_sats amount of visible sats */
  u8 num_sats_selected = 0;
  double az, el;
  for (u8 i=0; i<simulation_num_almanacs; i++) {
    calc_sat_az_el_almanac(&simulation_almanacs[i], t, week,
                            sim_state.pos, &az, &el);

    if (el > 0 &&
        num_sats_selected < sim_settings.num_sats &&
        num_sats_selected < MAX_CHANNELS) {

      /* Generate a code measurement which is just the pseudorange: */
      double points_to_sat[3];
      double base_points_to_sat[3];

      vector_subtract(3, simulation_sats_pos[i], sim_state.pos, points_to_sat);
      vector_subtract(3, simulation_sats_pos[i], sim_settings.base_ecef, base_points_to_sat);

      double distance_to_sat = vector_norm(3, points_to_sat);
      double base_distance_to_sat = vector_norm(3, base_points_to_sat);

      /* Fill out the observation details into the NAV_MEAS structure for this satellite, */
      /* We simulate the pseudorange as a noisy range measurement, and */
      /* the carrier phase as a noisy range in wavelengths + an integer offset. */

      populate_nav_meas(&sim_state.nav_meas[num_sats_selected],
        distance_to_sat, el, i);

      populate_nav_meas(&sim_state.base_nav_meas[num_sats_selected],
        base_distance_to_sat, el, i);

      /* As for tracking, we just set each sat consecutively in each channel. */
      /* This will cause weird jumps when a satellite rises or sets. */
      sim_state.tracking_channel[num_sats_selected].state = TRACKING_RUNNING;
      sim_state.tracking_channel[num_sats_selected].prn = simulation_almanacs[i].prn  + SIM_PRN_OFFSET;
      sim_state.tracking_channel[num_sats_selected].cn0 = sim_state.nav_meas[num_sats_selected].snr;

      num_sats_selected++;
    }
  }

  sim_state.noisy_solution.n_used = num_sats_selected;

}
Esempio n. 2
0
/** Using available almanac and ephemeris information, determine
 * whether a satellite is in view and the range of doppler frequencies
 * in which we expect to find it.
 *
 * \param prn 0-indexed PRN
 * \param t Time at which to evaluate ephemeris and almanac (typically system's
 *  estimate of current time)
 * \param dopp_hint_low, dopp_hint_high Pointers to store doppler search range
 *  from ephemeris or almanac, if available and elevation > mask
 * \return Score (higher is better)
 */
static u16 manage_warm_start(u8 prn, gps_time_t t,
                             float *dopp_hint_low, float *dopp_hint_high)
{
    /* Do we have any idea where/when we are?  If not, no score. */
    /* TODO: Stricter requirement on time and position uncertainty?
       We ought to keep track of a quantitative uncertainty estimate. */
    if (time_quality < TIME_GUESS &&
        position_quality < POSITION_GUESS)
      return SCORE_COLDSTART;

    float el = 0;
    double el_d, _, dopp_hint = 0, dopp_uncertainty = DOPP_UNCERT_ALMANAC;

    /* Do we have a suitable ephemeris for this sat?  If so, use
       that in preference to the almanac. */
    if (ephemeris_good(&es[prn], t)) {
      double sat_pos[3], sat_vel[3], el_d;
      calc_sat_state(&es[prn], t, sat_pos, sat_vel, &_, &_);
      wgsecef2azel(sat_pos, position_solution.pos_ecef, &_, &el_d);
      el = (float)(el_d) * R2D;
      if (el < elevation_mask)
        return SCORE_BELOWMASK;
      vector_subtract(3, sat_pos, position_solution.pos_ecef, sat_pos);
      vector_normalize(3, sat_pos);
      /* sat_pos now holds unit vector from us to satellite */
      vector_subtract(3, sat_vel, position_solution.vel_ecef, sat_vel);
      /* sat_vel now holds velocity of sat relative to us */
      dopp_hint = -GPS_L1_HZ * (vector_dot(3, sat_pos, sat_vel) / GPS_C
                                + position_solution.clock_bias);
      /* TODO: Check sign of receiver frequency offset correction */
      if (time_quality >= TIME_FINE)
        dopp_uncertainty = DOPP_UNCERT_EPHEM;
    } else if (almanac[prn].valid) {
      calc_sat_az_el_almanac(&almanac[prn], t.tow, t.wn-1024,
                             position_solution.pos_ecef, &_, &el_d);
      el = (float)(el_d) * R2D;
      if (el < elevation_mask)
        return SCORE_BELOWMASK;
      dopp_hint = -calc_sat_doppler_almanac(&almanac[prn], t.tow, t.wn,
                                            position_solution.pos_ecef);
    } else {
      return SCORE_COLDSTART; /* Couldn't determine satellite state. */
    }
    /* Return the doppler hints and a score proportional to elevation */
    *dopp_hint_low = dopp_hint - dopp_uncertainty;
    *dopp_hint_high = dopp_hint + dopp_uncertainty;
    return SCORE_COLDSTART + SCORE_WARMSTART * el / 90.f;
}
Esempio n. 3
0
static void manage_calc_almanac_scores(void)
{
  double az, el;
  gps_time_t t = get_current_time();

  for (u8 prn=0; prn<32; prn++) {
    if (!almanac[prn].valid ||
        time_quality == TIME_UNKNOWN ||
        position_quality == POSITION_UNKNOWN) {
      /* No almanac or position/time information, give it the benefit of the
       * doubt. */
      acq_prn_param[prn].score[ACQ_HINT_ALMANAC] = 0;
    } else {
      calc_sat_az_el_almanac(&almanac[prn], t.tow, t.wn-1024, position_solution.pos_ecef, &az, &el);
      float dopp = -calc_sat_doppler_almanac(&almanac[prn], t.tow, t.wn,
                                             position_solution.pos_ecef);
      acq_prn_param[prn].score[ACQ_HINT_ALMANAC] =
            el > 0 ? (u16)(SCORE_ALMANAC * 2 * el / M_PI) : 0;
      acq_prn_param[prn].dopp_hint_low = dopp - ALMANAC_DOPPLER_WINDOW;
      acq_prn_param[prn].dopp_hint_high = dopp + ALMANAC_DOPPLER_WINDOW;
    }
  }
}
Esempio n. 4
0
static void manage_calc_scores(void)
{
  double az, el;
  gps_time_t t;

  if (time_quality != TIME_UNKNOWN)
    t = get_current_time();

  for (u8 prn=0; prn<32; prn++) {
    if (!almanac[prn].valid ||
        time_quality == TIME_UNKNOWN ||
        position_quality == POSITION_UNKNOWN) {
      /* No almanac or position/time information, give it the benefit of the
       * doubt. */
      acq_prn_param[prn].score = 0;
    } else {
      calc_sat_az_el_almanac(&almanac[prn], t.tow, t.wn-1024, position_solution.pos_ecef, &az, &el);
      acq_prn_param[prn].score = (s8)(el/D2R);

      gps_time_t toa;
      toa.wn = almanac[prn].week + 1024;
      toa.tow = almanac[prn].toa;

      double dt_alm = fabs(gpsdifftime(t, toa));
      double dt_pos = fabs(gpsdifftime(t, position_solution.time));

      if (time_quality == TIME_GUESS ||
          dt_pos > 1*24*3600 ||
          dt_alm > 4*24*3600) {
        /* Don't exclude other sats if our time is just a guess, our last
         * position solution was ages ago or our almanac is old. */
        if (acq_prn_param[prn].score < 0)
          acq_prn_param[prn].score = 0;
      }
    }
  }
}
Esempio n. 5
0
/** Using available almanac and ephemeris information, determine
 * whether a satellite is in view and the range of doppler frequencies
 * in which we expect to find it.
 *
 * \param prn 0-indexed PRN
 * \param t Time at which to evaluate ephemeris and almanac (typically system's
 *  estimate of current time)
 * \param dopp_hint_low, dopp_hint_high Pointers to store doppler search range
 *  from ephemeris or almanac, if available and elevation > mask
 * \return Score (higher is better)
 */
static u16 manage_warm_start(gnss_signal_t sid, const gps_time_t* t,
                             float *dopp_hint_low, float *dopp_hint_high)
{
    /* Do we have any idea where/when we are?  If not, no score. */
    /* TODO: Stricter requirement on time and position uncertainty?
       We ought to keep track of a quantitative uncertainty estimate. */
    if (time_quality < TIME_GUESS &&
        position_quality < POSITION_GUESS)
      return SCORE_COLDSTART;

    float el = 0;
    double _, dopp_hint = 0, dopp_uncertainty = DOPP_UNCERT_ALMANAC;
    bool ready = false;
    /* Do we have a suitable ephemeris for this sat?  If so, use
       that in preference to the almanac. */
    const ephemeris_t *e = ephemeris_get(sid);
    u8 eph_valid;
    s8 ss_ret;
    double sat_pos[3], sat_vel[3], el_d;

    ephemeris_lock();
    eph_valid = ephemeris_valid(e, t);
    if (eph_valid) {
      ss_ret = calc_sat_state(e, t, sat_pos, sat_vel, &_, &_);
    }
    ephemeris_unlock();

    if (eph_valid && (ss_ret == 0)) {
      wgsecef2azel(sat_pos, position_solution.pos_ecef, &_, &el_d);
      el = (float)(el_d) * R2D;
      if (el < elevation_mask)
        return SCORE_BELOWMASK;
      vector_subtract(3, sat_pos, position_solution.pos_ecef, sat_pos);
      vector_normalize(3, sat_pos);
      /* sat_pos now holds unit vector from us to satellite */
      vector_subtract(3, sat_vel, position_solution.vel_ecef, sat_vel);
      /* sat_vel now holds velocity of sat relative to us */
      dopp_hint = -GPS_L1_HZ * (vector_dot(3, sat_pos, sat_vel) / GPS_C
                                + position_solution.clock_bias);
      /* TODO: Check sign of receiver frequency offset correction */
      if (time_quality >= TIME_FINE)
        dopp_uncertainty = DOPP_UNCERT_EPHEM;
      ready = true;
    }

    if(!ready) {
      const almanac_t *a = &almanac[sid_to_global_index(sid)];
      if (a->valid &&
          calc_sat_az_el_almanac(a, t, position_solution.pos_ecef,
                                 &_, &el_d) == 0) {
          el = (float)(el_d) * R2D;
          if (el < elevation_mask)
            return SCORE_BELOWMASK;
          if (calc_sat_doppler_almanac(a, t, position_solution.pos_ecef,
                                       &dopp_hint) != 0) {
            return SCORE_COLDSTART;
          }
          dopp_hint = -dopp_hint;
      } else {
        return SCORE_COLDSTART; /* Couldn't determine satellite state. */
      }
    }

    /* Return the doppler hints and a score proportional to elevation */
    *dopp_hint_low = dopp_hint - dopp_uncertainty;
    *dopp_hint_high = dopp_hint + dopp_uncertainty;
    return SCORE_COLDSTART + SCORE_WARMSTART * el / 90.f;
}