1   /* Copyright 2002-2026 CS GROUP
2    * Licensed to CS GROUP (CS) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * CS licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *   http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  package org.orekit.files.rinex.observation;
18  
19  import java.util.ArrayList;
20  import java.util.Collections;
21  import java.util.HashMap;
22  import java.util.List;
23  import java.util.Map;
24  
25  import org.hipparchus.geometry.euclidean.threed.Vector3D;
26  import org.hipparchus.geometry.euclidean.twod.Vector2D;
27  import org.orekit.files.rinex.section.Label;
28  import org.orekit.files.rinex.section.RinexClockObsBaseHeader;
29  import org.orekit.files.rinex.utils.ParsingUtils;
30  import org.orekit.files.rinex.utils.RinexFileType;
31  import org.orekit.gnss.SatInSystem;
32  import org.orekit.gnss.SatelliteSystem;
33  import org.orekit.time.AbsoluteDate;
34  import org.orekit.time.TimeScales;
35  
36  /** Container for Rinex observation file header.
37   * @since 9.2
38   */
39  public class RinexObservationHeader extends RinexClockObsBaseHeader {
40  
41      /** Index of label in header lines. */
42      public static final int LABEL_INDEX = 60;
43  
44      /** Name of the Antenna Marker. */
45      private String markerName;
46  
47      /** Number of Antenna marker. */
48      private String markerNumber;
49  
50      /** Type of Antenna marker. */
51      private String markerType;
52  
53      /** Name of Observer. */
54      private String observerName;
55  
56      /** Name of Agency. */
57      private String agencyName;
58  
59      /** Antenna Number. */
60      private String antennaNumber;
61  
62      /** Antenna Type. */
63      private String antennaType;
64  
65      /** Approximate Marker Position (WGS84). */
66      private Vector3D approxPos;
67  
68      /** Antenna Height. */
69      private double antennaHeight;
70  
71      /** Eccentricities of antenna center. */
72      private Vector2D eccentricities;
73  
74      /** Position of antenna reference point for antenna on vehicle. */
75      private Vector3D antRefPoint;
76  
77      /** Satellite system for average phasecenter position.
78       * @since 12.0
79       */
80      private SatelliteSystem phaseCenterSystem;
81  
82      /** Observation code of the average phasecenter position w/r to antenna reference point. */
83      private String observationCode;
84  
85      /** Antenna phasecenter.
86       * North/East/Up (fixed station) or X/Y/Z in body fixed system (vehicle). */
87      private Vector3D antennaPhaseCenter;
88  
89      /** Antenna B.Sight.
90       * Direction of the “vertical” antenna axis towards the GNSS satellites.  */
91      private Vector3D antennaBSight;
92  
93      /** Azimuth of the zero direction of a fixed antenna (degrees, from north). */
94      private double antennaAzimuth;
95  
96      /** Zero direction of antenna. */
97      private Vector3D antennaZeroDirection;
98  
99      /** Current center of mass (X,Y,Z, meters) of vehicle in body fixed coordinate system. */
100     private Vector3D centerMass;
101 
102     /** Unit of the carrier to noise ratio observables Snn (if present) DBHZ: S/N given in dbHz. */
103     private String signalStrengthUnit;
104 
105     /** Observation interval in seconds. */
106     private double interval;
107 
108     /** Time of First observation record. */
109     private AbsoluteDate tFirstObs;
110 
111     /** Time of last observation record. */
112     private AbsoluteDate tLastObs;
113 
114     /** Flag for application of real time-derived receiver clock offset.
115      * @since 12.1
116      */
117     private boolean clockOffsetApplied;
118 
119     /** List of phase shift correction used to generate phases consistent w/r to cycle shifts. */
120     private final List<PhaseShiftCorrection> phaseShiftCorrections;
121 
122     /** List of scale factor corrections. */
123     private final Map<SatelliteSystem, List<ScaleFactorCorrection>> scaleFactorCorrections;
124 
125     /** List of GLONASS satellite-channel associations.
126      * @since 12.0
127      */
128     private final List<GlonassSatelliteChannel> glonassChannels;
129 
130     /** Number of satellites.
131      * @since 12.0
132      */
133     private int nbSat;
134 
135     /** Number of observations per satellite.
136      * @since 12.0
137      */
138     private final Map<SatInSystem, Map<String, Integer>> nbObsPerSat;
139 
140     /** Code phase bias correction for GLONASS C1C signal.
141      * @since 12.0
142      */
143     private double c1cCodePhaseBias;
144 
145     /** Code phase bias correction for GLONASS C1P signal.
146      * @since 12.0
147      */
148     private double c1pCodePhaseBias;
149 
150     /** Code phase bias correction for GLONASS C2C signal.
151      * @since 12.0
152      */
153     private double c2cCodePhaseBias;
154 
155     /** Code phase bias correction for GLONASS C2P signal.
156      * @since 12.0
157      */
158     private double c2pCodePhaseBias;
159 
160     /** Simple constructor.
161      */
162     public RinexObservationHeader() {
163         super(RinexFileType.OBSERVATION);
164         antennaAzimuth         = Double.NaN;
165         antennaHeight          = Double.NaN;
166         eccentricities         = Vector2D.ZERO;
167         clockOffsetApplied     = false;
168         nbSat                  = -1;
169         interval               = Double.NaN;
170         phaseShiftCorrections  = new ArrayList<>();
171         scaleFactorCorrections = new HashMap<>();
172         glonassChannels        = new ArrayList<>();
173         nbObsPerSat            = new HashMap<>();
174         tLastObs               = AbsoluteDate.FUTURE_INFINITY;
175         c1cCodePhaseBias       = Double.NaN;
176         c1pCodePhaseBias       = Double.NaN;
177         c2cCodePhaseBias       = Double.NaN;
178         c2pCodePhaseBias       = Double.NaN;
179     }
180 
181     /** {@inheritDoc} */
182     @Override
183     public SatelliteSystem parseSatelliteSystem(final String line, final SatelliteSystem defaultSatelliteSystem) {
184         // for observation files, the satellite system is in column 40, and empty defaults to GPS
185         return SatelliteSystem.parseSatelliteSystem(line.substring(40, 41), defaultSatelliteSystem);
186     }
187 
188     /** {@inheritDoc} */
189     @Override
190     public void parseProgramRunByDate(final String line, final TimeScales timeScales) {
191         parseProgramRunByDate(ParsingUtils.parseString(line, 0, 20),
192                               ParsingUtils.parseString(line, 20, 20),
193                               ParsingUtils.parseString(line, 40, 20),
194                               timeScales);
195     }
196 
197     /** Set name of the antenna marker.
198      * @param markerName name of the antenna marker
199      */
200     public void setMarkerName(final String markerName) {
201         this.markerName = markerName;
202     }
203 
204     /** Get name of the antenna marker.
205      * @return name of the antenna marker
206      */
207     public String getMarkerName() {
208         return markerName;
209     }
210 
211     /** Set number of the antenna marker.
212      * @param markerNumber number of the antenna marker
213      */
214     public void setMarkerNumber(final String markerNumber) {
215         this.markerNumber = markerNumber;
216     }
217 
218     /** Get number of the antenna marker.
219      * @return number of the antenna marker
220      */
221     public String getMarkerNumber() {
222         return markerNumber;
223     }
224 
225     /** Set name of the observer.
226      * @param observerName name of the observer
227      */
228     public void setObserverName(final String observerName) {
229         this.observerName = observerName;
230     }
231 
232     /** Get name of the observer.
233      * @return name of the observer
234      */
235     public String getObserverName() {
236         return observerName;
237     }
238 
239     /**
240      * Setter for the agency name.
241      * @param agencyName the agency name to set
242      */
243     public void setAgencyName(final String agencyName) {
244         this.agencyName = agencyName;
245     }
246 
247     /** Get name of the agency.
248      * @return name of the agency
249      */
250     public String getAgencyName() {
251         return agencyName;
252     }
253 
254     /** Set the number of the antenna.
255      * @param antennaNumber number of the antenna
256      */
257     public void setAntennaNumber(final String antennaNumber) {
258         this.antennaNumber = antennaNumber;
259     }
260 
261     /** Get the number of the antenna.
262      * @return number of the antenna
263      */
264     public String getAntennaNumber() {
265         return antennaNumber;
266     }
267 
268     /** Set the type of the antenna.
269      * @param antennaType type of the antenna
270      */
271     public void setAntennaType(final String antennaType) {
272         this.antennaType = antennaType;
273     }
274 
275     /** Get the type of the antenna.
276      * @return type of the antenna
277      */
278     public String getAntennaType() {
279         return antennaType;
280     }
281 
282     /** Set the Approximate Marker Position.
283      * @param approxPos Approximate Marker Position
284      */
285     public void setApproxPos(final Vector3D approxPos) {
286         this.approxPos = approxPos;
287     }
288 
289     /** Get the Approximate Marker Position.
290      * @return Approximate Marker Position
291      */
292     public Vector3D getApproxPos() {
293         return approxPos;
294     }
295 
296     /** Set the antenna height.
297      * @param antennaHeight height of the antenna
298      */
299     public void setAntennaHeight(final double antennaHeight) {
300         this.antennaHeight = antennaHeight;
301     }
302 
303     /** Get the antenna height.
304      * @return height of the antenna
305      */
306     public double getAntennaHeight() {
307         return antennaHeight;
308     }
309 
310     /** Set the eccentricities of antenna center.
311      * @param eccentricities Eccentricities of antenna center
312      */
313     public void setEccentricities(final Vector2D eccentricities) {
314         this.eccentricities = eccentricities;
315     }
316 
317     /** Get the eccentricities of antenna center.
318      * @return Eccentricities of antenna center
319      */
320     public Vector2D getEccentricities() {
321         return eccentricities;
322     }
323 
324     /** Set the application flag for realtime-derived receiver clock offset.
325      * @param clockOffsetApplied application flag for realtime-derived receiver clock offset
326      * @since 12.1
327      */
328     public void setClockOffsetApplied(final boolean clockOffsetApplied) {
329         this.clockOffsetApplied = clockOffsetApplied;
330     }
331 
332     /** Get the application flag for realtime-derived receiver clock offset.
333      * @return application flag for realtime-derived receiver clock offset
334      * @since 12.1
335      */
336     public boolean getClockOffsetApplied() {
337         return clockOffsetApplied;
338     }
339 
340     /** Set the observation interval in seconds.
341      * @param interval Observation interval in seconds
342      */
343     public void setInterval(final double interval) {
344         this.interval = interval;
345     }
346 
347     /** Get the observation interval in seconds.
348      * @return Observation interval in seconds
349      */
350     public double getInterval() {
351         return interval;
352     }
353 
354     /** Set the time of First observation record.
355      * @param firstObs Time of First observation record
356      */
357     public void setTFirstObs(final AbsoluteDate firstObs) {
358         this.tFirstObs = firstObs;
359     }
360 
361     /** Get the time of First observation record.
362      * @return Time of First observation record
363      */
364     public AbsoluteDate getTFirstObs() {
365         return tFirstObs;
366     }
367 
368     /** Set the time of last observation record.
369      * @param lastObs Time of last observation record
370      */
371     public void setTLastObs(final AbsoluteDate lastObs) {
372         this.tLastObs = lastObs;
373     }
374 
375     /** Get the time of last observation record.
376      * @return Time of last observation record
377      */
378     public AbsoluteDate getTLastObs() {
379         return tLastObs;
380     }
381 
382     /** Set type of the antenna marker.
383      * @param markerType type of the antenna marker
384      */
385     public void setMarkerType(final String markerType) {
386         this.markerType = markerType;
387     }
388 
389     /** Get type of the antenna marker.
390      * @return type of the antenna marker
391      */
392     public String getMarkerType() {
393         return markerType;
394     }
395 
396     /** Set the position of antenna reference point for antenna on vehicle.
397      * @param refPoint Position of antenna reference point for antenna on vehicle
398      */
399     public void setAntennaReferencePoint(final Vector3D refPoint) {
400         this.antRefPoint = refPoint;
401     }
402 
403     /** Get the position of antenna reference point for antenna on vehicle.
404      * @return Position of antenna reference point for antenna on vehicle
405      */
406     public Vector3D getAntennaReferencePoint() {
407         return antRefPoint;
408     }
409 
410     /** Set satellite system for average phase center.
411      * @param phaseCenterSystem satellite system for average phase center
412      * @since 12.0
413      */
414     public void setPhaseCenterSystem(final SatelliteSystem phaseCenterSystem) {
415         this.phaseCenterSystem = phaseCenterSystem;
416     }
417 
418     /** Get satellite system for average phase center.
419      * @return satellite system for average phase center
420      * @since 12.0
421      */
422     public SatelliteSystem getPhaseCenterSystem() {
423         return phaseCenterSystem;
424     }
425 
426     /** Set the observation code of the average phasecenter position w/r to antenna reference point.
427      * @param observationCode Observation code of the average phasecenter position w/r to antenna reference point
428      */
429     public void setObservationCode(final String observationCode) {
430         this.observationCode = observationCode;
431     }
432 
433     /** Get the observation code of the average phasecenter position w/r to antenna reference point.
434      * @return Observation code of the average phasecenter position w/r to antenna reference point
435      */
436     public String getObservationCode() {
437         return observationCode;
438     }
439 
440     /** Set the antenna phasecenter.
441      * @param antennaPhaseCenter Antenna phasecenter
442      */
443     public void setAntennaPhaseCenter(final Vector3D antennaPhaseCenter) {
444         this.antennaPhaseCenter = antennaPhaseCenter;
445     }
446 
447     /** Get the antenna phasecenter.
448      * @return Antenna phasecenter
449      */
450     public Vector3D getAntennaPhaseCenter() {
451         return antennaPhaseCenter;
452     }
453 
454     /** Set the antenna B.Sight.
455      * @param antennaBSight Antenna B.Sight
456      */
457     public void setAntennaBSight(final Vector3D antennaBSight) {
458         this.antennaBSight = antennaBSight;
459     }
460 
461     /** Get the antenna B.Sight.
462      * @return Antenna B.Sight
463      */
464     public Vector3D getAntennaBSight() {
465         return antennaBSight;
466     }
467 
468     /** Set the azimuth of the zero direction of a fixed antenna.
469      * @param antennaAzimuth Azimuth of the zero direction of a fixed antenna
470      */
471     public void setAntennaAzimuth(final double antennaAzimuth) {
472         this.antennaAzimuth = antennaAzimuth;
473     }
474 
475     /** Get the azimuth of the zero direction of a fixed antenna.
476      * @return Azimuth of the zero direction of a fixed antenna
477      */
478     public double getAntennaAzimuth() {
479         return antennaAzimuth;
480     }
481 
482     /** Set the zero direction of antenna.
483      * @param antennaZeroDirection Zero direction of antenna
484      */
485     public void setAntennaZeroDirection(final Vector3D antennaZeroDirection) {
486         this.antennaZeroDirection = antennaZeroDirection;
487     }
488 
489     /** Get the zero direction of antenna.
490      * @return Zero direction of antenna
491      */
492     public Vector3D getAntennaZeroDirection() {
493         return antennaZeroDirection;
494     }
495 
496     /** Set the current center of mass of vehicle in body fixed coordinate system.
497      * @param centerMass Current center of mass of vehicle in body fixed coordinate system
498      */
499     public void setCenterMass(final Vector3D centerMass) {
500         this.centerMass = centerMass;
501     }
502 
503     /** Get the current center of mass of vehicle in body fixed coordinate system.
504      * @return Current center of mass of vehicle in body fixed coordinate system
505      */
506     public Vector3D getCenterMass() {
507         return centerMass;
508     }
509 
510     /** Set the unit of the carrier to noise ratio observables.
511      * @param signalStrengthUnit Unit of the carrier to noise ratio observables
512      */
513     public void setSignalStrengthUnit(final String signalStrengthUnit) {
514         this.signalStrengthUnit = signalStrengthUnit;
515     }
516 
517     /** Get the unit of the carrier to noise ratio observables.
518      * @return Unit of the carrier to noise ratio observables
519      */
520     public String getSignalStrengthUnit() {
521         return signalStrengthUnit;
522     }
523 
524     /** Add phase shift correction used to generate phases consistent w/r to cycle shifts.
525      * @param phaseShiftCorrection phase shift correction used to generate phases consistent w/r to cycle shifts
526      */
527     public void addPhaseShiftCorrection(final PhaseShiftCorrection phaseShiftCorrection) {
528         phaseShiftCorrections.add(phaseShiftCorrection);
529     }
530 
531     /** Get the list of phase shift correction used to generate phases consistent w/r to cycle shifts.
532      * @return List of phase shift correction used to generate phases consistent w/r to cycle shifts
533      */
534     public List<PhaseShiftCorrection> getPhaseShiftCorrections() {
535         return Collections.unmodifiableList(phaseShiftCorrections);
536     }
537 
538     /** Add scale factor correction.
539      * @param satelliteSystem system to which this scaling factor applies
540      * @param scaleFactorCorrection scale factor correction
541      */
542     public void addScaleFactorCorrection(final SatelliteSystem satelliteSystem, final ScaleFactorCorrection scaleFactorCorrection) {
543         final List<ScaleFactorCorrection> sfc;
544         synchronized (scaleFactorCorrections) {
545             sfc = scaleFactorCorrections.computeIfAbsent(satelliteSystem, k -> new ArrayList<>());
546         }
547         sfc.add(scaleFactorCorrection);
548     }
549 
550     /** Get the list of scale factor correction.
551      * @param satelliteSystem system to which this scaling factor applies
552      * @return List of scale factor correction
553      */
554     public List<ScaleFactorCorrection> getScaleFactorCorrections(final SatelliteSystem satelliteSystem) {
555         final List<ScaleFactorCorrection> sfc = scaleFactorCorrections.get(satelliteSystem);
556         return sfc == null ? Collections.emptyList() : Collections.unmodifiableList(sfc);
557     }
558 
559     /** Add GLONASS satellite/channel association.
560      * @param glonassChannel GLONASS satellite/channel association
561      * @since 12.0
562      */
563     public void addGlonassChannel(final GlonassSatelliteChannel glonassChannel) {
564         glonassChannels.add(glonassChannel);
565     }
566 
567     /** Get the list of GLONASS satellite/channel associations.
568      * @return List of GLONASS satellite/channel associations
569      * @since 12.0
570      */
571     public List<GlonassSatelliteChannel> getGlonassChannels() {
572         return Collections.unmodifiableList(glonassChannels);
573     }
574 
575     /** Set number of satellites.
576      * @param nbSat number of satellites
577      * @since 12.0
578      */
579     public void setNbSat(final int nbSat) {
580         this.nbSat = nbSat;
581     }
582 
583     /** Get number of satellites.
584      * @return number of satellites
585      * @since 12.0
586      */
587     public int getNbSat() {
588         return nbSat;
589     }
590 
591     /** Set number of observations for a satellite.
592      * @param sat satellite
593      * @param type observation type
594      * @param nbObs number of observations of this type for this satellite
595      * @since 12.0
596      */
597     public void setNbObsPerSatellite(final SatInSystem sat, final String type, final int nbObs) {
598         final Map<String, Integer> satNbObs;
599         synchronized (nbObsPerSat) {
600             satNbObs = nbObsPerSat.computeIfAbsent(sat, k -> new HashMap<>());
601         }
602         satNbObs.put(type, nbObs);
603     }
604 
605     /** Get an unmodifiable view of the map of number of observations per satellites.
606      * @return unmodifiable view of the map of number of observations per satellites
607      * @since 12.0
608      */
609     public Map<SatInSystem, Map<String, Integer>> getNbObsPerSat() {
610         return Collections.unmodifiableMap(nbObsPerSat);
611     }
612 
613     /** Set the code phase bias correction for GLONASS {@link org.orekit.gnss.PredefinedObservationType#C1C} signal.
614      * @param c1cCodePhaseBias code phase bias correction for GLONASS {@link org.orekit.gnss.PredefinedObservationType#C1C} signal
615      * @since 12.0
616      */
617     public void setC1cCodePhaseBias(final double c1cCodePhaseBias) {
618         this.c1cCodePhaseBias = c1cCodePhaseBias;
619     }
620 
621     /** Get the code phase bias correction for GLONASS {@link org.orekit.gnss.PredefinedObservationType#C1C} signal.
622      * @return code phase bias correction for GLONASS {@link org.orekit.gnss.PredefinedObservationType#C1C} signal
623      * @since 12.0
624      */
625     public double getC1cCodePhaseBias() {
626         return c1cCodePhaseBias;
627     }
628 
629     /** Set the code phase bias correction for GLONASS {@link org.orekit.gnss.PredefinedObservationType#C1P} signal.
630      * @param c1pCodePhaseBias code phase bias correction for GLONASS {@link org.orekit.gnss.PredefinedObservationType#C1P} signal
631      * @since 12.0
632      */
633     public void setC1pCodePhaseBias(final double c1pCodePhaseBias) {
634         this.c1pCodePhaseBias = c1pCodePhaseBias;
635     }
636 
637     /** Get the code phase bias correction for GLONASS {@link org.orekit.gnss.PredefinedObservationType#C1P} signal.
638      * @return code phase bias correction for GLONASS {@link org.orekit.gnss.PredefinedObservationType#C1P} signal
639      * @since 12.0
640      */
641     public double getC1pCodePhaseBias() {
642         return c1pCodePhaseBias;
643     }
644 
645     /** Set the code phase bias correction for GLONASS {@link org.orekit.gnss.PredefinedObservationType#C2C} signal.
646      * @param c2cCodePhaseBias code phase bias correction for GLONASS {@link org.orekit.gnss.PredefinedObservationType#C2C} signal
647      * @since 12.0
648      */
649     public void setC2cCodePhaseBias(final double c2cCodePhaseBias) {
650         this.c2cCodePhaseBias = c2cCodePhaseBias;
651     }
652 
653     /** Get the code phase bias correction for GLONASS {@link org.orekit.gnss.PredefinedObservationType#C2C} signal.
654      * @return code phase bias correction for GLONASS {@link org.orekit.gnss.PredefinedObservationType#C2C} signal
655      * @since 12.0
656      */
657     public double getC2cCodePhaseBias() {
658         return c2cCodePhaseBias;
659     }
660 
661     /** Set the code phase bias correction for GLONASS {@link org.orekit.gnss.PredefinedObservationType#C2P} signal.
662      * @param c2pCodePhaseBias code phase bias correction for GLONASS {@link org.orekit.gnss.PredefinedObservationType#C2P} signal
663      * @since 12.0
664      */
665     public void setC2pCodePhaseBias(final double c2pCodePhaseBias) {
666         this.c2pCodePhaseBias = c2pCodePhaseBias;
667     }
668 
669     /** Get the code phase bias correction for GLONASS {@link org.orekit.gnss.PredefinedObservationType#C2P} signal.
670      * @return code phase bias correction for GLONASS {@link org.orekit.gnss.PredefinedObservationType#C2P} signal
671      * @since 12.0
672      */
673     public double getC2pCodePhaseBias() {
674         return c2pCodePhaseBias;
675     }
676 
677     /** {@inheritDoc} */
678     @Override
679     public void checkType(final String line, final String name) {
680         checkType(line, 20, name);
681     }
682 
683     /** {@inheritDoc} */
684     @Override
685     public int getLabelIndex() {
686         return LABEL_INDEX;
687     }
688 
689     /** {@inheritDoc} */
690     @Override
691     public boolean matchFound(final Label label, final String line) {
692         final int max = getLabelIndex();
693         return line.length() >= max && label.matches(line.substring(max).trim());
694     }
695 
696 }