Esempio n. 1
0
/** Encode an RTCMv3 message type 1002 (Extended L1-Only GPS RTK Observables)
 * Message type 1002 has length `64 + n_sat*74` bits. Returned message length
 * is rounded up to the nearest whole byte.
 *
 * \param buff A pointer to the RTCM data message buffer.
 * \param id Reference station ID (DF003).
 * \param t GPS time of epoch (DF004).
 * \param n_sat Number of GPS satellites included in the message (DF006).
 * \param nm Struct containing the observation.
 * \param sync Synchronous GNSS Flag (DF005).
 * \return The message length in bytes.
 */
u16 rtcm3_encode_1002(u8 *buff, u16 id, gps_time_t t, u8 n_sat,
                      navigation_measurement_t *nm, u8 sync)
{
  rtcm3_write_header(buff, 1002, id, t, sync, n_sat, 0, 0);

  u16 bit = 64; /* Start at end of header. */

  u32 pr;
  s32 ppr;
  u8 amb, lock, cnr;

  for (u8 i=0; i<n_sat; i++) {
    gen_obs_gps(&nm[i], &amb, &pr, &ppr, &lock, &cnr);

    setbitu(buff, bit, 6, nm[i].sid.sat); bit += 6;
    /* TODO: set GPS code indicator if we ever support P(Y) code measurements. */
    setbitu(buff, bit, 1,  0);    bit += 1;
    setbitu(buff, bit, 24, pr);   bit += 24;
    setbits(buff, bit, 20, ppr);  bit += 20;
    setbitu(buff, bit, 7,  lock); bit += 7;
    setbitu(buff, bit, 8,  amb);  bit += 8;
    setbitu(buff, bit, 8,  cnr);  bit += 8;
  }

  /* Round number of bits up to nearest whole byte. */
  return (bit + 7) / 8;
}
Esempio n. 2
0
END_TEST

START_TEST(test_rtcm3_read_write_header)
{
  u8 buff[22];

  gps_time_t t = {
    .wn = 22,
    .tow = 22.222
  };

  rtcm3_write_header(buff, 1234, 2269, t, 1, 22, 1, 6);

  u16 type, id;
  u8 sync, n_sat, div_free, smooth;
  double tow;

  rtcm3_read_header(buff, &type, &id, &tow, &sync, &n_sat, &div_free, &smooth);

  fail_unless(type == 1234, "type decode error, decoded %d, expected 1234", type);
  fail_unless(id == 2269, "id decode error, decoded %d, expected 2269", id);
  fail_unless(fabs(tow - t.tow) < 1e3, "TOW decode error, decoded %f, expected %f", tow, t.tow);
  fail_unless(sync == 1, "id decode error, decoded %d, expected 1", id);
  fail_unless(n_sat == 22, "n_sat decode error, decoded %d, expected 22", n_sat);
  fail_unless(div_free == 1, "div_free decode error, decoded %d, expected 1", div_free);
  fail_unless(smooth == 6, "smooth decode error, decoded %d, expected 6", smooth);
}
END_TEST


START_TEST(test_rtcm3_encode_decode)
{
  navigation_measurement_t nm_orig[22];
  navigation_measurement_t nm[22];

  seed_rng();

  for (u8 i=0; i<22; i++) {
    nm[i].raw_pseudorange = frand(19e6, 21e6);
    nm[i].carrier_phase = frand(-5e5, 5e5);
    nm[i].lock_time = frand(0, 1000);
    nm[i].snr = frand(0, 20);
  }

  memcpy(nm_orig, nm, sizeof(nm));

  gps_time_t t = {
    .wn = 1234,
    .tow = frand(0, 604800)
  };

  u8 buff[355];

  rtcm3_encode_1002(buff, 1234, t, 22, nm, 0);

  navigation_measurement_t nm_out[22];
  double tow_out;
  u8 sync, n_sat = 222;
  u16 id;

  s8 ret = rtcm3_decode_1002(buff, &id, &tow_out, &n_sat, 0, &sync);

  fail_unless(ret >= 0, "rtcm3_decode_1002 returned an error (%d)", ret);
  fail_unless(id == 1234, "decoded station id as %d, expected 1234", id);
  fail_unless(n_sat == 22, "decoded n_sat as %d, expected 22", n_sat);
  fail_unless(fabs(tow_out - t.tow) < 1e-3, "decoded TOW as %f, expected %f, error %f",
      tow_out, t.tow, tow_out - t.tow);

  ret = rtcm3_decode_1002(buff, &id, &tow_out, &n_sat, nm_out, &sync);

  for (u8 i=0; i<22; i++) {
    double pr_err = nm[i].raw_pseudorange - nm_out[i].raw_pseudorange;
    fail_unless(fabs(pr_err) < 0.02, "[%d] pseudorange error > 0.04m - "
        "decoded %f, expected %f, error %f", i, nm_out[i].raw_pseudorange, nm[i].raw_pseudorange, pr_err);

    double carr_err = nm[i].carrier_phase - nm_out[i].carrier_phase;
    fail_unless(fabs(carr_err) < 0.003, "carrier phase error (fractional part) > 0.003 cycles - "
        "[%d] decoded %f, expected %f, error %f", i, nm_out[i].carrier_phase, nm[i].carrier_phase, carr_err);

    double snr_err = nm[i].snr - nm_out[i].snr;
    /* Calculate error bound on SNR given logarithmic error bound on CNR. */
    double err_bound = nm[i].snr * (pow(10.0, 1.0 / 40.0) - 1);
    fail_unless(fabs(snr_err) < err_bound, "SNR error > 0.003 - "
        "[%d] decoded %f, expected %f, error %f, bound %f", i, nm_out[i].snr, nm[i].snr, snr_err, err_bound);

    fail_unless((nm_out[i].lock_time == 0) && (nm[i].lock_time == 0),
        "lock time should be zero when adjusting int. amb. - [%d] decoded %f",
        i, nm_out[i].lock_time, nm[i].lock_time);

    double cp_adj = nm[i].carrier_phase - nm_orig[i].carrier_phase;
    fail_unless(fmod(cp_adj, 1.0) == 0,
        "carrier phase adjusted by non integer amount %f -> %f (%f)",
        nm_orig[i].carrier_phase, nm[i].carrier_phase, cp_adj);
  }

  /* Re-encode after adjustment, now there should be no further adjustment and
   * the lock time should be correct. */

  for (u8 i=0; i<22; i++)
    nm[i].lock_time = frand(0, 1000);

  rtcm3_encode_1002(buff, 1234, t, 22, nm, 0);
  rtcm3_decode_1002(buff, &id, &tow_out, &n_sat, nm_out, &sync);

  for (u8 i=0; i<22; i++) {
    double cp_adj = nm_out[i].carrier_phase - nm[i].carrier_phase;
    fail_unless(cp_adj < 0.003, "carrier phase re-adjusted %f -> %f (%f)",
        nm[i].carrier_phase, nm_out[i].carrier_phase, cp_adj);

    fail_unless(nm_out[i].lock_time <= nm[i].lock_time,
        "lock time error, should always be less than input lock time - [%d] decoded %f, expected %f",
        i, nm_out[i].lock_time, nm[i].lock_time);
  }
}
END_TEST


Suite* rtcm3_suite(void)
{
  Suite *s = suite_create("RTCMv3");

  TCase *tc_core = tcase_create("Core");
  tcase_add_test(tc_core, test_rtcm3_check_frame);
  tcase_add_test(tc_core, test_rtcm3_write_frame);
  tcase_add_test(tc_core, test_rtcm3_read_write_header);
  tcase_add_test(tc_core, test_rtcm3_encode_decode);
  suite_add_tcase(s, tc_core);

  return s;
}