1 /* Copyright 2002-2025 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.ilrs;
18
19 import java.util.ArrayList;
20 import java.util.Collections;
21 import java.util.List;
22 import java.util.Locale;
23 import java.util.SortedSet;
24 import java.util.TreeSet;
25 import java.util.regex.Pattern;
26 import java.util.stream.Collectors;
27
28 import org.hipparchus.util.FastMath;
29 import org.orekit.annotation.DefaultDataContext;
30 import org.orekit.time.AbsoluteDate;
31 import org.orekit.time.ChronologicalComparator;
32 import org.orekit.time.TimeScalesFactory;
33 import org.orekit.time.TimeStamped;
34 import org.orekit.utils.ImmutableTimeStampedCache;
35
36 /**
37 * This class stores all the information of the Consolidated laser ranging Data Format (CRD) parsed
38 * by CRDParser. It contains the header and a list of data records.
39 * @author Bryan Cazabonne
40 * @author Rongwang Li
41 * @since 10.3
42 */
43 public class CRD {
44
45 /** Value of 'not available' or 'not applicable' or 'no information'. */
46 public static final String STR_VALUE_NOT_AVAILABLE = "na";
47
48 /** String of "NaN". */
49 public static final String STR_NAN = "NaN";
50
51 /** Pattern of "NaN". */
52 public static final Pattern PATTERN_NAN = Pattern.compile(STR_NAN);
53
54 /** List of comments contained in the file. */
55 private final List<String> comments;
56
57 /** List of data blocks contain in the CDR file. */
58 private final List<CRDDataBlock> dataBlocks;
59
60 /**
61 * Constructor.
62 */
63 public CRD() {
64 // Initialise empty lists
65 this.comments = new ArrayList<>();
66 this.dataBlocks = new ArrayList<>();
67 }
68
69 /**
70 * Format the integer value as a string, or the string <code>VALUE_NOT_AVAILABLE</code>.
71 * @param value the value
72 * @param valueNotAvailable the value means not available
73 * @return a string
74 * @since 12.0
75 */
76 public static String formatIntegerOrNaN(final int value, final int valueNotAvailable) {
77 return value == valueNotAvailable ? STR_VALUE_NOT_AVAILABLE : String.format(Locale.US, "%d", value);
78 }
79
80 /**
81 * Replace all " NaN" with " na".
82 * @param crdString the original string
83 * @return the string
84 * @since 12.0
85 */
86 public static String handleNaN(final String crdString) {
87 return PATTERN_NAN.matcher(crdString).replaceAll(STR_VALUE_NOT_AVAILABLE);
88 }
89
90 /**
91 * Add a data block to the current list of data blocks.
92 * @param dataBlock data block to add
93 */
94 public void addDataBlock(final CRDDataBlock dataBlock) {
95 dataBlocks.add(dataBlock);
96 }
97
98 /**
99 * Get the comments contained in the file.
100 * @return the comments contained in the file
101 */
102 public List<String> getComments() {
103 return comments;
104 }
105
106 /**
107 * Get the data blocks contain in the file.
108 * @return the data blocks contain in the file
109 */
110 public List<CRDDataBlock> getDataBlocks() {
111 return Collections.unmodifiableList(dataBlocks);
112 }
113
114 /**
115 * Data block containing a set of data contain in the CRD file.
116 * <p>
117 * A data block consists of a header, configuration data and
118 * recorded data (range, angles, meteorological, etc.).
119 * </p>
120 */
121 public static class CRDDataBlock {
122
123 /** Data block header. */
124 private CRDHeader header;
125
126 /** Configuration record. */
127 private CRDConfiguration configurationRecords;
128
129 /** Range records. */
130 private final List<RangeMeasurement> rangeData;
131
132 /** Meteorological records. */
133 private final SortedSet<MeteorologicalMeasurement> meteoData;
134
135 /** Pointing angles records. */
136 private final List<AnglesMeasurement> anglesData;
137
138 /** RangeSupplement records. */
139 private final List<RangeSupplement> rangeSupplementData;
140
141 /** Session statistics record(s). */
142 private final List<SessionStatistics> sessionStatisticsData;
143
144 /** Calibration Record(s). */
145 private final List<Calibration> calibrationData;
146
147 /** Calibration detail record(s). */
148 private final List<CalibrationDetail> calibrationDetailData;
149
150 /**
151 * Constructor.
152 */
153 public CRDDataBlock() {
154 // Initialise empty lists
155 this.rangeData = new ArrayList<>();
156 this.meteoData = new TreeSet<>(new ChronologicalComparator());
157 this.anglesData = new ArrayList<>();
158 this.rangeSupplementData = new ArrayList<>();
159 this.sessionStatisticsData = new ArrayList<>();
160 this.calibrationData = new ArrayList<>();
161 this.calibrationDetailData = new ArrayList<>();
162 }
163
164 /**
165 * Get the header of the current data block.
166 * @return the header of the current data block
167 */
168 public CRDHeader getHeader() {
169 return header;
170 }
171
172 /**
173 * Set the header for the current data block.
174 * @param header the header to set
175 */
176 public void setHeader(final CRDHeader header) {
177 this.header = header;
178 }
179
180 /**
181 * Get the system configuration records.
182 * @return the system configuration records
183 */
184 public CRDConfiguration getConfigurationRecords() {
185 return configurationRecords;
186 }
187
188 /**
189 * Set the configuration records for the current data block.
190 * @param configurationRecords the configuration records to set
191 */
192 public void setConfigurationRecords(final CRDConfiguration configurationRecords) {
193 this.configurationRecords = configurationRecords;
194 }
195
196 /**
197 * Add an entry to the list of range data.
198 * @param range entry to add
199 */
200 public void addRangeData(final RangeMeasurement range) {
201 rangeData.add(range);
202 }
203
204 /**
205 * Add an entry to the list of meteorological data.
206 * @param meteorologicalMeasurement entry to add
207 */
208 public void addMeteoData(final MeteorologicalMeasurement meteorologicalMeasurement) {
209 meteoData.add(meteorologicalMeasurement);
210 }
211
212 /**
213 * Add an entry to the list of angles data.
214 * @param angles entry to add
215 */
216 public void addAnglesData(final AnglesMeasurement angles) {
217 anglesData.add(angles);
218 }
219
220 /**
221 * Get the range data for the data block.
222 * @return an unmodifiable list of range data
223 */
224 public List<RangeMeasurement> getRangeData() {
225 return Collections.unmodifiableList(rangeData);
226 }
227
228 /**
229 * Get the angles data for the data block.
230 * @return an unmodifiable list of angles data
231 */
232 public List<AnglesMeasurement> getAnglesData() {
233 return Collections.unmodifiableList(anglesData);
234 }
235
236 /**
237 * Get the meteorological data for the data block.
238 * @return an unmodifiable list of meteorological data
239 */
240 public Meteo getMeteoData() {
241 return new Meteo(meteoData);
242 }
243
244 /**
245 * Add an entry to the list of range supplement data.
246 * @param rangeSupplement entry to add
247 * @since 12.0
248 */
249 public void addRangeSupplementData(final RangeSupplement rangeSupplement) {
250 rangeSupplementData.add(rangeSupplement);
251 }
252
253 /**
254 * Get the range supplement data for the data block.
255 * @return an unmodifiable list of range supplement data
256 * @since 12.0
257 */
258 public List<RangeSupplement> getRangeSupplementData() {
259 return Collections.unmodifiableList(rangeSupplementData);
260 }
261
262 /**
263 * Add an entry to the list of session statistics data.
264 * @param sessionStatistics entry to add
265 * @since 12.0
266 */
267 public void addSessionStatisticsData(final SessionStatistics sessionStatistics) {
268 sessionStatisticsData.add(sessionStatistics);
269 }
270
271 /**
272 * Get the session statistics data for the data block.
273 * @return an unmodifiable list of session statistics data
274 * @since 12.0
275 */
276 public List<SessionStatistics> getSessionStatisticsData() {
277 return Collections.unmodifiableList(sessionStatisticsData);
278 }
279
280 /**
281 * Get the default (the first if there are many records) SessionStat record.
282 * @return the default (the first if there are many records) session statistics record
283 * @since 12.0
284 */
285 public SessionStatistics getSessionStatisticsRecord() {
286 return getSessionStatisticsRecord(null);
287 }
288
289 /**
290 * Get the session statistics record related to the systemConfigurationId.
291 * @param systemConfigurationId system configuration ID
292 * @return the session statistics record
293 * @since 12.0
294 */
295 public SessionStatistics getSessionStatisticsRecord(final String systemConfigurationId) {
296 if (sessionStatisticsData.isEmpty()) {
297 return null;
298 }
299
300 if (systemConfigurationId == null) {
301 // default (the first one)
302 return sessionStatisticsData.get(0);
303 }
304
305 // Loop to find the appropriate one
306 for (SessionStatistics sessionStatistics : sessionStatisticsData) {
307 if (systemConfigurationId.equalsIgnoreCase(sessionStatistics.getSystemConfigurationId())) {
308 return sessionStatistics;
309 }
310 }
311
312 return null;
313 }
314
315 /**
316 * Add an entry to the list of calibration data.
317 * @param cal entry to add
318 * @since 12.0
319 */
320 public void addCalibrationData(final Calibration cal) {
321 calibrationData.add(cal);
322 }
323
324 /**
325 * Get the calibration data for the data block.
326 * @return an unmodifiable list of calibration data
327 * @since 12.0
328 */
329 public List<Calibration> getCalibrationData() {
330 return Collections.unmodifiableList(calibrationData);
331 }
332
333 /**
334 * Get the Calibration record(s) related to the default system configuration id.
335 * @return the Calibration record(s) related to the default system configuration id
336 * @since 12.0
337 */
338 public List<Calibration> getCalibrationRecords() {
339 return getCalibrationRecords(null);
340 }
341
342 /**
343 * Get the Calibration record(s) related to the given systemConfigurationId.
344 * @param systemConfigurationId system configuration ID
345 * @return the Calibration record(s)
346 * @since 12.0
347 */
348 public List<Calibration> getCalibrationRecords(final String systemConfigurationId) {
349 if (calibrationData.isEmpty()) {
350 return null;
351 }
352
353 final String systemConfigId = systemConfigurationId == null ? getConfigurationRecords().getSystemRecord().getConfigurationId() : systemConfigurationId;
354
355 final List<Calibration> list = new ArrayList<>();
356 // Loop to find the appropriate one
357 for (Calibration calibration : calibrationData) {
358 if (systemConfigId.equalsIgnoreCase(calibration.getSystemConfigurationId())) {
359 list.add(calibration);
360 }
361 }
362
363 return list;
364 }
365
366 /**
367 * Add an entry to the list of calibration detail data.
368 * @param cal entry to add
369 * @since 12.0
370 */
371 public void addCalibrationDetailData(final CalibrationDetail cal) {
372 calibrationDetailData.add(cal);
373 }
374
375 /**
376 * Get the calibration detail data for the data block.
377 * @return an unmodifiable list of calibration detail data
378 * @since 12.0
379 */
380 public List<CalibrationDetail> getCalibrationDetailData() {
381 return Collections.unmodifiableList(calibrationDetailData);
382 }
383
384 /**
385 * Get the CalibrationDetail record(s) related to the default system configuration id.
386 * @return the CalibrationDetail record(s) related to the default system configuration id
387 * @since 12.0
388 */
389 public List<CalibrationDetail> getCalibrationDetailRecords() {
390 return getCalibrationDetailRecords(null);
391 }
392
393 /**
394 * Get the CalibrationDetail record(s) related to the given systemConfigurationId.
395 * @param systemConfigurationId system configuration ID
396 * @return the CalibrationDetail record(s)
397 * @since 12.0
398 */
399 public List<CalibrationDetail> getCalibrationDetailRecords(final String systemConfigurationId) {
400 if (calibrationDetailData.isEmpty()) {
401 return null;
402 }
403
404 final String systemConfigId = systemConfigurationId == null ? getConfigurationRecords().getSystemRecord().getConfigurationId() : systemConfigurationId;
405
406 final List<CalibrationDetail> list = new ArrayList<>();
407 // Loop to find the appropriate one
408 for (CalibrationDetail calibration : calibrationDetailData) {
409 if (systemConfigId.equalsIgnoreCase(calibration.getSystemConfigurationId())) {
410 list.add(calibration);
411 }
412 }
413
414 return list;
415 }
416
417 /**
418 * Get the wavelength related to the given RangeMeasurement.
419 *
420 * @param range a RangeMeasurement
421 * @return the wavelength related to the given RangeMeasurement.
422 * @since 12.0
423 */
424 public double getWavelength(final RangeMeasurement range) {
425 return getConfigurationRecords().getSystemRecord(range.getSystemConfigurationId()).getWavelength();
426 }
427
428 }
429
430 /** Range record. */
431 public static class RangeMeasurement implements TimeStamped {
432
433 /** Data epoch. */
434 private final AbsoluteDate date;
435
436 /** Time of flight [s]. */
437 private final double timeOfFlight;
438
439 /** System configuration ID. */
440 private final String systemConfigurationId;
441
442 /** Time event reference indicator.
443 * 0 = ground receive time (at SRP) (two-way)
444 * 1 = spacecraft bounce time (two-way)
445 * 2 = ground transmit time (at SRP) (two-way)
446 * 3 = spacecraft receive time (one-way)
447 * 4 = spacecraft transmit time (one-way)
448 * 5 = ground transmit time (at SRP) and spacecraft receive time (one-way)
449 * 6 = spacecraft transmit time and ground receive time (at SRP) (one-way)
450 * Currently, only 1 and 2 are used for laser ranging data.
451 */
452 private final int epochEvent;
453
454 /** Signal to noise ration. */
455 private final double snr;
456
457 /**
458 * Constructor.
459 * @param date data epoch
460 * @param timeOfFlight time of flight in seconds
461 * @param epochEvent indicates the time event reference
462 */
463 public RangeMeasurement(final AbsoluteDate date,
464 final double timeOfFlight,
465 final int epochEvent) {
466 this(date, timeOfFlight, epochEvent, Double.NaN);
467 }
468
469 /**
470 * Constructor.
471 * @param date data epoch
472 * @param timeOfFlight time of flight in seconds
473 * @param epochEvent indicates the time event reference
474 * @param snr signal to noise ratio (can be Double.NaN if unkonwn)
475 */
476 public RangeMeasurement(final AbsoluteDate date,
477 final double timeOfFlight,
478 final int epochEvent, final double snr) {
479 this(date, timeOfFlight, epochEvent, snr, null);
480 }
481
482 /**
483 * Constructor.
484 * @param date data epoch
485 * @param timeOfFlight time of flight in seconds
486 * @param epochEvent indicates the time event reference
487 * @param snr signal to noise ratio (can be Double.NaN if unkonwn)
488 * @param systemConfigurationId system configuration id
489 * @since 12.0
490 */
491 public RangeMeasurement(final AbsoluteDate date,
492 final double timeOfFlight, final int epochEvent,
493 final double snr,
494 final String systemConfigurationId) {
495 this.date = date;
496 this.timeOfFlight = timeOfFlight;
497 this.epochEvent = epochEvent;
498 this.snr = snr;
499 this.systemConfigurationId = systemConfigurationId;
500 }
501
502 /**
503 * Get the time-of-flight.
504 * @return the time-of-flight in seconds
505 */
506 public double getTimeOfFlight() {
507 return timeOfFlight;
508 }
509
510 /**
511 * Get the indicator for the time event reference.
512 * <ul>
513 * <li>0 = ground receive time (at SRP) (two-way)</li>
514 * <li>1 = spacecraft bounce time (two-way)</li>
515 * <li>2 = ground transmit time (at SRP) (two-way)</li>
516 * <li>3 = spacecraft receive time (one-way)</li>
517 * <li>4 = spacecraft transmit time (one-way)</li>
518 * <li>5 = ground transmit time (at SRP) and spacecraft receive time (one-way)</li>
519 * <li>6 = spacecraft transmit time and ground receive time (at SRP) (one-way)</li>
520 * </ul>
521 * Currently, only 1 and 2 are used for laser ranging data
522 * @return the indicator for the time event reference
523 */
524 public int getEpochEvent() {
525 return epochEvent;
526 }
527
528 /**
529 * Get the signal to noise ratio.
530 * @return the signal to noise ratio
531 */
532 public double getSnr() {
533 return snr;
534 }
535
536 /** {@inheritDoc} */
537 @Override
538 public AbsoluteDate getDate() {
539 return date;
540 }
541
542 /**
543 * Get the system configuration id.
544 * @return the system configuration id
545 * @since 12.0
546 */
547 public String getSystemConfigurationId() {
548 return systemConfigurationId;
549 }
550
551 /**
552 * Get a string representation of the instance in the CRD format.
553 * @return a string representation of the instance, in the CRD format.
554 * @since 12.0
555 */
556 public String toCrdString() {
557 return "00 not supported. use NptRangeMeasurement or FrRangeMeasurement instead.";
558 }
559 }
560
561 /**
562 * Range record -- Full rate, Sampled Engineering/Quicklook.
563 * @since 12.0
564 */
565 public static class FrRangeMeasurement extends RangeMeasurement {
566
567 /** Filter flag. **/
568 private final int filterFlag;
569
570 /** Detector channel. **/
571 private final int detectorChannel;
572
573 /** Stop number (in multiple-stop system). **/
574 private final int stopNumber;
575
576 /** Receive amplitude - a positive linear scale value. **/
577 private final int receiveAmplitude;
578
579 /** Transmit amplitude - a positive linear scale value. **/
580 private final int transmitAmplitude;
581
582 /**
583 * Constructor.
584 * @param date data epoch
585 * @param timeOfFlight time of flight in seconds
586 * @param epochEvent indicates the time event reference
587 * @param systemConfigurationId system configuration id
588 * @param filterFlag filter flag
589 * @param detectorChannel detector channel
590 * @param stopNumber stop number
591 * @param receiveAmplitude receive amplitude
592 * @param transmitAmplitude transmit amplitude
593 */
594 public FrRangeMeasurement(final AbsoluteDate date,
595 final double timeOfFlight,
596 final int epochEvent,
597 final String systemConfigurationId,
598 final int filterFlag,
599 final int detectorChannel,
600 final int stopNumber,
601 final int receiveAmplitude,
602 final int transmitAmplitude) {
603 super(date, timeOfFlight, epochEvent, Double.NaN, systemConfigurationId);
604 this.filterFlag = filterFlag;
605 this.detectorChannel = detectorChannel;
606 this.stopNumber = stopNumber;
607 this.receiveAmplitude = receiveAmplitude;
608 this.transmitAmplitude = transmitAmplitude;
609 }
610
611 /**
612 * Get the filter flag.
613 * @return the filter flag
614 */
615 public int getFilterFlag() {
616 return filterFlag;
617 }
618
619 /**
620 * Get the detector channel.
621 * @return the detector channel
622 */
623 public int getDetectorChannel() {
624 return detectorChannel;
625 }
626
627 /**
628 * Get the stop number.
629 * @return the stop number
630 */
631 public int getStopNumber() {
632 return stopNumber;
633 }
634
635 /**
636 * Get the receive amplitude.
637 * @return the receive amplitude, -1 if not measured
638 */
639 public int getReceiveAmplitude() {
640 return receiveAmplitude;
641 }
642
643 /**
644 * Get the transmit amplitude.
645 * @return the transmit amplitude, -1 if not measured
646 */
647 public int getTransmitAmplitude() {
648 return transmitAmplitude;
649 }
650
651 /** {@inheritDoc} */
652 @Override
653 @DefaultDataContext
654 public String toCrdString() {
655 return String.format(Locale.US, "10 %s", toString());
656 }
657
658 @Override
659 @DefaultDataContext
660 public String toString() {
661 // CRD suggested format, excluding the record type
662 // 'local' is already utc.
663 // Seconds of day (sod) is typically to 1 milllisec precision.
664 // receiveAmplitude, transmitAmplitude: -1 if not available
665 final double sod = getDate().
666 getComponents(TimeScalesFactory.getUTC()).
667 roundIfNeeded(60, 12).
668 getTime().
669 getSecondsInLocalDay();
670
671 final String str = String.format(Locale.US,
672 "%18.12f %18.12f %4s %1d %1d %1d %1d %5s %5s", sod,
673 getTimeOfFlight(), getSystemConfigurationId(),
674 getEpochEvent(), filterFlag, detectorChannel, stopNumber,
675 formatIntegerOrNaN(receiveAmplitude, -1),
676 formatIntegerOrNaN(transmitAmplitude, -1));
677 return handleNaN(str).replace(',', '.');
678 }
679
680 }
681
682 /**
683 * Range record -- Normal Point.
684 * @since 12.0
685 */
686 public static class NptRangeMeasurement extends RangeMeasurement {
687
688 /** Normal point window length [s]. */
689 private final double windowLength;
690
691 /** Number of raw ranges (after editing) compressed into the normal point. */
692 private final int numberOfRawRanges;
693
694 /** Bin RMS from the mean of raw accepted time-of-flight values minus the trend function. */
695 private final double binRms;
696
697 /** Bin skew from the mean of raw accepted time-of-flight values minus the trend function. */
698 private final double binSkew;
699
700 /** Bin kurtosis from the mean of raw accepted time-of-flight values minus the trend function. */
701 private final double binKurtosis;
702
703 /** Bin peak - mean value. */
704 private final double binPeakMinusMean;
705
706 /** Return rate [%]. */
707 private final double returnRate;
708
709 /** Detector channel. */
710 private final int detectorChannel;
711
712 /**
713 * Constructor.
714 * @param date data epoch
715 * @param timeOfFlight time of flight in seconds
716 * @param epochEvent indicates the time event reference
717 * @param snr signal to noise ratio (can be Double.NaN if unkonwn)
718 * @param systemConfigurationId System configuration id
719 */
720 public NptRangeMeasurement(final AbsoluteDate date,
721 final double timeOfFlight,
722 final int epochEvent, final double snr,
723 final String systemConfigurationId) {
724 this(date, timeOfFlight, epochEvent, snr, systemConfigurationId, -1,
725 -1, Double.NaN, Double.NaN, Double.NaN, Double.NaN,
726 Double.NaN, 0);
727 }
728
729 /**
730 * Constructor.
731 * @param date data epoch
732 * @param timeOfFlight time of flight in seconds
733 * @param epochEvent indicates the time event reference
734 * @param snr signal to noise ratio (can be Double.NaN if unkonwn)
735 * @param systemConfigurationId System configuration id
736 * @param windowLength normal point window length
737 * @param numberOfRawRanges number of raw ranges (after editing) compressed into the normal point
738 * @param binRms Bin RMS from the mean of raw accepted time-of-flight values minus the trend function
739 * @param binSkew Bin skew from the mean of raw accepted time-of-flight values minus the trend function
740 * @param binKurtosis Bin kurtosis from the mean of raw accepted time-of-flight values minus the trend function
741 * @param binPeakMinusMean Bin peak - mean value
742 * @param returnRate Return rate [%]
743 * @param detectorChannel detector channel
744 */
745 public NptRangeMeasurement(final AbsoluteDate date,
746 final double timeOfFlight,
747 final int epochEvent, final double snr,
748 final String systemConfigurationId,
749 final double windowLength,
750 final int numberOfRawRanges,
751 final double binRms, final double binSkew,
752 final double binKurtosis,
753 final double binPeakMinusMean,
754 final double returnRate,
755 final int detectorChannel) {
756 super(date, timeOfFlight, epochEvent, snr, systemConfigurationId);
757
758 this.windowLength = windowLength;
759 this.numberOfRawRanges = numberOfRawRanges;
760 this.binSkew = binSkew;
761 this.binKurtosis = binKurtosis;
762 this.binPeakMinusMean = binPeakMinusMean;
763 this.detectorChannel = detectorChannel;
764 this.binRms = binRms == -1.0e-12 ? Double.NaN : binRms; // -1=na, ps --> s
765 this.returnRate = returnRate == -1 ? Double.NaN : returnRate; // -1=na
766 }
767
768 /**
769 * Get the normal point window length.
770 * @return the normal point window length
771 */
772 public double getWindowLength() {
773 return windowLength;
774 }
775
776 /**
777 * Get the umber of raw ranges (after editing) compressed into the normal point.
778 * @return the umber of raw ranges
779 */
780 public int getNumberOfRawRanges() {
781 return numberOfRawRanges;
782 }
783
784 /**
785 * Get the bin RMS from the mean of raw accepted time-of-flight values minus the trend function.
786 * @return the bin RMS
787 */
788 public double getBinRms() {
789 return binRms;
790 }
791
792 /**
793 * Get the bin skew from the mean of raw accepted time-of-flight values minus the trend function.
794 * @return the bin skew
795 */
796 public double getBinSkew() {
797 return binSkew;
798 }
799
800 /**
801 * Get the bin kurtosis from the mean of raw accepted time-of-flight values minus the trend function.
802 * @return the bin kurtosis
803 */
804 public double getBinKurtosis() {
805 return binKurtosis;
806 }
807
808 /**
809 * Get the bin peak - mean value.
810 * @return the bin peak - mean value
811 */
812 public double getBinPeakMinusMean() {
813 return binPeakMinusMean;
814 }
815
816 /**
817 * Get the return rate.
818 * @return the return rate
819 */
820 public double getReturnRate() {
821 return returnRate;
822 }
823
824 /**
825 * Get the detector channel.
826 * @return the detector channel
827 */
828 public int getDetectorChannel() {
829 return detectorChannel;
830 }
831
832 /** {@inheritDoc} */
833 @Override
834 @DefaultDataContext
835 public String toCrdString() {
836 return String.format(Locale.US, "11 %s", toString());
837 }
838
839 @Override
840 @DefaultDataContext
841 public String toString() {
842 // CRD suggested format, excluding the record type
843 // binRms, binPeakMinusMean: s --> ps
844 // 'local' is already utc.
845 // Seconds of day (sod) is typically to 1 milllisec precision.
846 final double sod = getDate().
847 getComponents(TimeScalesFactory.getUTC()).
848 roundIfNeeded(60, 12).
849 getTime().
850 getSecondsInLocalDay();
851
852 final String str = String.format(Locale.US,
853 "%18.12f %18.12f %4s %1d %6.1f %6d %9.1f %7.3f %7.3f %9.1f %5.2f %1d %5.1f",
854 sod, getTimeOfFlight(), getSystemConfigurationId(),
855 getEpochEvent(), windowLength, numberOfRawRanges,
856 binRms * 1e12, binSkew, binKurtosis,
857 binPeakMinusMean * 1e12, returnRate, detectorChannel,
858 getSnr());
859 return handleNaN(str).replace(',', '.');
860 }
861
862 }
863
864 /**
865 * Range Supplement Record.
866 * @since 12.0
867 */
868 public static class RangeSupplement implements TimeStamped {
869
870 /** Data epoch. */
871 private final AbsoluteDate date;
872
873 /** System configuration ID. */
874 private final String systemConfigurationId;
875
876 /** Tropospheric refraction correction (one-way). */
877 private final double troposphericRefractionCorrection;
878
879 /** Target center of mass correction (one-way). */
880 private final double centerOfMassCorrection;
881
882 /** Neutral density (ND) filter value. */
883 private final double ndFilterValue;
884
885 /** Time bias applied. */
886 private final double timeBiasApplied;
887
888 /** Range rate. */
889 private final double rangeRate;
890
891 /**
892 * Constructor.
893 * @param date data epoch
894 * @param systemConfigurationId system configuration ID
895 * @param troposphericRefractionCorrection tropospheric refraction correction (one-way)
896 * @param centerOfMassCorrection target center of mass correction (one-way)
897 * @param ndFilterValue Neutral density (ND) filter value
898 * @param timeBiasApplied Time bias applied
899 * @param rangeRate Range rate
900 */
901 public RangeSupplement(final AbsoluteDate date,
902 final String systemConfigurationId,
903 final double troposphericRefractionCorrection,
904 final double centerOfMassCorrection,
905 final double ndFilterValue,
906 final double timeBiasApplied,
907 final double rangeRate) {
908 this.date = date;
909 this.systemConfigurationId = systemConfigurationId;
910 this.troposphericRefractionCorrection = troposphericRefractionCorrection;
911 this.centerOfMassCorrection = centerOfMassCorrection;
912 this.ndFilterValue = ndFilterValue;
913 this.timeBiasApplied = timeBiasApplied;
914 this.rangeRate = rangeRate;
915 }
916
917 @Override
918 public AbsoluteDate getDate() {
919 return date;
920 }
921
922 /**
923 * Get the system configuration id.
924 * @return the system configuration id
925 */
926 public String getSystemConfigurationId() {
927 return systemConfigurationId;
928 }
929
930 /**
931 * Get the tropospheric refraction correction.
932 * @return the tropospheric refraction correction
933 */
934 public double getTroposphericRefractionCorrection() {
935 return troposphericRefractionCorrection;
936 }
937
938 /**
939 * Get the target center of mass.
940 * @return the target center of mass
941 */
942 public double getCenterOfMassCorrection() {
943 return centerOfMassCorrection;
944 }
945
946 /**
947 * Get the neutral density (ND) filter value.
948 * @return the neutral density (ND) filter value
949 */
950 public double getNdFilterValue() {
951 return ndFilterValue;
952 }
953
954 /**
955 * Get the time bias applied.
956 * @return the time bias applied
957 */
958 public double getTimeBiasApplied() {
959 return timeBiasApplied;
960 }
961
962 /**
963 * Get the range rate.
964 * @return the range rate
965 */
966 public double getRangeRate() {
967 return rangeRate;
968 }
969
970 /**
971 * Get a string representation of the instance in the CRD format.
972 * @return a string representation of the instance, in the CRD format.
973 */
974 @DefaultDataContext
975 public String toCrdString() {
976 return String.format(Locale.US, "12 %s", toString());
977 }
978
979 @Override
980 @DefaultDataContext
981 public String toString() {
982 // CRD suggested format, excluding the record type
983 // troposphericRefractionCorrection: s --> ps
984 // 'local' is already utc.
985 // Seconds of day (sod) is typically to 1 milllisec precision.
986 final double sod = getDate().
987 getComponents(TimeScalesFactory.getUTC()).
988 roundIfNeeded(60, 12).
989 getTime().
990 getSecondsInLocalDay();
991
992 final String str = String.format(Locale.US,
993 "%18.12f %4s %6.1f %6.4f %5.2f %8.4f %f", sod,
994 getSystemConfigurationId(),
995 troposphericRefractionCorrection * 1e12,
996 centerOfMassCorrection, ndFilterValue, timeBiasApplied,
997 rangeRate);
998 return handleNaN(str).replace(',', '.');
999 }
1000
1001 }
1002
1003 /** This data record contains a minimal set of meteorological data. */
1004 public static class MeteorologicalMeasurement implements TimeStamped {
1005
1006 /** Data epoch. */
1007 private final AbsoluteDate date;
1008
1009 /** Surface pressure [bar]. */
1010 private final double pressure;
1011
1012 /** Surface temperature [K]. */
1013 private final double temperature;
1014
1015 /** Relative humidity at the surface [%]. */
1016 private final double humidity;
1017
1018 /** Origin of values.
1019 * 0=measured values, 1=interpolated values
1020 */
1021 private final int originOfValues;
1022
1023 /**
1024 * Constructor.
1025 * @param date data epoch
1026 * @param pressure the surface pressure in bars
1027 * @param temperature the surface temperature in degrees Kelvin
1028 * @param humidity the relative humidity at the surface in percents
1029 */
1030 public MeteorologicalMeasurement(final AbsoluteDate date,
1031 final double pressure, final double temperature,
1032 final double humidity) {
1033 this(date, pressure, temperature, humidity, 0);
1034 }
1035
1036 /**
1037 * Constructor.
1038 * @param date data epoch
1039 * @param pressure the surface pressure in bars
1040 * @param temperature the surface temperature in degrees Kelvin
1041 * @param humidity the relative humidity at the surface in percents
1042 * @param originOfValues Origin of values
1043 */
1044 public MeteorologicalMeasurement(final AbsoluteDate date, final double pressure, final double temperature,
1045 final double humidity, final int originOfValues) {
1046 this.date = date;
1047 this.pressure = pressure;
1048 this.temperature = temperature;
1049 this.humidity = humidity;
1050 this.originOfValues = originOfValues;
1051 }
1052
1053 /**
1054 * Get the surface pressure.
1055 * @return the surface pressure in bars
1056 */
1057 public double getPressure() {
1058 return pressure;
1059 }
1060
1061 /**
1062 * Get the surface temperature.
1063 * @return the surface temperature in degrees Kelvin
1064 */
1065 public double getTemperature() {
1066 return temperature;
1067 }
1068
1069 /**
1070 * Get the relative humidity at the surface.
1071 * @return the relative humidity at the surface in percents
1072 */
1073 public double getHumidity() {
1074 return humidity;
1075 }
1076
1077 /** {@inheritDoc} */
1078 @Override
1079 public AbsoluteDate getDate() {
1080 return date;
1081 }
1082
1083 /** Get the origin of values.
1084 * 0=measure values
1085 * 1=interpolated values
1086 * @return the origin of values
1087 * @since 12.0
1088 */
1089 public int getOriginOfValues() {
1090 return originOfValues;
1091 }
1092
1093 /**
1094 * Get a string representation of the instance in the CRD format.
1095 * @return a string representation of the instance, in the CRD format.
1096 * @since 12.0
1097 */
1098 @DefaultDataContext
1099 public String toCrdString() {
1100 return String.format(Locale.US, "20 %s", toString());
1101 }
1102
1103 @Override
1104 @DefaultDataContext
1105 public String toString() {
1106 // CRD suggested format, excluding the record type
1107 // pressure: bar --> mbar
1108 // 'local' is already utc.
1109 // Seconds of day (sod) is typically to 1 milllisec precision.
1110 final double sod = getDate().
1111 getComponents(TimeScalesFactory.getUTC()).
1112 roundIfNeeded(60, 3).
1113 getTime().
1114 getSecondsInLocalDay();
1115
1116 final String str = String.format(Locale.US, "%9.3f %7.2f %6.2f %4.0f %1d",
1117 sod, pressure * 1e3, temperature, humidity, originOfValues);
1118 return handleNaN(str).replace(',', '.');
1119 }
1120 }
1121
1122 /** Pointing angles record. */
1123 public static class AnglesMeasurement implements TimeStamped {
1124
1125 /** Data epoch. */
1126 private final AbsoluteDate date;
1127
1128 /** Azimuth [rad]. */
1129 private final double azimuth;
1130
1131 /** Elevation [rad]. */
1132 private final double elevation;
1133
1134 /** Direction flag (0 = transmit & receive ; 1 = transmit ; 2 = receive). */
1135 private final int directionFlag;
1136
1137 /** Angle origin indicator.
1138 * 0 = unknown
1139 * 1 = computed
1140 * 2 = commanded (from predictions)
1141 * 3 = measured (from encoders)
1142 */
1143 private final int originIndicator;
1144
1145 /** Refraction corrected. */
1146 private final boolean refractionCorrected;
1147
1148 /** Azimuth rate [rad/sec]. */
1149 private final double azimuthRate;
1150
1151 /** Elevation rate [rad/sec]. */
1152 private final double elevationRate;
1153
1154 /**
1155 * Constructor.
1156 * @param date data epoch
1157 * @param azimuth azimuth angle in radians
1158 * @param elevation elevation angle in radians
1159 * @param directionFlag direction flag
1160 * @param originIndicator angle origin indicator
1161 * @param refractionCorrected flag to indicate if the refraction is corrected
1162 * @param azimuthRate azimuth rate in radians per second (equal to Double.NaN if unknown)
1163 * @param elevationRate elevation rate in radians per second (equal to Double.NaN if unknown)
1164 */
1165 public AnglesMeasurement(final AbsoluteDate date, final double azimuth,
1166 final double elevation, final int directionFlag,
1167 final int originIndicator,
1168 final boolean refractionCorrected,
1169 final double azimuthRate, final double elevationRate) {
1170 this.date = date;
1171 this.azimuth = azimuth;
1172 this.elevation = elevation;
1173 this.directionFlag = directionFlag;
1174 this.originIndicator = originIndicator;
1175 this.refractionCorrected = refractionCorrected;
1176 this.azimuthRate = azimuthRate;
1177 this.elevationRate = elevationRate;
1178 }
1179
1180 /**
1181 * Get the azimuth angle.
1182 * @return the azimuth angle in radians
1183 */
1184 public double getAzimuth() {
1185 return azimuth;
1186 }
1187
1188 /**
1189 * Get the elevation angle.
1190 * @return the elevation angle in radians
1191 */
1192 public double getElevation() {
1193 return elevation;
1194 }
1195
1196 /**
1197 * Get the direction flag (0 = transmit & receive ; 1 = transmit ; 2 = receive).
1198 * @return the direction flag
1199 */
1200 public int getDirectionFlag() {
1201 return directionFlag;
1202 }
1203
1204 /**
1205 * Get the angle origin indicator.
1206 * <p>
1207 * 0 = unknown;
1208 * 1 = computed;
1209 * 2 = commanded (from predictions);
1210 * 3 = measured (from encoders)
1211 * </p>
1212 * @return the angle origin indicator
1213 */
1214 public int getOriginIndicator() {
1215 return originIndicator;
1216 }
1217
1218 /**
1219 * Get the flag indicating if the refraction is corrected.
1220 * @return true if refraction is corrected
1221 */
1222 public boolean isRefractionCorrected() {
1223 return refractionCorrected;
1224 }
1225
1226 /**
1227 * Get the azimuth rate.
1228 * <p>
1229 * Is equal to Double.NaN if the value is unknown.
1230 * </p>
1231 * @return the azimuth rate in radians per second
1232 */
1233 public double getAzimuthRate() {
1234 return azimuthRate;
1235 }
1236
1237 /**
1238 * Get the elevation rate.
1239 * <p>
1240 * Is equal to Double.NaN if the value is unknown.
1241 * </p>
1242 * @return the elevation rate in radians per second
1243 */
1244 public double getElevationRate() {
1245 return elevationRate;
1246 }
1247
1248 /** {@inheritDoc} */
1249 @Override
1250 public AbsoluteDate getDate() {
1251 return date;
1252 }
1253
1254 /**
1255 * Get a string representation of the instance in the CRD format.
1256 * @return a string representation of the instance, in the CRD format.
1257 * @since 12.0
1258 */
1259 @DefaultDataContext
1260 public String toCrdString() {
1261 return String.format(Locale.US, "30 %s", toString());
1262 }
1263
1264 @Override
1265 @DefaultDataContext
1266 public String toString() {
1267 // CRD suggested format, excluding the record type
1268 // azimuth, elevation: rad --> deg
1269 // azimuthRate, elevationRate: rad/s --> deg/s
1270 // 'local' is already utc.
1271 // Seconds of day (sod) is typically to 1 milllisec precision.
1272 final double sod = getDate().
1273 getComponents(TimeScalesFactory.getUTC()).
1274 roundIfNeeded(60, 3).
1275 getTime().
1276 getSecondsInLocalDay();
1277
1278 final String str = String.format(Locale.US,
1279 "%9.3f %8.4f %8.4f %1d %1d %1d %10.7f %10.7f",
1280 sod,
1281 FastMath.toDegrees(azimuth), FastMath.toDegrees(elevation),
1282 directionFlag, originIndicator, refractionCorrected ? 1 : 0,
1283 FastMath.toDegrees(azimuthRate),
1284 FastMath.toDegrees(elevationRate));
1285 return handleNaN(str).replace(',', '.');
1286 }
1287 }
1288
1289 /** Meteorological data. */
1290 public static class Meteo {
1291
1292 /** Number of neighbors for meteo data interpolation. */
1293 private static final int N_NEIGHBORS = 2;
1294
1295 /** First available date. */
1296 private final AbsoluteDate firstDate;
1297
1298 /** Last available date. */
1299 private final AbsoluteDate lastDate;
1300
1301 /** Previous set of meteorological parameters. */
1302 private transient MeteorologicalMeasurement previousParam;
1303
1304 /** Next set of solar meteorological parameters. */
1305 private transient MeteorologicalMeasurement nextParam;
1306
1307 /** List of meteo data. */
1308 private final transient ImmutableTimeStampedCache<MeteorologicalMeasurement> meteo;
1309
1310 /**
1311 * Constructor.
1312 * @param meteoData list of meteo data
1313 */
1314 public Meteo(final SortedSet<MeteorologicalMeasurement> meteoData) {
1315
1316 // Size
1317 final int neighborsSize = (meteoData.size() < 2) ? meteoData.size() : N_NEIGHBORS;
1318
1319 // Check neighbors size
1320 if (neighborsSize == 0) {
1321
1322 // Meteo data -> empty cache
1323 this.meteo = ImmutableTimeStampedCache.emptyCache();
1324
1325 // Null epochs (will ne be used)
1326 this.firstDate = null;
1327 this.lastDate = null;
1328
1329 } else {
1330
1331 // Meteo data
1332 this.meteo = new ImmutableTimeStampedCache<>(neighborsSize, meteoData);
1333
1334 // Initialize first and last available dates
1335 this.firstDate = meteoData.first().getDate();
1336 this.lastDate = meteoData.last().getDate();
1337
1338 }
1339
1340 }
1341
1342 /** Get an unmodifiable view of the tabulated meteorological data.
1343 * @return unmodifiable view of the tabulated meteorological data
1344 * @since 11.0
1345 */
1346 public List<MeteorologicalMeasurement> getData() {
1347 return meteo.getAll();
1348 }
1349
1350 /**
1351 * Get the meteorological parameters at a given date.
1352 * @param date date when user wants the meteorological parameters
1353 * @return the meteorological parameters at date (can be null if
1354 * meteorological data are empty).
1355 */
1356 public MeteorologicalMeasurement getMeteo(final AbsoluteDate date) {
1357
1358 // Check if meteorological data are available
1359 if (meteo.getMaxNeighborsSize() == 0) {
1360 return null;
1361 }
1362
1363 // Interpolating two neighboring meteorological parameters
1364 bracketDate(date);
1365 if (date.durationFrom(firstDate) <= 0 || date.durationFrom(lastDate) > 0) {
1366 // Date is outside file range
1367 return previousParam;
1368 } else {
1369 // Perform interpolations
1370 final double pressure = getLinearInterpolation(date, previousParam.getPressure(), nextParam.getPressure());
1371 final double temperature = getLinearInterpolation(date, previousParam.getTemperature(), nextParam.getTemperature());
1372 final double humidity = getLinearInterpolation(date, previousParam.getHumidity(), nextParam.getHumidity());
1373 return new MeteorologicalMeasurement(date, pressure, temperature, humidity);
1374 }
1375
1376 }
1377
1378 /**
1379 * Find the data bracketing a specified date.
1380 * @param date date to bracket
1381 */
1382 private void bracketDate(final AbsoluteDate date) {
1383
1384 // don't search if the cached selection is fine
1385 if (previousParam != null &&
1386 date.durationFrom(previousParam.getDate()) > 0 &&
1387 date.durationFrom(nextParam.getDate()) <= 0) {
1388 return;
1389 }
1390
1391 // Initialize previous and next parameters
1392 if (date.durationFrom(firstDate) <= 0) {
1393 // Current date is before the first date
1394 previousParam = meteo.getEarliest();
1395 nextParam = previousParam;
1396 } else if (date.durationFrom(lastDate) > 0) {
1397 // Current date is after the last date
1398 previousParam = meteo.getLatest();
1399 nextParam = previousParam;
1400 } else {
1401 // Current date is between first and last date
1402 final List<MeteorologicalMeasurement> neighbors = meteo.getNeighbors(date).collect(Collectors.toList());
1403 previousParam = neighbors.get(0);
1404 nextParam = neighbors.get(1);
1405 }
1406
1407 }
1408
1409 /**
1410 * Performs a linear interpolation between two values The weights are computed
1411 * from the time delta between previous date, current date, next date.
1412 * @param date the current date
1413 * @param previousValue the value at previous date
1414 * @param nextValue the value at next date
1415 * @return the value interpolated for the current date
1416 */
1417 private double getLinearInterpolation(final AbsoluteDate date,
1418 final double previousValue,
1419 final double nextValue) {
1420 // Perform a linear interpolation
1421 final AbsoluteDate previousDate = previousParam.getDate();
1422 final AbsoluteDate currentDate = nextParam.getDate();
1423 final double dt = currentDate.durationFrom(previousDate);
1424 final double previousWeight = currentDate.durationFrom(date) / dt;
1425 final double nextWeight = date.durationFrom(previousDate) / dt;
1426
1427 // Returns the data interpolated at the date
1428 return previousValue * previousWeight + nextValue * nextWeight;
1429 }
1430
1431 }
1432
1433 /**
1434 * Calibration Record.
1435 * @since 12.0
1436 */
1437 public static class Calibration implements TimeStamped {
1438
1439 /** Data epoch. */
1440 private final AbsoluteDate date;
1441
1442 /**
1443 * Type of data.
1444 * 0=station combined transmit and receive calibration (“normal” SLR/LLR)
1445 * 1=station transmit calibration (e.g., one-way ranging to transponders)
1446 * 2=station receive calibration
1447 * 3=target combined transmit and receive calibrations
1448 * 4=target transmit calibration
1449 * 5=target receive calibration
1450 */
1451 private final int typeOfData;
1452
1453 /** System configuration ID. */
1454 private final String systemConfigurationId;
1455
1456 /** Number of data points recorded. */
1457 private final int numberOfPointsRecorded;
1458
1459 /** Number of data points used. */
1460 private final int numberOfPointsUsed;
1461
1462 /** One-way target distance (meters, nominal). */
1463 private final double oneWayDistance;
1464
1465 /** Calibration System Delay. */
1466 private final double systemDelay;
1467
1468 /** Calibration Delay Shift - a measure of calibration stability. */
1469 private final double delayShift;
1470
1471 /** RMS of raw system delay. */
1472 private final double rms;
1473
1474 /** Skew of raw system delay values from the mean. */
1475 private final double skew;
1476
1477 /** Kurtosis of raw system delay values from the mean. */
1478 private final double kurtosis;
1479
1480 /** System delay peak – mean value. */
1481 private final double peakMinusMean;
1482
1483 /**
1484 * Calibration Type Indicator.
1485 * 0=not used or undefined
1486 * 1=nominal (from once off assessment)
1487 * 2=external calibrations
1488 * 3=internal calibrations – telescope
1489 * 4=internal calibrations – building
1490 * 5=burst calibrations
1491 * 6=other
1492 */
1493 private final int typeIndicator;
1494
1495 /**
1496 * Calibration Shift Type Indicator.
1497 * 0=not used or undefined
1498 * 1=nominal (from once off assessment)
1499 * 2=pre- to post- Shift
1500 * 3=minimum to maximum
1501 * 4=other
1502 */
1503 private final int shiftTypeIndicator;
1504
1505 /** Detector Channel.
1506 * 0=not applicable or “all”
1507 * 1-4 for quadrant
1508 * 1-n for many channels
1509 */
1510 private final int detectorChannel;
1511
1512 /**
1513 * Calibration Span.
1514 * 0 = not applicable (e.g. Calibration type indicator is “nominal”)
1515 * 1 = Pre-calibration only
1516 * 2 = Post-calibration only
1517 * 3 = Combined (pre- and post-calibrations or multiple)
1518 * 4 = Real-time calibration (data taken while ranging to a satellite)
1519 */
1520 private final int span;
1521
1522 /** Return Rate (%). */
1523 private final double returnRate;
1524
1525 /**
1526 * Constructor.
1527 * @param date data epoch
1528 * @param typeOfData type of data
1529 * @param systemConfigurationId system configuration id
1530 * @param numberOfPointsRecorded number of data points recorded
1531 * @param numberOfPointsUsed number of data points used
1532 * @param oneWayDistance one-way target distance (nominal)
1533 * @param systemDelay calibration system delay
1534 * @param delayShift calibration delay shift - a measure of calibration stability
1535 * @param rms RMS of raw system delay
1536 * @param skew skew of raw system delay values from the mean.
1537 * @param kurtosis kurtosis of raw system delay values from the mean.
1538 * @param peakMinusMean system delay peak – mean value
1539 * @param typeIndicator calibration type indicator
1540 * @param shiftTypeIndicator calibration shift type indicator
1541 * @param detectorChannel detector channel
1542 * @param span calibration span
1543 * @param returnRate return rate (%)
1544 */
1545 public Calibration(final AbsoluteDate date, final int typeOfData,
1546 final String systemConfigurationId,
1547 final int numberOfPointsRecorded,
1548 final int numberOfPointsUsed,
1549 final double oneWayDistance,
1550 final double systemDelay, final double delayShift,
1551 final double rms, final double skew,
1552 final double kurtosis, final double peakMinusMean,
1553 final int typeIndicator, final int shiftTypeIndicator,
1554 final int detectorChannel, final int span,
1555 final double returnRate) {
1556 this.date = date;
1557 this.typeOfData = typeOfData;
1558 this.systemConfigurationId = systemConfigurationId;
1559 this.numberOfPointsRecorded = numberOfPointsRecorded;
1560 this.numberOfPointsUsed = numberOfPointsUsed;
1561 this.systemDelay = systemDelay;
1562 this.delayShift = delayShift;
1563 this.rms = rms;
1564 this.skew = skew;
1565 this.kurtosis = kurtosis;
1566 this.peakMinusMean = peakMinusMean;
1567 this.typeIndicator = typeIndicator;
1568 this.shiftTypeIndicator = shiftTypeIndicator;
1569 this.detectorChannel = detectorChannel;
1570 this.span = span;
1571 this.returnRate = returnRate;
1572 this.oneWayDistance = oneWayDistance == -1 ? Double.NaN : oneWayDistance; // -1=na
1573 }
1574
1575 @Override
1576 public AbsoluteDate getDate() {
1577 return date;
1578 }
1579
1580 /**
1581 * Get the type of data.
1582 *
1583 * <ul>
1584 * <li>0=station combined transmit and receive calibration (“normal” SLR/LLR)
1585 * <li>1=station transmit calibration (e.g., one-way ranging to transponders)
1586 * <li>2=station receive calibration
1587 * <li>3=target combined transmit and receive calibrations
1588 * <li>4=target transmit calibration
1589 * <li>5=target receive calibration
1590 * </ul>
1591 * @return the type of data
1592 */
1593 public int getTypeOfData() {
1594 return typeOfData;
1595 }
1596
1597 /**
1598 * Get the system configuration id.
1599 * @return the system configuration id
1600 */
1601 public String getSystemConfigurationId() {
1602 return systemConfigurationId;
1603 }
1604
1605 /**
1606 * Get the number of data points recorded.
1607 * @return the number of data points recorded, -1 if no information
1608 */
1609 public int getNumberOfPointsRecorded() {
1610 return numberOfPointsRecorded;
1611 }
1612
1613 /**
1614 * Get the number of data points used.
1615 * @return the number of data points used, -1 if no information
1616 */
1617 public int getNumberOfPointsUsed() {
1618 return numberOfPointsUsed;
1619 }
1620
1621 /**
1622 * Get the one-way target distance (nominal).
1623 * @return the one-way target distance (nominal)
1624 */
1625 public double getOneWayDistance() {
1626 return oneWayDistance;
1627 }
1628
1629 /**
1630 * Get the calibration system delay.
1631 * @return the calibration system delay
1632 */
1633 public double getSystemDelay() {
1634 return systemDelay;
1635 }
1636
1637 /**
1638 * Get the calibration delay shift.
1639 * @return the calibration delay shift
1640 */
1641 public double getDelayShift() {
1642 return delayShift;
1643 }
1644
1645 /**
1646 * Get the rms of raw system delay.
1647 * @return the rms of raw system delay
1648 */
1649 public double getRms() {
1650 return rms;
1651 }
1652
1653 /**
1654 * Get the skew of raw system delay values from the mean.
1655 * @return the skew of raw system delay values from the mean.
1656 */
1657 public double getSkew() {
1658 return skew;
1659 }
1660
1661 /**
1662 * Get the kurtosis of raw system delay values from the mean.
1663 * @return the kurtosis of raw system delay values from the mean.
1664 */
1665 public double getKurtosis() {
1666 return kurtosis;
1667 }
1668
1669 /**
1670 * Get the system delay peak – mean value.
1671 * @return the system delay peak – mean value
1672 */
1673 public double getPeakMinusMean() {
1674 return peakMinusMean;
1675 }
1676
1677 /**
1678 * Get the calibration type indicator.
1679 *
1680 * <ul>
1681 * <li>0=not used or undefined
1682 * <li>1=nominal (from once off assessment)
1683 * <li>2=external calibrations
1684 * <li>3=internal calibrations – telescope
1685 * <li>4=internal calibrations – building
1686 * <li>5=burst calibrations
1687 * <li>6=other
1688 * </ul>
1689 * @return the calibration type indicator
1690 */
1691 public int getTypeIndicator() {
1692 return typeIndicator;
1693 }
1694
1695 /**
1696 * Get the calibration shift type indicator.
1697 *
1698 * <ul>
1699 * <li>0=not used or undefined
1700 * <li>1=nominal (from once off assessment)
1701 * <li>2=pre- to post- Shift
1702 * <li>3=minimum to maximum
1703 * <li>4=other
1704 * </ul>
1705 * @return the calibration shift type indicator
1706 */
1707 public int getShiftTypeIndicator() {
1708 return shiftTypeIndicator;
1709 }
1710
1711 /**
1712 * Get the detector channel.
1713 *
1714 * <ul>
1715 * <li>0=not applicable or “all”
1716 * <li>1-4 for quadrant
1717 * <li>1-n for many channels
1718 * </ul>
1719 * @return the detector channel
1720 */
1721 public int getDetectorChannel() {
1722 return detectorChannel;
1723 }
1724
1725 /**
1726 * Get the calibration span.
1727 *
1728 * <ul>
1729 * <li>0 = not applicable (e.g. Calibration type indicator is “nominal”)
1730 * <li>1 = Pre-calibration only
1731 * <li>2 = Post-calibration only
1732 * <li>3 = Combined (pre- and post-calibrations or multiple)
1733 * <li>4 = Real-time calibration (data taken while ranging to a satellite)
1734 * </ul>
1735 * @return the calibration span
1736 */
1737 public int getSpan() {
1738 return span;
1739 }
1740
1741 /**
1742 * Get the return rate.
1743 * @return the return rate
1744 */
1745 public double getReturnRate() {
1746 return returnRate;
1747 }
1748
1749 /**
1750 * Get a string representation of the instance in the CRD format.
1751 * @return a string representation of the instance, in the CRD format.
1752 */
1753 @DefaultDataContext
1754 public String toCrdString() {
1755 return String.format(Locale.US, "40 %s", toString());
1756 }
1757
1758 @Override
1759 @DefaultDataContext
1760 public String toString() {
1761 // CRD suggested format, excluding the record type
1762 // systemDelay, delayShift: s --> ps
1763 // rms, peakMinusMean: s --> ps
1764 // 'local' is already utc.
1765 // Seconds of day (sod) is typically to 1 milllisec precision.
1766 final double sod = getDate().
1767 getComponents(TimeScalesFactory.getUTC()).
1768 roundIfNeeded(60, 12).
1769 getTime().
1770 getSecondsInLocalDay();
1771
1772 final String str = String.format(
1773 "%18.12f %1d %4s %8s %8s %8.4f %10.1f %8.1f %6.1f %7.3f %7.3f %6.1f %1d %1d %1d %1d %5.1f",
1774 sod, typeOfData, systemConfigurationId,
1775 formatIntegerOrNaN(numberOfPointsRecorded, -1),
1776 formatIntegerOrNaN(numberOfPointsUsed, -1), oneWayDistance,
1777 systemDelay * 1e12, delayShift * 1e12, rms * 1e12, skew,
1778 kurtosis, peakMinusMean * 1e12, typeIndicator,
1779 shiftTypeIndicator, detectorChannel, span, returnRate);
1780 return handleNaN(str).replace(',', '.');
1781 }
1782
1783 }
1784
1785 /**
1786 * Calibration Detail Record.
1787 * @since 12.0
1788 */
1789 public static class CalibrationDetail extends Calibration {
1790 // same as Calibration record except that the record type is '41' rather than '40'.
1791
1792 /**
1793 * Constructor.
1794 * @param date data epoch
1795 * @param typeOfData type of data
1796 * @param systemConfigurationId system configuration id
1797 * @param numberOfPointsRecorded number of data points recorded
1798 * @param numberOfPointsUsed number of data points used
1799 * @param oneWayDistance one-way target distance (nominal)
1800 * @param systemDelay calibration system delay
1801 * @param delayShift calibration delay shift - a measure of calibration stability
1802 * @param rms RMS of raw system delay
1803 * @param skew skew of raw system delay values from the mean.
1804 * @param kurtosis kurtosis of raw system delay values from the mean.
1805 * @param peakMinusMean system delay peak – mean value
1806 * @param typeIndicator calibration type indicator
1807 * @param shiftTypeIndicator calibration shift type indicator
1808 * @param detectorChannel detector channel
1809 * @param span calibration span
1810 * @param returnRate return rate (%)
1811 */
1812 public CalibrationDetail(final AbsoluteDate date, final int typeOfData,
1813 final String systemConfigurationId,
1814 final int numberOfPointsRecorded,
1815 final int numberOfPointsUsed, final double oneWayDistance,
1816 final double systemDelay, final double delayShift,
1817 final double rms, final double skew, final double kurtosis,
1818 final double peakMinusMean, final int typeIndicator,
1819 final int shiftTypeIndicator, final int detectorChannel,
1820 final int span, final double returnRate) {
1821 super(date, typeOfData, systemConfigurationId, numberOfPointsRecorded,
1822 numberOfPointsUsed, oneWayDistance, systemDelay, delayShift, rms, skew,
1823 kurtosis, peakMinusMean, typeIndicator, shiftTypeIndicator,
1824 detectorChannel, span, returnRate);
1825 }
1826
1827 /**
1828 * Get a string representation of the instance in the CRD format.
1829 * @return a string representation of the instance, in the CRD format.
1830 */
1831 @DefaultDataContext
1832 public String toCrdString() {
1833 return String.format(Locale.US, "41 %s", toString());
1834 }
1835
1836 }
1837
1838 /**
1839 * Session (Pass) Statistics Record.
1840 * @since 12.0
1841 */
1842 public static class SessionStatistics {
1843
1844 /** System configuration ID. */
1845 private final String systemConfigurationId;
1846
1847 /** Session RMS from the mean of raw accepted time-of-flight values minus the trend function. */
1848 private final double rms;
1849
1850 /** Session skewness from the mean of raw accepted time-of-flight values minus the trend function. */
1851 private final double skewness;
1852
1853 /** Session kurtosis from the mean of raw accepted time-of-flight values minus the trend function. */
1854 private final double kurtosis;
1855
1856 /** Session peak – mean value. */
1857 private final double peakMinusMean;
1858
1859 /**
1860 * Data quality assessment indicator.
1861 * <ul>
1862 * <li>0=undefined or no comment</li>
1863 * <li>1=clear, easily filtered data, with little or no noise</li>
1864 * <li>2=clear data with some noise; filtering is slightly compromised by noise level</li>
1865 * <li>3=clear data with a significant amount of noise, or weak data with little noise. Data are certainly
1866 * present, but filtering is difficult.</li>
1867 * <li>4=unclear data; data appear marginally to be present, but are very difficult to separate from noise
1868 * during filtering. Signal to noise ratio can be less than 1:1.</li>
1869 * <li>5=no data apparent</li>
1870 * </ul>
1871 */
1872 private final int dataQulityIndicator;
1873
1874 /**
1875 * Constructor.
1876 * @param systemConfigurationId system configuration ID
1877 * @param rms session RMS from the mean of raw accepted time-of-flight values minus the trend function
1878 * @param skewness session skewness from the mean of raw accepted time-of-flight values minus the trend function
1879 * @param kurtosis session kurtosis from the mean of raw accepted time-of-flight values minus the trend function
1880 * @param peakMinusMean session peak – mean value
1881 * @param dataQulityIndicator data quality assessment indicator
1882 */
1883 public SessionStatistics(final String systemConfigurationId,
1884 final double rms, final double skewness,
1885 final double kurtosis,
1886 final double peakMinusMean,
1887 final int dataQulityIndicator) {
1888 this.systemConfigurationId = systemConfigurationId;
1889 this.rms = rms;
1890 this.skewness = skewness;
1891 this.kurtosis = kurtosis;
1892 this.peakMinusMean = peakMinusMean;
1893 this.dataQulityIndicator = dataQulityIndicator;
1894 }
1895
1896 /**
1897 * Get system configuration id.
1898 * @return the system configuration id
1899 */
1900 public String getSystemConfigurationId() {
1901 return systemConfigurationId;
1902 }
1903
1904 /**
1905 * Get the session RMS from the mean of raw accepted time-of-flight values minus the trend function.
1906 * @return the session RMS
1907 */
1908 public double getRms() {
1909 return rms;
1910 }
1911
1912 /**
1913 * Get the session skewness from the mean of raw accepted time-of-flight values minus the trend function.
1914 * @return the session skewness
1915 */
1916 public double getSkewness() {
1917 return skewness;
1918 }
1919
1920 /**
1921 * Get the session kurtosis from the mean of raw accepted time-of-flight values minus the trend function.
1922 * @return the session kurtosis
1923 */
1924 public double getKurtosis() {
1925 return kurtosis;
1926 }
1927
1928 /**
1929 * Get the session peak – mean value.
1930 * @return the session peak – mean value
1931 */
1932 public double getPeakMinusMean() {
1933 return peakMinusMean;
1934 }
1935
1936 /**
1937 * Get the data quality assessment indicator
1938 * <ul>
1939 * <li>0=undefined or no comment</li>
1940 * <li>1=clear, easily filtered data, with little or no noise</li>
1941 * <li>2=clear data with some noise; filtering is slightly compromised by noise level</li>
1942 * <li>3=clear data with a significant amount of noise, or weak data with little noise. Data are certainly
1943 * present, but filtering is difficult.</li>
1944 * <li>4=unclear data; data appear marginally to be present, but are very difficult to separate from noise
1945 * during filtering. Signal to noise ratio can be less than 1:1.</li>
1946 * <li>5=no data apparent</li>
1947 * </ul>
1948 * @return the data quality assessment indicator
1949 */
1950 public int getDataQulityIndicator() {
1951 return dataQulityIndicator;
1952 }
1953
1954 /**
1955 * Get a string representation of the instance in the CRD format.
1956 * @return a string representation of the instance, in the CRD format.
1957 */
1958 public String toCrdString() {
1959 return String.format(Locale.US, "50 %s", toString());
1960 }
1961
1962 @Override
1963 public String toString() {
1964 // CRD suggested format, excluding the record type
1965 // rms, peakMinusMean: s --> ps
1966 final String str = String.format(Locale.US, "%4s %6.1f %7.3f %7.3f %6.1f %1d",
1967 systemConfigurationId, rms * 1e12, skewness, kurtosis,
1968 peakMinusMean * 1e12, dataQulityIndicator);
1969 return handleNaN(str).replace(',', '.');
1970 }
1971
1972 }
1973
1974 }