Changeset 11042 in ntrip


Ignore:
Timestamp:
Sep 22, 2026, 5:19:12 PM (64 minutes ago)
Author:
stuerze
Message:

updates regarding RTCM-SSR

Location:
trunk/BNC/src
Files:
9 edited

Legend:

Unmodified
Added
Removed
  • trunk/BNC/src/PPP/pppSatObs.cpp

    r11041 r11042  
    409409// provider is relied on to keep DF+010 synchronized with DF+069 across all
    410410// systems for this to work.
    411 ////////////////////////////////////////////////////////////////////////////
    412 static bool ssrSatAntennaTrusted(const t_satAntenna* satAntenna) {
     411//
     412// Separately, providers only guarantee SatelliteAntennaIOD uniqueness within
     413// a rolling 64-day window (it wraps/repeats after that), so a client that
     414// has been without a fresh Antenna message for that system for 64 days or
     415// more must treat any cached data as unverifiable and stop using it, even
     416// if the IOD/Metadata check above would otherwise pass - the same IOD value
     417// could by then legitimately mean something else. epoTime is the current
     418// processing epoch, compared against t_satAntenna::_time (when this data
     419// was actually decoded, not a wire epoch - the message carries none).
     420////////////////////////////////////////////////////////////////////////////
     421static bool ssrSatAntennaTrusted(const t_satAntenna* satAntenna, const bncTime& epoTime) {
     422  const double MAX_AGE_SEC = 64.0 * 86400.0;
    413423  if (!satAntenna || satAntenna->_satelliteAntennaIOD == 0) {
     424    return false;
     425  }
     426  if (epoTime.valid() && satAntenna->_time.valid() &&
     427      epoTime - satAntenna->_time >= MAX_AGE_SEC) {
    414428    return false;
    415429  }
     
    543557  if (PPP_CLIENT->antex()) {
    544558    const t_satAntenna* satAntenna = PPP_CLIENT->obsPool()->satAntenna(_prn);
    545     if (!ssrSatAntennaTrusted(satAntenna)) {
     559    if (!ssrSatAntennaTrusted(satAntenna, _time)) {
    546560      satAntenna = 0; // untrusted (IOD zero, or not confirmed via Metadata) - fall back to ANTEX
    547561    }
  • trunk/BNC/src/RTCM3/clock_and_orbit/clock_orbit.h

    r11041 r11042  
    604604#define E_NADIR_ANGLE_DEPENDENT_CORR_RANGE_EXTENSION(a) ADDBITS(4,  a)                      /* DF+015 (new RTCM) to extend DF+021*/
    605605#define E_SATELLITE_SET_INDICATOR(a)                    ADDBITS(1,  a)                      /* DF+016 (new RTCM) */
    606 #define E_SATELLITE_MASK(a)                             ADDBITS(64, a)                      /* DF394 */
     606/* ADDBITS' mask "(1<<a)-1" uses a 32-bit int literal, so a plain
     607   ADDBITS(64, a) is broken the same way GETSSRBITS(a, 64) was on decode
     608   (see D_SATELLITE_MASK) - here even ADDBITS(32, ...) is unsafe, since
     609   shifting a 32-bit int by exactly its own width is undefined behavior
     610   too. Stay well clear of that edge by writing four 16-bit chunks. */
     611#define E_SATELLITE_MASK(a)                             { \
     612  uint64_t mask64_ = (a); \
     613  ADDBITS(16, (mask64_ >> 48) & 0xFFFFU) \
     614  ADDBITS(16, (mask64_ >> 32) & 0xFFFFU) \
     615  ADDBITS(16, (mask64_ >> 16) & 0xFFFFU) \
     616  ADDBITS(16,  mask64_        & 0xFFFFU) \
     617}                                                                             /* DF394 */
    607618#define E_FREQUENCY_SET_INDICATOR(a)                    ADDBITS(1,  a)                      /* DF+017 (new RTCM) */
    608619#define E_GNSS_FREQUENCY_MASK(a)                        ADDBITS(6,  a)                      /* DF+018 (new RTCM) */
  • trunk/BNC/src/RTCM3/clock_and_orbit/clock_orbit_igs.cpp

    r11041 r11042  
    945945}
    946946
     947//
     948////////////////////////////////////////////////////////////////////////////
     949size_t SsrCorrIgs::MakeAntenna(const struct Antenna*, SatAntennaType, char*, size_t) {
     950  // This format does not encode Satellite Antenna message content; nothing
     951  // to encode.
     952  return 0;
     953}
     954
  • trunk/BNC/src/RTCM3/clock_and_orbit/clock_orbit_igs.h

    r11041 r11042  
    227227  size_t MakeVTEC(const struct VTEC *v, int moremessagesfollow, char *buffer, size_t size);
    228228  size_t MakeMetaData(const struct MetaData *md, char *buffer, size_t size);
     229  size_t MakeAntenna(const struct Antenna *a, SatAntennaType type, char *buffer, size_t size);
    229230  enum GCOB_RETURN GetSSR(struct ClockOrbit *co, struct CodeBias *cb, struct VTEC *v,
    230231                          struct PhaseBias *pb, struct MetaData *md, struct Antenna* a,
  • trunk/BNC/src/RTCM3/clock_and_orbit/clock_orbit_rtcm.cpp

    r11041 r11042  
    13991399}
    14001400
     1401//
     1402////////////////////////////////////////////////////////////////////////////
     1403size_t SsrCorrRtcm::MakeAntenna(const struct Antenna*, SatAntennaType, char*, size_t) {
     1404  // Satellite Antenna messages are not defined in (old) RTCM-SSR; nothing
     1405  // to encode.
     1406  return 0;
     1407}
     1408
  • trunk/BNC/src/RTCM3/clock_and_orbit/clock_orbit_rtcm.h

    r11041 r11042  
    226226  size_t MakeVTEC(const struct VTEC *v, int moremessagesfollow, char *buffer, size_t size);
    227227  size_t MakeMetaData(const struct MetaData *md, char *buffer, size_t size);
     228  size_t MakeAntenna(const struct Antenna *a, SatAntennaType type, char *buffer, size_t size);
    228229  enum GCOB_RETURN GetSSR(struct ClockOrbit *co, struct CodeBias *cb, struct VTEC *v,
    229230                          struct PhaseBias *pb, struct MetaData *md, struct Antenna* a,
  • trunk/BNC/src/RTCM3/clock_and_orbit/clock_orbit_rtcm_new.cpp

    r11041 r11042  
    495495}
    496496
     497//
     498////////////////////////////////////////////////////////////////////////////
     499size_t SsrCorrRtcmNew::MakeAntenna(const struct Antenna* a, SatAntennaType type,
     500  char* buffer, size_t size) {
     501  unsigned int s, k, satBlockIdx, freqBlockIdx, deg, f, numSatBlocks, numFreqBlocks;
     502  unsigned int satPositions[64], numSatPositions;
     503  unsigned int freqPositions[ANT_MAXFREQUENCIES], numFreqPositions;
     504
     505  STARTDATA
     506
     507    for (s = 0; s < CLOCKORBIT_SATNUM; ++s) {
     508      if (a->SatelliteMask[s] == 0 ||
     509          !(type == SATANTTYPE_AUTO || type == corType[s][COBOFS_SATANT])) {
     510        continue;
     511      }
     512      INITBLOCK
     513        E_RTCM_MESSAGE_NUMBER(corType[s][COBOFS_SATANT])
     514        E_SSR_PROVIDER_ID(a->SSRProviderID[s])
     515        E_SATELLITE_ANTENNA_IOD(a->SatelliteAntennaIOD[s])
     516        E_PHASE_CENTER_INFO_INDICATOR(a->PhaseCenterInformationIndicator[s])
     517        E_GROUP_DELAY_INFO_INDICATOR(a->GroupDelayInformationIndicator[s])
     518        E_NADIR_ANGLE_DEPENDENT_CORR_INDICATOR(a->NadirAngleDependentCorrectionIndicator[s])
     519        if (a->NadirAngleDependentCorrectionIndicator[s]) {
     520          E_MAXIMUM_OFF_NADIR_ANGLE(a->maximumOffNadirAngle[s])
     521          E_NADIR_ANGLE_DEPENDENT_CORR_RANGE_EXTENSION(a->NadirAngleDependentCorrectionRangeExtension[s])
     522        }
     523        E_SATELLITE_SET_INDICATOR(a->SatelliteSetIndicator[s])
     524        E_SATELLITE_MASK(a->SatelliteMask[s])
     525
     526        /* same MSB-first mask convention as D_SATELLITE_MASK/GetSSR */
     527        numSatPositions = 0;
     528        for (k = 0; k < 64 && satoffset[s] + k < satoffset[s + 1]; ++k) {
     529          if ((a->SatelliteMask[s] >> (63 - k)) & 1ULL) {
     530            satPositions[numSatPositions++] = satoffset[s] + k;
     531          }
     532        }
     533        numSatBlocks = a->SatelliteSetIndicator[s] ? (numSatPositions ? 1 : 0) : numSatPositions;
     534
     535        for (satBlockIdx = 0; satBlockIdx < numSatBlocks; ++satBlockIdx) {
     536          /* satellites sharing a block (SatelliteSetIndicator set) must
     537             already carry identical Sat[] content - the caller is
     538             responsible for that, same as the encoder trusts NumberOfSat
     539             elsewhere; only the first masked satellite's data is sent */
     540          const struct Antenna::SatellitePart& satBlock = a->Sat[satPositions[satBlockIdx]];
     541          E_FREQUENCY_SET_INDICATOR(satBlock.FrequencySetIndicator)
     542          E_GNSS_FREQUENCY_MASK(satBlock.GnssFrequencyMask)
     543
     544          numFreqPositions = 0;
     545          for (k = 0; k < ANT_MAXFREQUENCIES; ++k) {
     546            if ((satBlock.GnssFrequencyMask >> (ANT_MAXFREQUENCIES - 1 - k)) & 1U) {
     547              freqPositions[numFreqPositions++] = k;
     548            }
     549          }
     550          numFreqBlocks = satBlock.FrequencySetIndicator ? (numFreqPositions ? 1 : 0) : numFreqPositions;
     551
     552          for (freqBlockIdx = 0; freqBlockIdx < numFreqBlocks; ++freqBlockIdx) {
     553            f = satBlock.FrequencySetIndicator ? freqPositions[0] : freqPositions[freqBlockIdx];
     554            E_NADIR_CORR_INDICATOR(satBlock.Freq[f].NadirCorrectionIndicator)
     555            if (satBlock.Freq[f].NadirCorrectionIndicator) {
     556              E_NADIR_CORRECTION(satBlock.Freq[f].NadirCorrection)
     557            }
     558            if (a->NadirAngleDependentCorrectionIndicator[s]) {
     559              for (deg = 0; deg <= a->maximumOffNadirAngle[s] && deg < ANT_MAXNADIRDEGREES; ++deg) {
     560                E_NADIR_ANGLE_DEPENDENT_CORRECTION(satBlock.Freq[f].NadirAngleCorrection[deg],
     561                  a->NadirAngleDependentCorrectionRangeExtension[s])
     562              }
     563            }
     564          }
     565        }
     566      ENDBLOCK
     567    }
     568  return ressize;
     569}
     570
    497571enum GCOB_RETURN SsrCorrRtcmNew::GetSSR(struct ClockOrbit* co, struct CodeBias* cb, struct VTEC* v,
    498572  struct PhaseBias* pb, struct MetaData* md, struct Antenna* a, const char* buffer, size_t size, int* bytesused) {
     
    11521226
    11531227      for (satBlockIdx = 0; satBlockIdx < numSatBlocks; ++satBlockIdx) {
    1154         struct Antenna::SatellitePart satBlock;
     1228        /* zero-initialized, not just declared: DF+019/DF+013 unset means the
     1229           correction IS zero (not "not present"), per spec - a plain
     1230           declaration left NadirCorrection/NadirAngleCorrection as
     1231           uninitialized stack garbage for every satellite/frequency whose
     1232           indicator was 0, which is nearly all of them in real data. This
     1233           went unnoticed because normal call depth happened to leave zero
     1234           there; it surfaced via a deeper (nested) call stack during
     1235           MakeAntenna round-trip testing. */
     1236        struct Antenna::SatellitePart satBlock = {};
    11551237        D_FREQUENCY_SET_INDICATOR(satBlock.FrequencySetIndicator)
    11561238        D_GNSS_FREQUENCY_MASK(satBlock.GnssFrequencyMask)
  • trunk/BNC/src/RTCM3/clock_and_orbit/clock_orbit_rtcm_new.h

    r11041 r11042  
    280280  size_t MakeVTEC(const struct VTEC *v, int moremessagesfollow, char *buffer, size_t size);
    281281  size_t MakeMetaData(const struct MetaData *md, char *buffer, size_t size);
     282  size_t MakeAntenna(const struct Antenna *a, SatAntennaType type, char *buffer, size_t size);
    282283  enum GCOB_RETURN GetSSR(struct ClockOrbit *co, struct CodeBias *cb, struct VTEC *v,
    283284                          struct PhaseBias *pb, struct MetaData *md, struct Antenna* a,
  • trunk/BNC/src/bnchelp.html

    r11027 r11042  
    46154615  <ol type="1">
    46164616    <li>Special character '&#62;' is the first character in each 'Epoch Record' (as we have it in RINEX Version 3)</li>
    4617     <li>SSR message or topic descriptor, valid descriptors are:<br>ORBIT, CLOCK, CODE_BIAS, PHASE_BIAS, or VTEC</li>
     4617    <li>SSR message or topic descriptor, valid descriptors are:<br>ORBIT, CLOCK, CODE_BIAS, PHASE_BIAS, VTEC, META_DATA, or SAT_ANTENNA</li>
    46184618    <li>Year, GPS time</li>
    46194619    <li>Month, GPS time</li>
     
    46524652  <pre><p style="font-family:Monospace">
    46534653> ORBIT 2022 10 01 23 59 45.0 2 110 SSRA00CNE1
     4654 2
    46544655G01          93    -0.1588    -0.8664    -0.0600        0.2210    -0.1200    -0.0400
    46554656G02          33     0.0491    -1.7468     0.5608        0.1820     0.0040     0.0200
     
    46724673<p></pre>
    46734674
     4675  <p>
     4676    The second record in this block provides one parameter, an SSR source format indicator:
     4677  <ul>
     4678    <li>SSR source format indicator<br>
     4679      0 &minus; unknown<br>
     4680      1 &minus; (old) RTCM-SSR / IGS-SSR<br>
     4681      2 &minus; (new) RTCM-SSR
     4682    </li>
     4683  </ul>
     4684  This indicator determines which relativistic correction formula applies when the orbit correction is combined
     4685  with the Broadcast Ephemeris: the velocity-based formula of IS-GPS-200D 20.3.3.3.3.1 for the (new) RTCM-SSR
     4686  format, or the classic eccentricity-based formula otherwise.
     4687  </p>
    46744688  Records in this block provide the following satellite specific information:
    46754689  <ul>
     
    47634777  <pre><p style="font-family:Monospace">
    47644778> PHASE_BIAS 2022 10 01 23 59 45.0 2 110 SSRA00CNE1
    4765  0   1
     4779 2   0   1
    47664780G01 157.50000000   0.00000000    3   1C    -0.6023   1   2   7   2W    -0.8679   1   2   7   5I    -0.8614   1   2   7
    47674781G02  13.35937500   0.00000000    2   1C     0.7878   1   2   4   2W     1.1236   1   2   4
     
    47834797</p></pre>
    47844798  <p>
    4785     The second record in this block provides the following consistency information:
     4799    The second record in this block starts with the same SSR source format indicator used in the 'ORBIT' block
     4800    (0 = unknown, 1 = (old) RTCM-SSR / IGS-SSR, 2 = (new) RTCM-SSR), followed by two more numbers whose meaning
     4801    depends on it, since RTCM-SSR and IGS-SSR/(old) RTCM-SSR define different phase bias parameters here:
    47864802  <ul>
    47874803
    4788     <li>Dispersive bias consistency indicatory<br>
    4789       0 &minus; phase biases valid for non-dispersive signal only<br>
    4790       1 &minus; phase biases maintain consistency between non-dispersive and all original dispersive phase signals
    4791     </li>
    4792 
    4793     <li>MW consistency indicator<br>
    4794       0 &minus; code and phase biases are independently derived<br>
    4795       1 &minus; consistency between code and phase biases is maintained for the MW combinations
    4796     </li>
     4804    <li>SSR source format indicator = 2, i.e. (new) RTCM-SSR:</li>
     4805    <ul>
     4806      <li>Satellite Yaw Information indicator<br>
     4807        0 &minus; yaw angle/rate not provided (both fields below are zero)<br>
     4808        1 &minus; yaw angle/rate provided
     4809      </li>
     4810      <li>Extended Phase Bias Property ID &minus; a satellite-specific property ID (0-15) used to correlate a
     4811          later Extended Phase Bias message's wide-lane information back onto this satellite's signals</li>
     4812    </ul>
     4813
     4814    <li>SSR source format indicator = 0 or 1, i.e. unknown or (old) RTCM-SSR/IGS-SSR:</li>
     4815    <ul>
     4816      <li>Dispersive Bias Consistency indicator<br>
     4817        0 &minus; phase biases valid for non-dispersive signal only<br>
     4818        1 &minus; phase biases maintain consistency between non-dispersive and all original dispersive phase
     4819            signals
     4820      </li>
     4821      <li>MW Consistency indicator<br>
     4822        0 &minus; code and phase biases are independently derived<br>
     4823        1 &minus; consistency between code and phase biases is maintained for the MW combinations
     4824      </li>
     4825    </ul>
    47974826
    47984827  </ul>
     
    48584887    <li>Spherical harmonic coefficients C and S, sorted by degree and order (0 to maximum)</li>
    48594888  </ul>
     4889  </p>
     4890
     4891  <p>
     4892    <b>Example for block 'META_DATA' carrying model/correction metadata</b>
     4893  </p>
     4894  <pre><p style="font-family:Monospace">
     4895> META_DATA 2026 06 26 09 00 15.0 0 3 SSRA00BKG0
     48962 260 3
     4897 3 1 0  0 0   0
     4898 6 1 0  0 0   0
     4899 7 1 0  0 0   0
     4900</p></pre>
     4901  <p>
     4902    The second record in this block provides three parameters:
     4903  <ul>
     4904    <li>SSR IOD</li>
     4905    <li>SSR Provider ID</li>
     4906    <li>SSR Solution ID</li>
     4907  </ul>
     4908  Following records, one per model/correction entry, provide:
     4909  <ul>
     4910    <li>Model/correction type indicator<br>
     4911      1 &minus; satellite antenna Phase Center Variations (PCV)<br>
     4912      2 &minus; satellite antenna Group Delay Variations (GDV)<br>
     4913      3 &minus; solid earth tides<br>
     4914      4 &minus; ocean loading<br>
     4915      5 &minus; pole tides<br>
     4916      6 &minus; relativity<br>
     4917      7 &minus; GNSS broadcast ephemeris reference
     4918    </li>
     4919    <li>Application indicator (whether the model/correction is applied on the provider's side)</li>
     4920    <li>Non-default model indicator</li>
     4921    <li>Non-default model identifier (only valid if the non-default model indicator is set)</li>
     4922    <li>Data IOD indicator</li>
     4923    <li>Data IOD (only valid if the Data IOD indicator is set) &minus; for type 1 or 2, this confirms the
     4924        Satellite Antenna IOD of a 'SAT_ANTENNA' block below, see there</li>
     4925  </ul>
     4926  </p>
     4927
     4928  <p>
     4929    <b>Example for block 'SAT_ANTENNA' carrying satellite antenna corrections</b>
     4930  </p>
     4931  <pre><p style="font-family:Monospace">
     4932> SAT_ANTENNA 2026 06 26 09 00 15.0 0 16 SSRA00BKG0
     4933G08  260 23 1 0 1 16  7    2   G1 0     0.0000    0.0000   -0.0020   -0.0030   -0.0050   -0.0060   -0.0070   -0.0090   -0.0100   -0.0100   -0.0100   -0.0100   -0.0080   -0.0060   -0.0030    0.0000    0.0060    0.0120   G2 0     0.0000    0.0000   -0.0020   -0.0030   -0.0050   -0.0060   -0.0070   -0.0090   -0.0100   -0.0100   -0.0100   -0.0100   -0.0080   -0.0060   -0.0030    0.0000    0.0060    0.0120
     4934G16  260 23 1 0 1 16  7    2   G1 0     0.0000    0.0000    0.0010    0.0030    0.0050    0.0070    0.0100    0.0110    0.0110    0.0100    0.0090    0.0070    0.0050    0.0040    0.0040    0.0050    0.0050    0.0080   G2 0     0.0000    0.0000    0.0010    0.0030    0.0050    0.0070    0.0100    0.0110    0.0110    0.0100    0.0090    0.0070    0.0050    0.0040    0.0040    0.0050    0.0050    0.0080
     4935..
     4936</p></pre>
     4937  <p>
     4938    Records in this block provide the following satellite specific information:
     4939  <ul>
     4940    <li>GNSS Indicator and Satellite Vehicle Pseudo Random Number</li>
     4941    <li>SSR Provider ID</li>
     4942    <li>Satellite Antenna IOD &minus; unique per Provider ID within a rolling 64-day period, see note below</li>
     4943    <li>Phase Center Information indicator &minus; corrections apply to phaserange observations</li>
     4944    <li>Group Delay Information indicator &minus; corrections apply to pseudorange observations</li>
     4945    <li>Nadir Angle Dependent Correction indicator</li>
     4946    <li>Maximum off-nadir angle [deg] (only meaningful if the previous indicator is set)</li>
     4947    <li>Nadir angle dependent correction range extension (extra bit width for the correction values below)</li>
     4948    <li>Number of frequencies, succeeded by frequency specific information:</li>
     4949    <ul>
     4950      <li>Frequency label (e.g. G1, G2, G5, R1, R2, E1, E5, E6, E7, E8, J1, J2, J5, J6, C1, C2, C5, C6, C7)</li>
     4951      <li>Nadir correction indicator</li>
     4952      <li>Nadir correction [m] &minus; offset between the orbit antenna reference point and the frequency
     4953          reference point along the satellite's nadir direction; zero if the indicator above is not set</li>
     4954      <li>Nadir angle dependent correction [m], one value per 1-degree bin from 0 up to the maximum
     4955          off-nadir angle above (only present if the Nadir Angle Dependent Correction indicator is set)</li>
     4956      <li>Frequency label, ...</li>
     4957      <li>etc.</li>
     4958    </ul>
     4959  </ul>
     4960  </p>
     4961  <p>
     4962    Whether a given correction is a Phase Center Variation (PCV, applies to phaserange observations only), a
     4963    Group Delay Variation (GDV, applies to pseudorange observations only), or both at once (same values applied to
     4964    each observation type independently) is determined by the Phase Center Information and Group Delay Information
     4965    indicators, not by the type of value itself.
     4966  </p>
     4967  <p>
     4968    Before BNC's PPP client applies a satellite's antenna correction, it must be confirmed via a 'META_DATA' block:
     4969    the Satellite Antenna IOD must be non-zero and must match the Data IOD of a Metadata entry of type 1 (PCV) or
     4970    type 2 (GDV) &minus; either is sufficient, since Metadata carries this IOD once globally while the Satellite
     4971    Antenna IOD is GNSS-specific, so the same Metadata entries serve as the trust anchor for every GNSS. In
     4972    addition, since a Satellite Antenna IOD is only guaranteed unique within a rolling 64-day period, BNC discards
     4973    any Satellite Antenna correction that is 64 days or older, even if its IOD would otherwise still match, and
     4974    falls back to using ANTEX-based satellite antenna corrections instead.
    48604975  </p>
    48614976
Note: See TracChangeset for help on using the changeset viewer.