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