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  
18  package org.orekit.files.ccsds.ndm.tdm;
19  
20  import java.util.ArrayList;
21  import java.util.List;
22  import java.util.Map;
23  import java.util.Optional;
24  import java.util.TreeMap;
25  
26  import org.orekit.annotation.Nullable;
27  import org.orekit.errors.OrekitException;
28  import org.orekit.errors.OrekitMessages;
29  import org.orekit.files.ccsds.definitions.CcsdsFrameMapper;
30  import org.orekit.files.ccsds.definitions.FrameFacade;
31  import org.orekit.files.ccsds.section.Metadata;
32  import org.orekit.frames.Frame;
33  import org.orekit.time.AbsoluteDate;
34  import org.orekit.utils.Constants;
35  
36  /** The TDMMetadata class gathers the meta-data present in the Tracking Data Message (TDM).<p>
37   *  References:<p>
38   *  <a href="https://public.ccsds.org/Pubs/503x0b1c1.pdf">CCSDS 503.0-B-1 recommended standard</a>. §3.3 ("Tracking Data Message", Blue Book, Version 1.0, November 2007).
39   *
40   * @author Maxime Journot
41   * @since 9.0
42   */
43  public class TdmMetadata extends Metadata {
44  
45      /** Identifier for the tracking data. */
46      @Nullable
47      private String trackId;
48  
49      /** List of data types in the data section. */
50      private List<ObservationType> dataTypes;
51  
52      /** Start epoch of total time span covered by observations block. */
53      @Nullable
54      private AbsoluteDate startTime;
55  
56      /** End epoch of total time span covered by observations block. */
57      @Nullable
58      private AbsoluteDate stopTime;
59  
60      /** Map of participants in the tracking data session (minimum 1 and up to 5).<p>
61       *  Participants may include ground stations, spacecraft, and/or quasars.<p>
62       *  Participants represent the classical transmitting parties, transponding parties, and receiving parties.
63       */
64      private Map<Integer, String> participants;
65  
66      /** Tracking mode. */
67      @Nullable
68      private TrackingMode mode;
69  
70      /** The path shall reflect the signal path by listing the index of each participant
71       *  in order, separated by commas, with no inserted white space.<p>
72       *  The integers 1, 2, 3, 4, 5 used to specify the signal path correlate
73       *  with the indices of the PARTICIPANT keywords.<p>
74       *  The first entry in the PATH shall be the transmit participant.<p>
75       *  The non-indexed 'PATH' keyword shall be used if the MODE is 'SEQUENTIAL'.<p>
76       *  The indexed 'PATH_1' and 'PATH_2' keywords shall be used where the MODE is 'SINGLE_DIFF'.
77       */
78      @Nullable
79      private int[] path;
80  
81      /** Path 1 (see above). */
82      @Nullable
83      private int[] path1;
84  
85      /** Path 2 (see above). */
86      @Nullable
87      private int[] path2;
88  
89      /** Map of external ephemeris names for participants (minimum 1 and up to 5). */
90      private Map<Integer, String> ephemerisNames;
91  
92      /** Frequency band for transmitted frequencies. */
93      @Nullable
94      private String transmitBand;
95  
96      /** Frequency band for received frequencies. */
97      @Nullable
98      private String receiveBand;
99  
100     /** Turn-around ratio numerator.<p>
101      *  Numerator of the turn-around ratio that is necessary to calculate the coherent downlink from the uplink frequency.
102      */
103     @Nullable
104     private Integer turnaroundNumerator;
105 
106     /** Turn-around ratio denominator .*/
107     @Nullable
108     private Integer turnaroundDenominator;
109 
110     /** Timetag reference.<p>
111      *  Provides a reference for time tags in the tracking data.<p>
112      *  It indicates whether the timetag associated with the data is the transmit time or the receive time.
113      */
114     @Nullable
115     private TimetagReference timetagRef;
116 
117     /** Integration interval. <p>
118      *  Provides the Doppler count time in seconds for Doppler data or for the creation
119      *  of normal points.
120      */
121     @Nullable
122     private Double integrationInterval;
123 
124     /** Integration reference.<p>
125      *  Used in conjunction with timetag reference and integration interval.<p>
126      *  Indicates whether the timetag represents the start, middle or end of the integration interval.
127      */
128     @Nullable
129     private IntegrationReference integrationRef;
130 
131     /** Frequency offset.<p>
132      *  A frequency in Hz that must be added to every RECEIVE_FREQ to reconstruct it.
133      */
134     @Nullable
135     private Double freqOffset;
136 
137     /** Range mode. */
138     @Nullable
139     private RangeMode rangeMode;
140 
141     /** Raw range modulus (in RangeUnits). */
142     @Nullable
143     private Double rawRangeModulus;
144 
145     /** Range units. */
146     @Nullable
147     private RangeUnits rangeUnits;
148 
149     /** Angle type. */
150     @Nullable
151     private AngleType angleType;
152 
153     /** Reference frame in which data are given: used in combination with ANGLE_TYPE=RADEC. */
154     @Nullable
155     private FrameFacade referenceFrame;
156 
157     /** The interpolation method to be used. */
158     @Nullable
159     private String interpolationMethod;
160 
161     /** The interpolation degree. */
162     @Nullable
163     private Integer interpolationDegree;
164 
165     /** Bias that was added to Doppler count in the data section. */
166     @Nullable
167     private Double doppplerCountBias;
168 
169     /** Scaled by which Doppler count was multiplied in the data section. */
170     @Nullable
171     private Double dopplerCountScale;
172 
173     /** Indicator for occurred rollover in Doppler count. */
174     @Nullable
175     private Boolean doppplerCountRollover;
176 
177     /** Transmit delays map.<p>
178      *  Specifies a fixed interval of time, in seconds, for the signal to travel from the transmitting
179      *  electronics to the transmit point. Each item in the list corresponds to the each participants.
180      */
181     private Map<Integer, Double> transmitDelays;
182 
183     /** Receive delays list.<p>
184      *  Specifies a fixed interval of time, in seconds, for the signal to travel from the tracking
185      *  point to the receiving electronics. Each item in the list corresponds to the each participants.
186      */
187     private Map<Integer, Double> receiveDelays;
188 
189     /** Data quality. */
190     @Nullable
191     private DataQuality dataQuality;
192 
193     /** Correction angle 1.<p>
194      *  Angle correction that has been added or should be added to the ANGLE_1 data.
195      */
196     @Nullable
197     private Double correctionAngle1;
198 
199     /** Correction angle 2.<p>
200      *  Angle correction that has been added or should be added to the ANGLE_2 data.
201      */
202     @Nullable
203     private Double correctionAngle2;
204 
205     /** Correction Doppler.<p>
206      *  Doppler correction that has been added or should be added to the DOPPLER data.
207      */
208     @Nullable
209     private Double correctionDoppler;
210 
211     /** Correction magnitude.<p>
212      *  Magnitude correction that has been added or should be added to the MAGNITUDE data.
213      */
214     @Nullable
215     private Double correctionMagnitude;
216 
217     /** Raw correction Range in {@link #getRangeUnits()}.<p>
218      *  Range correction that has been added or should be added to the RANGE data.
219      */
220     @Nullable
221     private Double rawCorrectionRange;
222 
223     /** Correction radar cross section.<p>
224      *  Radar cross section correction that has been added or should be added to the RCS data.
225      */
226     @Nullable
227     private Double correctionRcs;
228 
229     /** Correction receive.<p>
230      *  Receive correction that has been added or should be added to the RECEIVE data.
231      */
232     @Nullable
233     private Double correctionReceive;
234 
235     /** Correction transmit.<p>
236      *  Transmit correction that has been added or should be added to the TRANSMIT data.
237      */
238     @Nullable
239     private Double correctionTransmit;
240 
241     /** Yearly aberration correction.<p>
242      *  Yearly correction that has been added or should be added to the ANGLE data.
243      */
244     @Nullable
245     private Double correctionAberrationYearly;
246 
247     /** Diurnal aberration correction.<p>
248      *  Diurnl correction that has been added or should be added to the ANGLE data.
249      */
250     @Nullable
251     private Double correctionAberrationDiurnal;
252 
253     /** Correction applied ? YES/NO<p>
254      *  Indicate whethers or not the values associated with the CORRECTION_* keywords have been
255      *  applied to the tracking data.
256      */
257     @Nullable
258     private CorrectionApplied correctionsApplied;
259 
260     /**
261      * Create a new TDM meta-data.
262      *
263      * @param frameMapper for creating an Orekit {@link Frame}.
264      * @since 13.1.5
265      */
266     public TdmMetadata(final CcsdsFrameMapper frameMapper) {
267         super(null, frameMapper);
268         dataTypes      = new ArrayList<>();
269         participants   = new TreeMap<>();
270         ephemerisNames = new TreeMap<>();
271         transmitDelays = new TreeMap<>();
272         receiveDelays  = new TreeMap<>();
273     }
274 
275     /** {@inheritDoc} */
276     @Override
277     public void validate(final double version) {
278         super.validate(version);
279         if (participants.isEmpty()) {
280             throw new OrekitException(OrekitMessages.UNINITIALIZED_VALUE_FOR_KEY, TdmMetadataKey.PARTICIPANT_1);
281         }
282     }
283 
284     /** Getter for the tracking data identifier.
285      * @return tracking data identifier
286      */
287     public Optional<String> getTrackId() {
288         return Optional.ofNullable(trackId);
289     }
290 
291     /** Setter for the tracking data identifier.
292      * @param trackId tracking data identifier
293      */
294     public void setTrackId(final String trackId) {
295         refuseFurtherComments();
296         this.trackId = trackId;
297     }
298 
299     /** Getter for the data types in the data section.
300      * @return data types in the data section
301      */
302     public List<ObservationType> getDataTypes() {
303         return dataTypes;
304     }
305 
306     /** Setter for the data types in the data section.
307      * @param dataTypes data types in the data section
308      */
309     public void setDataTypes(final List<ObservationType> dataTypes) {
310         refuseFurtherComments();
311         this.dataTypes = new ArrayList<>();
312         this.dataTypes.addAll(dataTypes);
313     }
314 
315     /** Getter for the startTime.
316      * @return the startTime
317      */
318     public Optional<AbsoluteDate> getStartTime() {
319         return Optional.ofNullable(startTime);
320     }
321 
322     /** Setter for the startTime.
323      * @param startTime the startTime to set
324      */
325     public void setStartTime(final AbsoluteDate startTime) {
326         refuseFurtherComments();
327         this.startTime = startTime;
328     }
329 
330     /** Getter for the stopTime.
331      * @return the stopTime
332      */
333     public Optional<AbsoluteDate> getStopTime() {
334         return Optional.ofNullable(stopTime);
335     }
336 
337     /** Setter for the stopTime.
338      * @param stopTime the stopTime to set
339      */
340     public void setStopTime(final AbsoluteDate stopTime) {
341         refuseFurtherComments();
342         this.stopTime = stopTime;
343     }
344 
345     /** Getter for the participants.
346      * @return the participants
347      */
348     public Map<Integer, String> getParticipants() {
349         return participants;
350     }
351 
352     /** Setter for the participants.
353      * @param participants the participants to set
354      */
355     public void setParticipants(final Map<Integer, String> participants) {
356         refuseFurtherComments();
357         this.participants = new TreeMap<>();
358         this.participants.putAll(participants);
359     }
360 
361     /** Adds a participant to the list.
362      * @param participantNumber the number of the participant to add
363      * @param participant the name of the participant to add
364      */
365     public void addParticipant(final int participantNumber, final String participant) {
366         refuseFurtherComments();
367         this.participants.put(participantNumber, participant);
368     }
369 
370     /** Getter for the mode.
371      * @return the mode
372      */
373     public Optional<TrackingMode> getMode() {
374         return Optional.ofNullable(mode);
375     }
376 
377     /** Setter for the mode.
378      * @param mode the mode to set
379      */
380     public void setMode(final TrackingMode mode) {
381         refuseFurtherComments();
382         this.mode = mode;
383     }
384 
385     /** Getter for the path.
386      * @return the path
387      */
388     public Optional<int[]> getPath() {
389         return Optional.ofNullable(path).map(int[]::clone);
390     }
391 
392     /** Setter for the path.
393      * @param path the path to set
394      */
395     public void setPath(final int[] path) {
396         refuseFurtherComments();
397         this.path = path == null ? null : path.clone();
398     }
399 
400     /** Getter for the path1.
401      * @return the path1
402      */
403     public Optional<int[]> getPath1() {
404         return Optional.ofNullable(path1).map(int[]::clone);
405     }
406 
407     /** Setter for the path1.
408      * @param path1 the path1 to set
409      */
410     public void setPath1(final int[] path1) {
411         refuseFurtherComments();
412         this.path1 = path1 == null ? null : path1.clone();
413     }
414 
415     /** Getter for the path2.
416      * @return the path2
417      */
418     public Optional<int[]> getPath2() {
419         return Optional.ofNullable(path2).map(int[]::clone);
420     }
421 
422     /** Setter for the path2.
423      * @param path2 the path2 to set
424      */
425     public void setPath2(final int[] path2) {
426         refuseFurtherComments();
427         this.path2 = path2 == null ? null : path2.clone();
428     }
429 
430     /** Getter for external ephemeris names for participants.
431      * @return external ephemeris names for participants
432      */
433     public Map<Integer, String> getEphemerisNames() {
434         return ephemerisNames;
435     }
436 
437     /** Setter for the external ephemeris names for participants.
438      * @param ephemerisNames external ephemeris names for participants
439      */
440     public void setEphemerisNames(final Map<Integer, String> ephemerisNames) {
441         refuseFurtherComments();
442         this.ephemerisNames = new TreeMap<>();
443         this.ephemerisNames.putAll(ephemerisNames);
444     }
445 
446     /** Adds an ephemeris name to the list.
447      * @param participantNumber the number of the participant
448      * @param ephemerisName name of the ephemeris for the participant
449      */
450     public void addEphemerisName(final int participantNumber, final String ephemerisName) {
451         refuseFurtherComments();
452         this.ephemerisNames.put(participantNumber, ephemerisName);
453     }
454 
455     /** Getter for the transmitBand.
456      * @return the transmitBand
457      */
458     public Optional<String> getTransmitBand() {
459         return Optional.ofNullable(transmitBand);
460     }
461 
462     /** Setter for the transmitBand.
463      * @param transmitBand the transmitBand to set
464      */
465     public void setTransmitBand(final String transmitBand) {
466         refuseFurtherComments();
467         this.transmitBand =  transmitBand;
468     }
469 
470     /** Getter for the receiveBand.
471      * @return the receiveBand
472      */
473     public Optional<String> getReceiveBand() {
474         return Optional.ofNullable(receiveBand);
475     }
476 
477     /** Setter for the receiveBand.
478      * @param receiveBand the receiveBand to set
479      */
480     public void setReceiveBand(final String receiveBand) {
481         refuseFurtherComments();
482         this.receiveBand = receiveBand;
483     }
484 
485     /** Getter for the turnaroundNumerator.
486      * @return the turnaroundNumerator
487      */
488     public Optional<Integer> getTurnaroundNumerator() {
489         return Optional.ofNullable(turnaroundNumerator);
490     }
491 
492     /** Setter for the turnaroundNumerator.
493      * @param turnaroundNumerator the turnaroundNumerator to set
494      */
495     public void setTurnaroundNumerator(final int turnaroundNumerator) {
496         refuseFurtherComments();
497         this.turnaroundNumerator = turnaroundNumerator;
498     }
499 
500     /** Getter for the turnaroundDenominator.
501      * @return the turnaroundDenominator
502      */
503     public Optional<Integer> getTurnaroundDenominator() {
504         return Optional.ofNullable(turnaroundDenominator);
505     }
506 
507     /** Setter for the turnaroundDenominator.
508      * @param turnaroundDenominator the turnaroundDenominator to set
509      */
510     public void setTurnaroundDenominator(final int turnaroundDenominator) {
511         refuseFurtherComments();
512         this.turnaroundDenominator = turnaroundDenominator;
513     }
514 
515     /** Getter for the timetagRef.
516      * @return the timetagRef
517      */
518     public Optional<TimetagReference> getTimetagRef() {
519         return Optional.ofNullable(timetagRef);
520     }
521 
522     /** Setter for the timetagRef.
523      * @param timetagRef the timetagRef to set
524      */
525     public void setTimetagRef(final TimetagReference timetagRef) {
526         refuseFurtherComments();
527         this.timetagRef = timetagRef;
528     }
529 
530     /** Getter for the integrationInterval.
531      * @return the integrationInterval
532      */
533     public Optional<Double> getIntegrationInterval() {
534         return Optional.ofNullable(integrationInterval);
535     }
536 
537     /** Setter for the integrationInterval.
538      * @param integrationInterval the integrationInterval to set
539      */
540     public void setIntegrationInterval(final double integrationInterval) {
541         refuseFurtherComments();
542         this.integrationInterval = integrationInterval;
543     }
544 
545     /** Getter for the integrationRef.
546      * @return the integrationRef
547      */
548     public Optional<IntegrationReference> getIntegrationRef() {
549         return Optional.ofNullable(integrationRef);
550     }
551 
552     /** Setter for the integrationRef.
553      * @param integrationRef the integrationRef to set
554      */
555     public void setIntegrationRef(final IntegrationReference integrationRef) {
556         refuseFurtherComments();
557         this.integrationRef = integrationRef;
558     }
559 
560     /** Getter for the freqOffset.
561      * @return the freqOffset
562      */
563     public Optional<Double> getFreqOffset() {
564         return Optional.ofNullable(freqOffset);
565     }
566 
567     /** Setter for the freqOffset.
568      * @param freqOffset the freqOffset to set
569      */
570     public void setFreqOffset(final double freqOffset) {
571         refuseFurtherComments();
572         this.freqOffset = freqOffset;
573     }
574 
575     /** Getter for the rangeMode.
576      * @return the rangeMode
577      */
578     public Optional<RangeMode> getRangeMode() {
579         return Optional.ofNullable(rangeMode);
580     }
581 
582     /** Setter for the rangeMode.
583      * @param rangeMode the rangeMode to set
584      */
585     public void setRangeMode(final RangeMode rangeMode) {
586         refuseFurtherComments();
587         this.rangeMode = rangeMode;
588     }
589 
590     /** Getter for the range modulus in meters.
591      * @param converter converter to use if {@link #getRangeUnits() range units}
592      * are set to {@link RangeUnits#RU}
593      * @return the range modulus in meters
594      */
595     public Optional<Double> getRangeModulus(final RangeUnitsConverter converter) {
596         if (rangeUnits == RangeUnits.km) {
597             return Optional.ofNullable(rawRangeModulus * 1000);
598         } else if (rangeUnits == RangeUnits.s) {
599             return Optional.ofNullable(rawRangeModulus * Constants.SPEED_OF_LIGHT);
600         } else {
601             return Optional.ofNullable(converter.ruToMeters(this, startTime, rawRangeModulus));
602         }
603     }
604 
605     /** Getter for the raw range modulus.
606      * @return the raw range modulus in range units
607      */
608     public Optional<Double> getRawRangeModulus() {
609         return Optional.ofNullable(rawRangeModulus);
610     }
611 
612     /** Setter for the raw range modulus.
613      * @param rawRangeModulus the raw range modulus to set
614      */
615     public void setRawRangeModulus(final double rawRangeModulus) {
616         refuseFurtherComments();
617         this.rawRangeModulus = rawRangeModulus;
618     }
619 
620     /** Getter for the rangeUnits.
621      * @return the rangeUnits
622      */
623     public Optional<RangeUnits> getRangeUnits() {
624         return Optional.ofNullable(rangeUnits);
625     }
626 
627     /** Setter for the rangeUnits.
628      * @param rangeUnits the rangeUnits to set
629      */
630     public void setRangeUnits(final RangeUnits rangeUnits) {
631         refuseFurtherComments();
632         this.rangeUnits = rangeUnits;
633     }
634 
635     /** Getter for angleType.
636      * @return the angleType
637      */
638     public Optional<AngleType> getAngleType() {
639         return Optional.ofNullable(angleType);
640     }
641 
642     /** Setter for the angleType.
643      * @param angleType the angleType to set
644      */
645     public void setAngleType(final AngleType angleType) {
646         refuseFurtherComments();
647         this.angleType = angleType;
648     }
649 
650     /** Get the the value of {@code REFERENCE_FRAME} as an Orekit {@link Frame}.
651      * @return The reference frame specified by the {@code REFERENCE_FRAME} keyword.
652      * @see #getRadecFrame()
653      */
654     public Optional<FrameFacade> getReferenceFrame() {
655         return  Optional.ofNullable(referenceFrame);
656     }
657 
658     /** Set the reference frame in which data are given: used for RADEC tracking data.
659      * @param referenceFrame the reference frame to be set
660      */
661     public void setReferenceFrame(final FrameFacade referenceFrame) {
662         refuseFurtherComments();
663         this.referenceFrame = referenceFrame;
664     }
665 
666     /**
667      * Get the reference frame used right ascension and declination
668      * measurements.
669      *
670      * <p>Note that CCSDS 503 says "The origin (center) of the
671      * reference frame is assumed to be at the antenna reference point", but
672      * since the TDM does not provide the location of the antenna reference
673      * point the returned frame is not centered at the antenna reference point.
674      * Therefore, only the orientation of the returned frame is significant.
675      *
676      * @return Orientation of the frame used for RADEC observations.
677      * @see #getReferenceFrame()
678      * @since 13.1.5
679      */
680     public Optional<Frame> getRadecFrame() {
681         // TDM doesn't allow specifying an epoch
682         return getReferenceFrame().isEmpty() ?
683                Optional.empty() :
684                Optional.ofNullable(getFrameMapper().buildCcsdsFrame(getReferenceFrame().get(), null));
685     }
686 
687     /**
688      * Get the interpolation method to be used.
689      *
690      * @return the interpolation method
691      */
692     public Optional<String> getInterpolationMethod() {
693         return Optional.ofNullable(interpolationMethod);
694     }
695 
696     /**
697      * Set the interpolation method to be used.
698      * @param interpolationMethod the interpolation method to be set
699      */
700     public void setInterpolationMethod(final String interpolationMethod) {
701         refuseFurtherComments();
702         this.interpolationMethod = interpolationMethod;
703     }
704 
705     /**
706      * Get the interpolation degree.
707      * @return the interpolation degree
708      */
709     public Optional<Integer> getInterpolationDegree() {
710         return Optional.ofNullable(interpolationDegree);
711     }
712 
713     /**
714      * Set the interpolation degree.
715      * @param interpolationDegree the interpolation degree to be set
716      */
717     public void setInterpolationDegree(final int interpolationDegree) {
718         refuseFurtherComments();
719         this.interpolationDegree = interpolationDegree;
720     }
721 
722     /**
723      * Get the Doppler count bias.
724      * @return the Doppler count bias in Hz
725      */
726     public Optional<Double> getDopplerCountBias() {
727         return Optional.ofNullable(doppplerCountBias);
728     }
729 
730     /**
731      * Set the Doppler count bias.
732      * @param dopplerCountBias Doppler count bias in Hz to set
733      */
734     public void setDopplerCountBias(final double dopplerCountBias) {
735         refuseFurtherComments();
736         this.doppplerCountBias = dopplerCountBias;
737     }
738 
739     /**
740      * Get the Doppler count scale.
741      * @return the Doppler count scale
742      */
743     public Optional<Double> getDopplerCountScale() {
744         return Optional.ofNullable(dopplerCountScale);
745     }
746 
747     /**
748      * Set the Doppler count Scale.
749      * @param dopplerCountScale Doppler count scale to set
750      */
751     public void setDopplerCountScale(final double dopplerCountScale) {
752         refuseFurtherComments();
753         this.dopplerCountScale = dopplerCountScale;
754     }
755 
756     /**
757      * Check if there is a Doppler count rollover.
758      * @return an optional that is true if there is a Doppler count rollover
759      */
760     public Optional<Boolean> hasDopplerCountRollover() {
761         return Optional.ofNullable(doppplerCountRollover);
762     }
763 
764     /**
765      * Set the indicator for Doppler count rollover.
766      * @param dopplerCountRollover indicator for Doppler count rollover
767      */
768     public void setDopplerCountRollover(final boolean dopplerCountRollover) {
769         refuseFurtherComments();
770         this.doppplerCountRollover = dopplerCountRollover;
771     }
772 
773     /** Getter for the transmitDelays.
774      * @return the transmitDelays
775      */
776     public Map<Integer, Double> getTransmitDelays() {
777         return transmitDelays;
778     }
779 
780     /** Setter for the transmitDelays.
781      * @param transmitDelays the transmitDelays to set
782      */
783     public void setTransmitDelays(final Map<Integer, Double> transmitDelays) {
784         refuseFurtherComments();
785         this.transmitDelays = new TreeMap<>();
786         this.transmitDelays.putAll(transmitDelays);
787     }
788 
789     /** Adds a transmit delay to the list.
790      *  @param participantNumber the number of the participants for which the transmit delay is given
791      *  @param transmitDelay the transmit delay value to add
792      */
793     public void addTransmitDelay(final int participantNumber, final double transmitDelay) {
794         refuseFurtherComments();
795         this.transmitDelays.put(participantNumber, transmitDelay);
796     }
797 
798     /** Getter for receiveDelays.
799      * @return the receiveDelays
800      */
801     public Map<Integer, Double> getReceiveDelays() {
802         return receiveDelays;
803     }
804 
805     /** Setter for the receiveDelays.
806      * @param receiveDelays the receiveDelays to set
807      */
808     public void setReceiveDelays(final Map<Integer, Double> receiveDelays) {
809         refuseFurtherComments();
810         this.receiveDelays = new TreeMap<>();
811         this.receiveDelays.putAll(receiveDelays);
812     }
813 
814     /** Adds a receive delay to the list.
815      * @param participantNumber the number of the participants for which the receive delay is given
816      * @param receiveDelay the receive delay value to add
817      */
818     public void addReceiveDelay(final int participantNumber, final double receiveDelay) {
819         refuseFurtherComments();
820         this.receiveDelays.put(participantNumber, receiveDelay);
821     }
822     /** Getter for the dataQuality.
823      * @return the dataQuality
824      */
825     public Optional<DataQuality> getDataQuality() {
826         return Optional.ofNullable(dataQuality);
827     }
828 
829     /** Setter for the dataQuality.
830      * @param dataQuality the dataQuality to set
831      */
832     public void setDataQuality(final DataQuality dataQuality) {
833         refuseFurtherComments();
834         this.dataQuality = dataQuality;
835     }
836 
837     /** Getter for the correctionAngle1.
838      * @return the correctionAngle1 (in radians)
839      */
840     public Optional<Double> getCorrectionAngle1() {
841         return Optional.ofNullable(correctionAngle1);
842     }
843 
844     /** Setter for the correctionAngle1.
845      * @param correctionAngle1 the correctionAngle1 to set (in radians)
846      */
847     public void setCorrectionAngle1(final double correctionAngle1) {
848         refuseFurtherComments();
849         this.correctionAngle1 = correctionAngle1;
850     }
851 
852     /** Getter for the correctionAngle2.
853      * @return the correctionAngle2 (in radians)
854      */
855     public Optional<Double> getCorrectionAngle2() {
856         return Optional.ofNullable(correctionAngle2);
857     }
858 
859     /** Setter for the correctionAngle2.
860      * @param correctionAngle2 the correctionAngle2 to set (in radians)
861      */
862     public void setCorrectionAngle2(final double correctionAngle2) {
863         refuseFurtherComments();
864         this.correctionAngle2 = correctionAngle2;
865     }
866 
867     /** Getter for the correctionDoppler.
868      * @return the correctionDoppler (in m/s)
869      */
870     public Optional<Double> getCorrectionDoppler() {
871         return Optional.ofNullable(correctionDoppler);
872     }
873 
874     /** Setter for the correctionDoppler.
875      * @param correctionDoppler the correctionDoppler to set (in m/s)
876      */
877     public void setCorrectionDoppler(final double correctionDoppler) {
878         refuseFurtherComments();
879         this.correctionDoppler = correctionDoppler;
880     }
881 
882     /** Getter for the magnitude correction.
883      * @return the magnitude correction
884      */
885     public Optional<Double> getCorrectionMagnitude() {
886         return Optional.ofNullable(correctionMagnitude);
887     }
888 
889     /** Setter for the magnitude correction.
890      * @param correctionMagnitude the magnitude correction to set
891      */
892     public void setCorrectionMagnitude(final double correctionMagnitude) {
893         refuseFurtherComments();
894         this.correctionMagnitude = correctionMagnitude;
895     }
896 
897     /** Getter for the raw correction for range in meters.
898      * @param converter converter to use if {@link #getRangeUnits() range units}
899      * are set to {@link RangeUnits#RU}
900      * @return the raw correction for range in meters
901      */
902     public Optional<Double> getCorrectionRange(final RangeUnitsConverter converter) {
903         if (rangeUnits == RangeUnits.km) {
904             return Optional.ofNullable(rawCorrectionRange * 1000);
905         } else if (rangeUnits == RangeUnits.s) {
906             return Optional.ofNullable(rawCorrectionRange * Constants.SPEED_OF_LIGHT);
907         } else {
908             return Optional.ofNullable(converter.ruToMeters(this, startTime, rawCorrectionRange));
909         }
910     }
911 
912     /** Getter for the raw correction for range.
913      * @return the raw correction for range (in {@link #getRangeUnits()})
914      */
915     public Optional<Double> getRawCorrectionRange() {
916         return Optional.ofNullable(rawCorrectionRange);
917     }
918 
919     /** Setter for the raw correction for range.
920      * @param rawCorrectionRange the raw correction for range to set (in {@link #getRangeUnits()})
921      */
922     public void setRawCorrectionRange(final double rawCorrectionRange) {
923         refuseFurtherComments();
924         this.rawCorrectionRange = rawCorrectionRange;
925     }
926 
927     /** Getter for the radar cross section correction.
928      * @return the radar cross section correction in m²
929      */
930     public Optional<Double> getCorrectionRcs() {
931         return Optional.ofNullable(correctionRcs);
932     }
933 
934     /** Setter for the radar cross section correction.
935      * @param correctionRcs the radar cross section correction in m² to set
936      */
937     public void setCorrectionRcs(final double correctionRcs) {
938         refuseFurtherComments();
939         this.correctionRcs = correctionRcs;
940     }
941 
942     /** Getter for the yearly aberration correction.
943      * @return the yearly aberration correction in radians
944      */
945     public Optional<Double> getCorrectionAberrationYearly() {
946         return Optional.ofNullable(correctionAberrationYearly);
947     }
948 
949     /** Setter for the yearly aberration correction.
950      * @param correctionAberrationYearly the yearly aberration correction in radians to set
951      */
952     public void setCorrectionAberrationYearly(final double correctionAberrationYearly) {
953         refuseFurtherComments();
954         this.correctionAberrationYearly = correctionAberrationYearly;
955     }
956 
957     /** Getter for the diurnal aberration correction.
958      * @return the diurnal aberration correction in radians
959      */
960     public Optional<Double> getCorrectionAberrationDiurnal() {
961         return Optional.ofNullable(correctionAberrationDiurnal);
962     }
963 
964     /** Setter for the diurnal aberration correction.
965      * @param correctionAberrationDiurnal the diurnal aberration correction in radians to set
966      */
967     public void setCorrectionAberrationDiurnal(final double correctionAberrationDiurnal) {
968         refuseFurtherComments();
969         this.correctionAberrationDiurnal = correctionAberrationDiurnal;
970     }
971 
972     /** Getter for the correctionReceive.
973      * @return the correctionReceive (in TDM units, without conversion)
974      */
975     public Optional<Double> getCorrectionReceive() {
976         return Optional.ofNullable(correctionReceive);
977     }
978 
979     /** Setter for the correctionReceive.
980      * @param correctionReceive the correctionReceive to set (in TDM units, without conversion)
981      */
982     public void setCorrectionReceive(final double correctionReceive) {
983         refuseFurtherComments();
984         this.correctionReceive = correctionReceive;
985     }
986 
987     /** Getter for the correctionTransmit.
988      * @return the correctionTransmit (in TDM units, without conversion)
989      */
990     public Optional<Double> getCorrectionTransmit() {
991         return Optional.ofNullable(correctionTransmit);
992     }
993 
994     /** Setter for the correctionTransmit.
995      * @param correctionTransmit the correctionTransmit to set (in TDM units, without conversion)
996      */
997     public void setCorrectionTransmit(final double correctionTransmit) {
998         refuseFurtherComments();
999         this.correctionTransmit = correctionTransmit;
1000     }
1001 
1002     /** Getter for the correctionApplied.
1003      * @return the correctionApplied (in TDM units, without conversion)
1004      */
1005     public Optional<CorrectionApplied> getCorrectionsApplied() {
1006         return Optional.ofNullable(correctionsApplied);
1007     }
1008 
1009     /** Setter for the correctionApplied.
1010      * @param correctionsApplied the correctionApplied to set (in TDM units, without conversion)
1011      */
1012     public void setCorrectionsApplied(final CorrectionApplied correctionsApplied) {
1013         refuseFurtherComments();
1014         this.correctionsApplied = correctionsApplied;
1015     }
1016 }