CRDConfiguration.java

  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. import java.util.ArrayList;
  19. import java.util.Arrays;
  20. import java.util.Collections;
  21. import java.util.Hashtable;
  22. import java.util.List;
  23. import java.util.Locale;
  24. import java.util.Map;
  25. import java.util.Set;
  26. import java.util.regex.Pattern;

  27. /**
  28.  * Container for Consolidated laser ranging Data Format (CDR) configuration records.
  29.  * @author Bryan Cazabonne
  30.  * @author Rongwang Li
  31.  * @since 10.3
  32.  */
  33. public class CRDConfiguration {

  34.     /** Dict of configuration record. **/
  35.     private final Map<String, BaseConfiguration> mapConfigurationRecords;

  36.     /** List of system configuration. **/
  37.     private final List<SystemConfiguration> systemConfigurationRecords;

  38.     /**
  39.      * Constructor.
  40.      */
  41.     public CRDConfiguration() {
  42.         systemConfigurationRecords = new ArrayList<>();
  43.         mapConfigurationRecords = new Hashtable<>();
  44.     }

  45.     /**
  46.      * Get the system configuration record.
  47.      * @return the system configuration record
  48.      */
  49.     public SystemConfiguration getSystemRecord() {
  50.         return systemConfigurationRecords.isEmpty() ? null : systemConfigurationRecords.get(0);
  51.     }

  52.     /**
  53.      * Get the system configuration record.
  54.      * @return the system configuration record
  55.      */
  56.     public SystemConfiguration getLastSystemRecord() {
  57.         return systemConfigurationRecords.isEmpty() ? null : systemConfigurationRecords.get(systemConfigurationRecords.size() - 1);
  58.     }

  59.     /**
  60.      * Get the laser configuration record.
  61.      * @return the laser configuration record
  62.      */
  63.     public LaserConfiguration getLaserRecord() {
  64.         return getLaserRecord(getSystemRecord());
  65.     }

  66.     /**
  67.      * Get the detector configuration record.
  68.      * @return the detector configuration record
  69.      */
  70.     public DetectorConfiguration getDetectorRecord() {
  71.         return getDetectorRecord(getSystemRecord());
  72.     }

  73.     /**
  74.      * Get the timing system configuration record.
  75.      * @return the timing system configuration record
  76.      */
  77.     public TimingSystemConfiguration getTimingRecord() {
  78.         return getTimingRecord(getSystemRecord());
  79.     }

  80.     /**
  81.      * Get the transponder configuration record.
  82.      * @return the transponder configuration record
  83.      */
  84.     public TransponderConfiguration getTransponderRecord() {
  85.         return getTransponderRecord(getSystemRecord());
  86.     }


  87.     /**
  88.      * Get the software configuration record.
  89.      * @return the software configuration record
  90.      */
  91.     public SoftwareConfiguration getSoftwareRecord() {
  92.         return getSoftwareRecord(getSystemRecord());
  93.     }

  94.     /**
  95.      * Get the meteorological record.
  96.      * @return the meteorological record
  97.      */
  98.     public MeteorologicalConfiguration getMeteorologicalRecord() {
  99.         return getMeteorologicalRecord(getSystemRecord());
  100.     }

  101.     /**
  102.      * Add a configuration record, such as SystemConfiguation, LaserConfiguration, DetectorConfiguration, etc.
  103.      * @param config the configuration record
  104.      * @since 12.0
  105.      */
  106.     public void addConfigurationRecord(final BaseConfiguration config) {
  107.         if (config == null) {
  108.             return;
  109.         }

  110.         mapConfigurationRecords.put(config.getConfigurationId(), config);

  111.         if (config instanceof SystemConfiguration) {
  112.             // Add to the list systemConfigurationRecords if it is a SystemConfiguration
  113.             systemConfigurationRecords.add((SystemConfiguration) config);
  114.         }
  115.     }

  116.     /**
  117.      * Get the configuration records map.
  118.      * @return the configuration records map
  119.      * @since 12.0
  120.      */
  121.     public Map<String, BaseConfiguration> getConfigurationRecordMap() {
  122.         return Collections.unmodifiableMap(mapConfigurationRecords);
  123.     }

  124.     /**
  125.      * Get configuration record corresponding to the configId.
  126.      * @param configId the id of configuration
  127.      * @return the configuration with configId, or null
  128.      * @since 12.0
  129.      */
  130.     public BaseConfiguration getConfigurationRecord(final String configId) {
  131.         return mapConfigurationRecords.get(configId);
  132.     }

  133.     /**
  134.      * Get a set of configuration ids.
  135.      * @return an unmodifiable set of configuration ids
  136.      * @since 12.0
  137.      */
  138.     public Set<String> getSystemConfigurationIds() {
  139.         return Collections.unmodifiableSet(mapConfigurationRecords.keySet());
  140.     }

  141.     /**
  142.      * Get a list of system configurations.
  143.      * @return an unmodifiable list of system configurations
  144.      * @since 12.0
  145.      */
  146.     public List<SystemConfiguration> getSystemConfigurationRecords() {
  147.         return Collections.unmodifiableList(systemConfigurationRecords);
  148.     }

  149.     /**
  150.      * Get configuration record related to systemRecord and the given class.
  151.      * @param systemRecord system configuration record
  152.      * @param c the class, such as LaserConfiguration, DetectorConfiguration, TimingSystemConfiguration, etc
  153.      * @return the configuration record
  154.      * @since 12.0
  155.      */
  156.     private BaseConfiguration getRecord(final SystemConfiguration systemRecord,
  157.             final Class<? extends BaseConfiguration> c) {
  158.         BaseConfiguration config;
  159.         for (final String configId : systemRecord.getComponents()) {
  160.             config = getConfigurationRecord(configId);
  161.             if (config != null && config.getClass() == c) {
  162.                 return config;
  163.             }
  164.         }

  165.         return null;
  166.     }

  167.     /**
  168.      * Get system configuration record. If configId is null, the default(first system configuration record) is returned.
  169.      * @param configId system configuration id, it can be null.
  170.      * @return the system configuration record
  171.      * @since 12.0
  172.      */
  173.     public SystemConfiguration getSystemRecord(final String configId) {
  174.         if (configId == null) {
  175.             // default
  176.             return getSystemRecord();
  177.         }

  178.         final BaseConfiguration config = mapConfigurationRecords.get(configId);
  179.         return config == null ? null : (SystemConfiguration) config;
  180.     }

  181.     /**
  182.      * Get laser configuration record related to the systemRecord.
  183.      * @param systemRecord the system configuration
  184.      * @return the laser configuration record related the the systemRecord
  185.      * @since 12.0
  186.      */
  187.     public LaserConfiguration getLaserRecord(final SystemConfiguration systemRecord) {
  188.         final BaseConfiguration config = getRecord(systemRecord, LaserConfiguration.class);
  189.         return config == null ? null : (LaserConfiguration) config;
  190.     }

  191.     /**
  192.      * Get detector configuration record related to the systemRecord.
  193.      * @param systemRecord the system configuration
  194.      * @return the detector configuration record related the the systemRecord
  195.      * @since 12.0
  196.      */
  197.     public DetectorConfiguration getDetectorRecord(final SystemConfiguration systemRecord) {
  198.         final BaseConfiguration config = getRecord(systemRecord, DetectorConfiguration.class);
  199.         return config == null ? null : (DetectorConfiguration) config;
  200.     }

  201.     /**
  202.      * Get timing system configuration record related to the systemRecord.
  203.      * @param systemRecord the system configuration
  204.      * @return the timing system configuration record related the the systemRecord
  205.      * @since 12.0
  206.      */
  207.     public TimingSystemConfiguration getTimingRecord(final SystemConfiguration systemRecord) {
  208.         final BaseConfiguration config = getRecord(systemRecord, TimingSystemConfiguration.class);
  209.         return config == null ? null : (TimingSystemConfiguration) config;
  210.     }

  211.     /**
  212.      * Get transponder configuration record related to the systemRecord.
  213.      * @param systemRecord the system configuration
  214.      * @return the transponder configuration record related the the systemRecord
  215.      * @since 12.0
  216.      */
  217.     public TransponderConfiguration getTransponderRecord(final SystemConfiguration systemRecord) {
  218.         final BaseConfiguration config = getRecord(systemRecord, TransponderConfiguration.class);
  219.         return config == null ? null : (TransponderConfiguration) config;
  220.     }

  221.     /**
  222.      * Get software configuration record related to the systemRecord.
  223.      * @param systemRecord the system configuration
  224.      * @return the software configuration record related the the systemRecord
  225.      * @since 12.0
  226.      */
  227.     public SoftwareConfiguration getSoftwareRecord(final SystemConfiguration systemRecord) {
  228.         final BaseConfiguration config = getRecord(systemRecord, SoftwareConfiguration.class);
  229.         return config == null ? null : (SoftwareConfiguration) config;
  230.     }

  231.     /**
  232.      * Get meteorological configuration record related to the systemRecord.
  233.      * @param systemRecord the system configuration
  234.      * @return the meteorological configuration record related the the systemRecord
  235.      * @since 12.0
  236.      */
  237.     public MeteorologicalConfiguration getMeteorologicalRecord(final SystemConfiguration systemRecord) {
  238.         final BaseConfiguration config = getRecord(systemRecord, MeteorologicalConfiguration.class);
  239.         return config == null ? null : (MeteorologicalConfiguration) config;
  240.     }

  241.     /**
  242.      * Get calibration target configuration record related to the systemRecord.
  243.      * @param systemRecord the system configuration
  244.      * @return the calibration target configuration record related the the systemRecord
  245.      * @since 12.0
  246.      */
  247.     public CalibrationTargetConfiguration getCalibrationTargetRecord(final SystemConfiguration systemRecord) {
  248.         final BaseConfiguration config = getRecord(systemRecord, CalibrationTargetConfiguration.class);
  249.         return config == null ? null : (CalibrationTargetConfiguration) config;
  250.     }

  251.     /**
  252.      * Get the calibration target configuration record.
  253.      * @return the calibration target configuration record
  254.      * @since 12.0
  255.      */
  256.     public CalibrationTargetConfiguration getCalibrationTargetRecord() {
  257.         return getCalibrationTargetRecord(getSystemRecord());
  258.     }

  259.     /**
  260.      * Base class for configuration record.
  261.      * @since 12.0
  262.      */
  263.     public abstract static class BaseConfiguration {

  264.         /** Configuration ID. */
  265.         private String configurationId;

  266.         /** Empty constructor.
  267.          * <p>
  268.          * This constructor is not strictly necessary, but it prevents spurious
  269.          * javadoc warnings with JDK 18 and later.
  270.          * </p>
  271.          * @since 12.0
  272.          */
  273.         public BaseConfiguration() {
  274.             // nothing to do
  275.         }

  276.         /**
  277.          * Get the configuration ID.
  278.          * @return the configuration ID
  279.          */
  280.         public String getConfigurationId() {
  281.             return configurationId;
  282.         }

  283.         /**
  284.          * Set the configuration ID.
  285.          * @param configurationId the configuration ID to set
  286.          */
  287.         public void setConfigurationId(final String configurationId) {
  288.             this.configurationId = configurationId;
  289.         }

  290.         @Override
  291.         public int hashCode() {
  292.             return toString().hashCode();
  293.         }

  294.         @Override
  295.         public boolean equals(final Object record) {
  296.             if (record == null) {
  297.                 return false;
  298.             }

  299.             if (record == this) {
  300.                 return true;
  301.             }

  302.             return toString().equals(record.toString());

  303.         }

  304.         /**
  305.          * Get a string representation of the instance in the CRD format.
  306.          * @return a string representation of the instance, in the CRD format.
  307.          * @since 12.0
  308.          */
  309.         public abstract String toCrdString();
  310.     }

  311.     /** Container for system configuration record. */
  312.     public static class SystemConfiguration extends BaseConfiguration {

  313.         /** Transmit Wavelength [m]. */
  314.         private double wavelength;

  315.         /** List of components. **/
  316.         private List<String> components;

  317.         /**
  318.          * Constructor.
  319.          */
  320.         public SystemConfiguration() {
  321.             this.components = new ArrayList<>();
  322.         }

  323.         /**
  324.          * Get the transmit wavelength.
  325.          * @return the transmit wavelength in meters
  326.          */
  327.         public double getWavelength() {
  328.             return wavelength;
  329.         }

  330.         /**
  331.          * Set the transmit wavelength.
  332.          * @param wavelength the wavelength to set
  333.          */
  334.         public void setWavelength(final double wavelength) {
  335.             this.wavelength = wavelength;
  336.         }

  337.         /**
  338.          * Get the system configuration ID.
  339.          * @return the system configuration ID
  340.          */
  341.         public String getSystemId() {
  342.             return getConfigurationId();
  343.         }

  344.         /**
  345.          * Set the system configuration ID.
  346.          * @param systemId the system configuration ID to set
  347.          */
  348.         public void setSystemId(final String systemId) {
  349.             setConfigurationId(systemId);
  350.         }

  351.         /**
  352.          * Get the components (config ids) for system configuration.
  353.          * @return an unmodifiable list of components
  354.          * @since 12.0
  355.          */
  356.         public List<String> getComponents() {
  357.             return Collections.unmodifiableList(components);
  358.         }

  359.         /**
  360.          * Set the components (config ids) for system configuration.
  361.          * @param components the components (config ids)
  362.          * @since 12.0
  363.          */
  364.         public void setComponents(final String[] components) {
  365.             this.components = Arrays.asList(components);
  366.         }

  367.         /** {@inheritDoc} */
  368.         @Override
  369.         public String toCrdString() {
  370.             return String.format(Locale.US, "C0 0 %s", toString());
  371.         }

  372.         @Override
  373.         public String toString() {
  374.             // CRD suggested format, excluding the record type
  375.             final StringBuilder sb = new StringBuilder();
  376.             sb.append(String.format(Locale.US, "%10.3f %s", wavelength * 1e9, getConfigurationId()));
  377.             for (final String comp : components) {
  378.                 sb.append(String.format(Locale.US, " %s", comp));
  379.             }
  380.             return sb.toString().replace(',', '.');
  381.         }
  382.     }

  383.     /** Container for laser configuration record. */
  384.     public static class LaserConfiguration extends BaseConfiguration {

  385.         /** Laser Type. */
  386.         private String laserType;

  387.         /** Primary wavelength [m]. */
  388.         private double primaryWavelength;

  389.         /** Nominal Fire Rate [Hz]. */
  390.         private double nominalFireRate;

  391.         /** Pulse Energy [mJ]. */
  392.         private double pulseEnergy;

  393.         /** Pulse Width [ps]. */
  394.         private double pulseWidth;

  395.         /** Bean divergence [arcsec]. */
  396.         private double beamDivergence;

  397.         /** Number of pulses in outgoing semi-train. */
  398.         private int pulseInOutgoingSemiTrain;

  399.         /** Empty constructor.
  400.          * <p>
  401.          * This constructor is not strictly necessary, but it prevents spurious
  402.          * javadoc warnings with JDK 18 and later.
  403.          * </p>
  404.          * @since 12.0
  405.          */
  406.         public LaserConfiguration() {
  407.             // nothing to do
  408.         }

  409.         /**
  410.          * Get the laser configuration ID.
  411.          * @return the laser configuration ID
  412.          */
  413.         public String getLaserId() {
  414.             return getConfigurationId();
  415.         }

  416.         /**
  417.          * Set the laser configuration ID.
  418.          * @param laserId the laser configuration ID to set
  419.          */
  420.         public void setLaserId(final String laserId) {
  421.             setConfigurationId(laserId);
  422.         }

  423.         /**
  424.          * Get the laser type.
  425.          * @return the laser type
  426.          */
  427.         public String getLaserType() {
  428.             return laserType;
  429.         }

  430.         /**
  431.          * Set the laser type.
  432.          * @param laserType the laser type to set
  433.          */
  434.         public void setLaserType(final String laserType) {
  435.             this.laserType = laserType;
  436.         }

  437.         /**
  438.          * Get the primary wavelength.
  439.          * @return the primary wavelength in meters
  440.          */
  441.         public double getPrimaryWavelength() {
  442.             return primaryWavelength;
  443.         }

  444.         /**
  445.          * Set the primary wavelength.
  446.          * @param primaryWavelength the primary wavelength to set in meters
  447.          */
  448.         public void setPrimaryWavelength(final double primaryWavelength) {
  449.             this.primaryWavelength = primaryWavelength;
  450.         }

  451.         /**
  452.          * Get the nominal fire rate.
  453.          * @return the nominal fire rate in Hz.
  454.          */
  455.         public double getNominalFireRate() {
  456.             return nominalFireRate;
  457.         }

  458.         /**
  459.          * Set the nominal fire rate.
  460.          * @param nominalFireRate the nominal fire rate to set in Hz
  461.          */
  462.         public void setNominalFireRate(final double nominalFireRate) {
  463.             this.nominalFireRate = nominalFireRate;
  464.         }

  465.         /**
  466.          * Get the pulse energy.
  467.          * @return the pulse energy in mJ
  468.          */
  469.         public double getPulseEnergy() {
  470.             return pulseEnergy;
  471.         }

  472.         /**
  473.          * Set the pulse energy.
  474.          * @param pulseEnergy the pulse energy to set in mJ
  475.          */
  476.         public void setPulseEnergy(final double pulseEnergy) {
  477.             this.pulseEnergy = pulseEnergy;
  478.         }

  479.         /**
  480.          * Get the pulse width (FWHM in ps).
  481.          * @return the pulse width
  482.          */
  483.         public double getPulseWidth() {
  484.             return pulseWidth;
  485.         }

  486.         /**
  487.          * Set the pulse width.
  488.          * @param pulseWidth the pulse width to set, ps
  489.          */
  490.         public void setPulseWidth(final double pulseWidth) {
  491.             this.pulseWidth = pulseWidth;
  492.         }

  493.         /**
  494.          * Get the beam divergence.
  495.          * @return the beam divergence in arcsec
  496.          */
  497.         public double getBeamDivergence() {
  498.             return beamDivergence;
  499.         }

  500.         /**
  501.          * Set the beam divergence.
  502.          * @param beamDivergence the beam divergence to set in arcsec
  503.          */
  504.         public void setBeamDivergence(final double beamDivergence) {
  505.             this.beamDivergence = beamDivergence;
  506.         }

  507.         /**
  508.          * Get the number of pulses in outgoing semi-train.
  509.          * @return the number of pulses in outgoing semi-train
  510.          */
  511.         public int getPulseInOutgoingSemiTrain() {
  512.             return pulseInOutgoingSemiTrain;
  513.         }

  514.         /**
  515.          * Set the number of pulses in outgoing semi-train.
  516.          * @param pulseInOutgoingSemiTrain the number of pulses in outgoing semi-train to set
  517.          */
  518.         public void setPulseInOutgoingSemiTrain(final int pulseInOutgoingSemiTrain) {
  519.             this.pulseInOutgoingSemiTrain = pulseInOutgoingSemiTrain;
  520.         }

  521.         /** {@inheritDoc} */
  522.         @Override
  523.         public String toCrdString() {
  524.             return String.format(Locale.US, "C1 0 %s", toString());
  525.         }

  526.         @Override
  527.         public String toString() {
  528.             // CRD suggested format, excluding the record type
  529.             // primaryWavelength: m --> nm
  530.             final String str = String.format(Locale.US,
  531.                     "%s %s %.2f %.2f %.2f %.1f %.2f %d", getConfigurationId(),
  532.                     laserType, primaryWavelength * 1e9, nominalFireRate,
  533.                     pulseEnergy, pulseWidth, beamDivergence,
  534.                     pulseInOutgoingSemiTrain);
  535.             return CRD.handleNaN(str).replace(',', '.');
  536.         }

  537.     }

  538.     /** Container for detector configuration record. */
  539.     public static class DetectorConfiguration extends BaseConfiguration {

  540.         /** Detector Type. */
  541.         private String detectorType;

  542.         /** Applicable wavelength. */
  543.         private double applicableWavelength;

  544.         /** Quantum efficiency at applicable wavelength [%]. */
  545.         private double quantumEfficiency;

  546.         /** Applied voltage [V]. */
  547.         private double appliedVoltage;

  548.         /** Dark Count [Hz]. */
  549.         private double darkCount;

  550.         /** Output pulse type. */
  551.         private String outputPulseType;

  552.         /** Output pulse width [ps]. */
  553.         private double outputPulseWidth;

  554.         /** Spectral Filter [m]. */
  555.         private double spectralFilter;

  556.         /** % Transmission of Spectral Filter. */
  557.         private double transmissionOfSpectralFilter;

  558.         /** Spatial Filter [arcsec]. */
  559.         private double spatialFilter;

  560.         /** External Signal processing. */
  561.         private String externalSignalProcessing;

  562.         /** Amplifier Gain. */
  563.         private double amplifierGain;

  564.         /** Amplifier Bandwidth [Hz]. */
  565.         private double amplifierBandwidth;

  566.         /** Amplifier In Use. */
  567.         private String amplifierInUse;

  568.         /** Empty constructor.
  569.          * <p>
  570.          * This constructor is not strictly necessary, but it prevents spurious
  571.          * javadoc warnings with JDK 18 and later.
  572.          * </p>
  573.          * @since 12.0
  574.          */
  575.         public DetectorConfiguration() {
  576.             // nothing to do
  577.         }

  578.         /**
  579.          * Get the detector configuration ID.
  580.          * @return the detector configuration ID
  581.          */
  582.         public String getDetectorId() {
  583.             return getConfigurationId();
  584.         }

  585.         /**
  586.          * Set the detector configuration ID.
  587.          * @param detectorId the detector configuration ID to set
  588.          */
  589.         public void setDetectorId(final String detectorId) {
  590.             setConfigurationId(detectorId);
  591.         }

  592.         /**
  593.          * Get the detector type.
  594.          * @return the detector type
  595.          */
  596.         public String getDetectorType() {
  597.             return detectorType;
  598.         }

  599.         /**
  600.          * Set the detector type.
  601.          * @param detectorType the detector type to set
  602.          */
  603.         public void setDetectorType(final String detectorType) {
  604.             this.detectorType = detectorType;
  605.         }

  606.         /**
  607.          * Get the applicable wavelength.
  608.          * @return pplicable wavelength in meters
  609.          */
  610.         public double getApplicableWavelength() {
  611.             return applicableWavelength;
  612.         }

  613.         /**
  614.          * Set the applicable wavelength.
  615.          * @param applicableWavelength the applicable wavelength to set in meters
  616.          */
  617.         public void setApplicableWavelength(final double applicableWavelength) {
  618.             this.applicableWavelength = applicableWavelength;
  619.         }

  620.         /**
  621.          * Get the quantum efficiency at applicable wavelength.
  622.          * @return the quantum efficiency at applicable wavelength in percents
  623.          */
  624.         public double getQuantumEfficiency() {
  625.             return quantumEfficiency;
  626.         }

  627.         /**
  628.          * Set the quantum efficiency at applicable wavelength.
  629.          * @param quantumEfficiency the efficiency to set in percents
  630.          */
  631.         public void setQuantumEfficiency(final double quantumEfficiency) {
  632.             // NOTE: The quantumEfficiency may be -1.0, which means 'not available'
  633.             if (quantumEfficiency == -1.0) {
  634.                 this.quantumEfficiency = Double.NaN;
  635.             } else {
  636.                 this.quantumEfficiency = quantumEfficiency;
  637.             }
  638.         }

  639.         /**
  640.          * Get the applied voltage.
  641.          * @return the applied voltage in Volts
  642.          */
  643.         public double getAppliedVoltage() {
  644.             return appliedVoltage;
  645.         }

  646.         /**
  647.          * Set the applied voltage.
  648.          * @param appliedVoltage the applied voltage to set in Volts
  649.          */
  650.         public void setAppliedVoltage(final double appliedVoltage) {
  651.             // NOTE: The quantumEfficiency may be -1.0, which means 'not available' or 'not applicable'
  652.             if (appliedVoltage == -1.0) {
  653.                 this.appliedVoltage = Double.NaN;
  654.             } else {
  655.                 this.appliedVoltage = appliedVoltage;
  656.             }
  657.         }

  658.         /**
  659.          * Get the dark count.
  660.          * @return the dark count in Hz
  661.          */
  662.         public double getDarkCount() {
  663.             return darkCount;
  664.         }

  665.         /**
  666.          * Set the dark count.
  667.          * @param darkCount the dark count to set in Hz
  668.          */
  669.         public void setDarkCount(final double darkCount) {
  670.          // NOTE: The quantumEfficiency may be -1.0, which means 'not available'
  671.             if (darkCount == -1.0e3) { // -1=na, kHz --> Hz
  672.                 this.darkCount = Double.NaN;
  673.             } else {
  674.                 this.darkCount = darkCount;
  675.             }
  676.         }

  677.         /**
  678.          * Get the output pulse type.
  679.          * @return the output pulse type
  680.          */
  681.         public String getOutputPulseType() {
  682.             return outputPulseType;
  683.         }

  684.         /**
  685.          * Set the output pulse type.
  686.          * @param outputPulseType the output pulse type to set
  687.          */
  688.         public void setOutputPulseType(final String outputPulseType) {
  689.             this.outputPulseType = outputPulseType;
  690.         }

  691.         /**
  692.          * Get the output pulse width.
  693.          * @return the output pulse width in ps
  694.          */
  695.         public double getOutputPulseWidth() {
  696.             return outputPulseWidth;
  697.         }

  698.         /**
  699.          * Set the output pulse width.
  700.          * @param outputPulseWidth the output pulse width to set in ps
  701.          */
  702.         public void setOutputPulseWidth(final double outputPulseWidth) {
  703.             // NOTE: The quantumEfficiency may be -1.0, which means 'not available' or 'not applicable'
  704.             if (outputPulseWidth == -1.0) {
  705.                 this.outputPulseWidth = Double.NaN;
  706.             } else {
  707.                 this.outputPulseWidth = outputPulseWidth;
  708.             }
  709.         }

  710.         /**
  711.          * Get the spectral filter.
  712.          * @return the spectral filter in meters
  713.          */
  714.         public double getSpectralFilter() {
  715.             return spectralFilter;
  716.         }

  717.         /**
  718.          * Set the spectral filter.
  719.          * @param spectralFilter  the spectral filter to set in meters
  720.          */
  721.         public void setSpectralFilter(final double spectralFilter) {
  722.             this.spectralFilter = spectralFilter;
  723.         }

  724.         /**
  725.          * Get the percentage of transmission of spectral filter.
  726.          * @return the percentage of transmission of spectral filter
  727.          */
  728.         public double getTransmissionOfSpectralFilter() {
  729.             return transmissionOfSpectralFilter;
  730.         }

  731.         /**
  732.          * Set the percentage of transmission of spectral filter.
  733.          * @param transmissionOfSpectralFilter the percentage to set
  734.          */
  735.         public void setTransmissionOfSpectralFilter(final double transmissionOfSpectralFilter) {
  736.             this.transmissionOfSpectralFilter = transmissionOfSpectralFilter;
  737.         }

  738.         /**
  739.          * Get the spatial filter.
  740.          * @return the spatial filter in arcsec
  741.          */
  742.         public double getSpatialFilter() {
  743.             return spatialFilter;
  744.         }

  745.         /**
  746.          * Set the spatial filter.
  747.          * @param spatialFilter the spatial filter to set in arcsec
  748.          */
  749.         public void setSpatialFilter(final double spatialFilter) {
  750.             this.spatialFilter = spatialFilter;
  751.         }

  752.         /**
  753.          * Get the external signal processing.
  754.          * @return the external signal processing
  755.          */
  756.         public String getExternalSignalProcessing() {
  757.             return externalSignalProcessing;
  758.         }

  759.         /**
  760.          * Set the external signal processing.
  761.          * @param externalSignalProcessing the external signal processing to set
  762.          */
  763.         public void setExternalSignalProcessing(final String externalSignalProcessing) {
  764.             this.externalSignalProcessing = externalSignalProcessing;
  765.         }

  766.         /**
  767.          * Get the amplifier gain.
  768.          * @return the amplifier gain
  769.          */
  770.         public double getAmplifierGain() {
  771.             return amplifierGain;
  772.         }

  773.         /**
  774.          * Set the amplifier gain.
  775.          * @param amplifierGain the amplifier gain to set
  776.          */
  777.         public void setAmplifierGain(final double amplifierGain) {
  778.             this.amplifierGain = amplifierGain;
  779.         }

  780.         /**
  781.          * Get the amplifier bandwidth.
  782.          * @return the amplifier bandwidth in Hz
  783.          */
  784.         public double getAmplifierBandwidth() {
  785.             return amplifierBandwidth;
  786.         }

  787.         /**
  788.          * Set the amplifier bandwidth.
  789.          * @param amplifierBandwidth the amplifier bandwidth to set in Hz
  790.          */
  791.         public void setAmplifierBandwidth(final double amplifierBandwidth) {
  792.             this.amplifierBandwidth = amplifierBandwidth;
  793.         }

  794.         /**
  795.          * Get the amplifier in use.
  796.          * @return the amplifier in use
  797.          */
  798.         public String getAmplifierInUse() {
  799.             return amplifierInUse;
  800.         }

  801.         /**
  802.          * Set the amplifier in use.
  803.          * @param amplifierInUse the amplifier in use to set
  804.          */
  805.         public void setAmplifierInUse(final String amplifierInUse) {
  806.             this.amplifierInUse = amplifierInUse;
  807.         }

  808.         /** {@inheritDoc} */
  809.         @Override
  810.         public String toCrdString() {
  811.             return String.format(Locale.US, "C2 0 %s", toString());
  812.         }

  813.         @Override
  814.         public String toString() {
  815.             // CRD suggested format, excluding the record type
  816.             // applicableWavelength, spectralFilter: m --> nm
  817.             // darkCount, amplifierBandwidth: Hz --> kHz
  818.             final String str = String.format(Locale.US,
  819.                     "%s %s %.3f %.2f %.1f %.1f %s %.1f %.2f %.1f %.1f %s %.1f %.1f %s",
  820.                     getConfigurationId(), detectorType,
  821.                     applicableWavelength * 1e9, quantumEfficiency,
  822.                     appliedVoltage, darkCount * 1e-3, outputPulseType,
  823.                     outputPulseWidth, spectralFilter * 1e9,
  824.                     transmissionOfSpectralFilter, spatialFilter,
  825.                     externalSignalProcessing, amplifierGain,
  826.                     amplifierBandwidth * 1e-3, amplifierInUse);
  827.             return CRD.handleNaN(str).replace(',', '.');
  828.         }
  829.     }

  830.     /** Container for timing system configuration record. */
  831.     public static class TimingSystemConfiguration extends BaseConfiguration {

  832.         /** Time Source. */
  833.         private String timeSource;

  834.         /** Frequency Source. */
  835.         private String frequencySource;

  836.         /** Timer. */
  837.         private String timer;

  838.         /** Timer Serial Number. */
  839.         private String timerSerialNumber;

  840.         /** Epoch delay correction [s]. */
  841.         private double epochDelayCorrection;

  842.         /** Empty constructor.
  843.          * <p>
  844.          * This constructor is not strictly necessary, but it prevents spurious
  845.          * javadoc warnings with JDK 18 and later.
  846.          * </p>
  847.          * @since 12.0
  848.          */
  849.         public TimingSystemConfiguration() {
  850.             // nothing to do
  851.         }

  852.         /**
  853.          * Get the time source.
  854.          * @return the time source
  855.          */
  856.         public String getTimeSource() {
  857.             return timeSource;
  858.         }

  859.         /**
  860.          * Get the local timing system configuration ID.
  861.          * @return the local timing system configuration ID
  862.          */
  863.         public String getLocalTimingId() {
  864.             return getConfigurationId();
  865.         }

  866.         /**
  867.          * Set the local timing system configuration ID.
  868.          * @param localTimingId the local timing system configuration ID to set
  869.          */
  870.         public void setLocalTimingId(final String localTimingId) {
  871.             setConfigurationId(localTimingId);
  872.         }

  873.         /**
  874.          * Set the time source.
  875.          * @param timeSource the time source to set
  876.          */
  877.         public void setTimeSource(final String timeSource) {
  878.             this.timeSource = timeSource;
  879.         }

  880.         /**
  881.          * Get the frequency source.
  882.          * @return the frequency source
  883.          */
  884.         public String getFrequencySource() {
  885.             return frequencySource;
  886.         }

  887.         /**
  888.          * Set the frequency source.
  889.          * @param frequencySource the frequency source to set
  890.          */
  891.         public void setFrequencySource(final String frequencySource) {
  892.             this.frequencySource = frequencySource;
  893.         }

  894.         /**
  895.          * Get the timer name.
  896.          * @return the timer name
  897.          */
  898.         public String getTimer() {
  899.             return timer;
  900.         }

  901.         /**
  902.          * Set the timer name.
  903.          * @param timer the timer name to set
  904.          */
  905.         public void setTimer(final String timer) {
  906.             this.timer = timer;
  907.         }

  908.         /**
  909.          * Get the timer serial number.
  910.          * @return the timer serial number
  911.          */
  912.         public String getTimerSerialNumber() {
  913.             return timerSerialNumber;
  914.         }

  915.         /**
  916.          * Set the timer serial number.
  917.          * @param timerSerialNumber the timer serial number to set
  918.          */
  919.         public void setTimerSerialNumber(final String timerSerialNumber) {
  920.             this.timerSerialNumber = timerSerialNumber;
  921.         }

  922.         /**
  923.          * Get the epoch delay correction.
  924.          * @return the epoch delay correction in seconds
  925.          */
  926.         public double getEpochDelayCorrection() {
  927.             return epochDelayCorrection;
  928.         }

  929.         /**
  930.          * Set the epoch delay correction.
  931.          * @param epochDelayCorrection the epoch delay correction to set in seconds
  932.          */
  933.         public void setEpochDelayCorrection(final double epochDelayCorrection) {
  934.             this.epochDelayCorrection = epochDelayCorrection;
  935.         }

  936.         /** {@inheritDoc} */
  937.         @Override
  938.         public String toCrdString() {
  939.             return String.format(Locale.US, "C3 0 %s", toString());
  940.         }

  941.         @Override
  942.         public String toString() {
  943.             // CRD suggested format, excluding the record type
  944.             // epochDelayCorrection: s --> us
  945.             final String str = String.format(Locale.US, "%s %s %s %s %s %.1f",
  946.                     getConfigurationId(), timeSource, frequencySource, timer,
  947.                     timerSerialNumber, epochDelayCorrection * 1e6);
  948.             return CRD.handleNaN(str).replace(',', '.');
  949.         }
  950.     }

  951.     /** Container for transponder configuration record. */
  952.     public static class TransponderConfiguration extends BaseConfiguration {

  953.         /** Estimated Station UTC offset [s]. */
  954.         private double stationUTCOffset;

  955.         /** Estimated Station Oscillator Drift in parts in 10^15. */
  956.         private double stationOscDrift;

  957.         /** Estimated Transponder UTC offset [s]. */
  958.         private double transpUTCOffset;

  959.         /** Estimated Transponder Oscillator Drift in parts in 10^15. */
  960.         private double transpOscDrift;

  961.         /** Transponder Clock Reference Time. */
  962.         private double transpClkRefTime;

  963.         /** Station clock offset and drift applied indicator. */
  964.         private int stationClockAndDriftApplied;

  965.         /** Spacecraft clock offset and drift applied indicator . */
  966.         private int spacecraftClockAndDriftApplied;

  967.         /** Spacecraft time simplified flag. */
  968.         private boolean isSpacecraftTimeSimplified;

  969.         /** Empty constructor.
  970.          * <p>
  971.          * This constructor is not strictly necessary, but it prevents spurious
  972.          * javadoc warnings with JDK 18 and later.
  973.          * </p>
  974.          * @since 12.0
  975.          */
  976.         public TransponderConfiguration() {
  977.             // nothing to do
  978.         }

  979.         /**
  980.          * Get the transponder configuration ID.
  981.          * @return the transponder configuration ID
  982.          */
  983.         public String getTransponderId() {
  984.             return getConfigurationId();
  985.         }

  986.         /**
  987.          * Set the transponder configuration ID.
  988.          * @param transponderId the transponder configuration ID to set
  989.          */
  990.         public void setTransponderId(final String transponderId) {
  991.             setConfigurationId(transponderId);
  992.         }

  993.         /**
  994.          * Get the estimated station UTC offset.
  995.          * @return the estimated station UTC offset in seconds
  996.          */
  997.         public double getStationUTCOffset() {
  998.             return stationUTCOffset;
  999.         }

  1000.         /**
  1001.          * Set the estimated station UTC offset.
  1002.          * @param stationUTCOffset the estimated station UTC offset to set in seconds
  1003.          */
  1004.         public void setStationUTCOffset(final double stationUTCOffset) {
  1005.             this.stationUTCOffset = stationUTCOffset;
  1006.         }

  1007.         /**
  1008.          * Get the estimated station oscillator drift in parts in 10¹⁵.
  1009.          * @return the station oscillator drift
  1010.          */
  1011.         public double getStationOscDrift() {
  1012.             return stationOscDrift;
  1013.         }

  1014.         /**
  1015.          * Set the estimated station oscillator drift in parts in 10¹⁵.
  1016.          * @param stationOscDrift the station oscillator drift to set
  1017.          */
  1018.         public void setStationOscDrift(final double stationOscDrift) {
  1019.             this.stationOscDrift = stationOscDrift;
  1020.         }

  1021.         /**
  1022.          * Get the estimated transponder UTC offset.
  1023.          * @return the estimated transponder UTC offset in seconds
  1024.          */
  1025.         public double getTranspUTCOffset() {
  1026.             return transpUTCOffset;
  1027.         }

  1028.         /**
  1029.          * Set the estimated transponder UTC offset.
  1030.          * @param transpUTCOffset the estimated transponder UTC offset to set in seconds
  1031.          */
  1032.         public void setTranspUTCOffset(final double transpUTCOffset) {
  1033.             this.transpUTCOffset = transpUTCOffset;
  1034.         }

  1035.         /**
  1036.          * Get the estimated transponder oscillator drift in parts in 10¹⁵.
  1037.          * @return the estimated transponder oscillator drift
  1038.          */
  1039.         public double getTranspOscDrift() {
  1040.             return transpOscDrift;
  1041.         }

  1042.         /**
  1043.          * Set the estimated transponder oscillator drift in parts in 10¹⁵.
  1044.          * @param transpOscDrift the estimated transponder oscillator drift to set
  1045.          */
  1046.         public void setTranspOscDrift(final double transpOscDrift) {
  1047.             this.transpOscDrift = transpOscDrift;
  1048.         }

  1049.         /**
  1050.          * Get the transponder clock reference time.
  1051.          * @return the transponder clock reference time
  1052.          */
  1053.         public double getTranspClkRefTime() {
  1054.             return transpClkRefTime;
  1055.         }

  1056.         /**
  1057.          * Set the transponder clock reference time.
  1058.          * @param transpClkRefTime the transponder clock reference time to set
  1059.          */
  1060.         public void setTranspClkRefTime(final double transpClkRefTime) {
  1061.             this.transpClkRefTime = transpClkRefTime;
  1062.         }

  1063.         /**
  1064.          * Get the station clock offset and drift applied indicator.
  1065.          * @return the station clock offset and drift applied indicator
  1066.          */
  1067.         public int getStationClockAndDriftApplied() {
  1068.             return stationClockAndDriftApplied;
  1069.         }

  1070.         /**
  1071.          * Set the station clock offset and drift applied indicator.
  1072.          * @param stationClockAndDriftApplied the indicator to set
  1073.          */
  1074.         public void setStationClockAndDriftApplied(final int stationClockAndDriftApplied) {
  1075.             this.stationClockAndDriftApplied = stationClockAndDriftApplied;
  1076.         }

  1077.         /**
  1078.          * Get the spacecraft clock offset and drift applied indicator.
  1079.          * @return the spacecraft clock offset and drift applied indicator
  1080.          */
  1081.         public int getSpacecraftClockAndDriftApplied() {
  1082.             return spacecraftClockAndDriftApplied;
  1083.         }

  1084.         /**
  1085.          * Set the spacecraft clock offset and drift applied indicator.
  1086.          * @param spacecraftClockAndDriftApplied the indicator to set
  1087.          */
  1088.         public void setSpacecraftClockAndDriftApplied(final int spacecraftClockAndDriftApplied) {
  1089.             this.spacecraftClockAndDriftApplied = spacecraftClockAndDriftApplied;
  1090.         }

  1091.         /**
  1092.          * Get the spacecraft time simplified flag.
  1093.          * @return true if spacecraft time is simplified
  1094.          */
  1095.         public boolean isSpacecraftTimeSimplified() {
  1096.             return isSpacecraftTimeSimplified;
  1097.         }

  1098.         /**
  1099.          * Set the spacecraft time simplified flag.
  1100.          * @param isSpacecraftTimeSimplified true if spacecraft time is simplified
  1101.          */
  1102.         public void setIsSpacecraftTimeSimplified(final boolean isSpacecraftTimeSimplified) {
  1103.             this.isSpacecraftTimeSimplified = isSpacecraftTimeSimplified;
  1104.         }

  1105.         /** {@inheritDoc} */
  1106.         @Override
  1107.         public String toCrdString() {
  1108.             return String.format(Locale.US, "C4 0 %s", toString());
  1109.         }

  1110.         @Override
  1111.         public String toString() {
  1112.             // CRD suggested format, excluding the record type
  1113.             // stationUTCOffset, transpUTCOffset: s --> ns
  1114.             final String str = String.format(
  1115.                     "%s %.3f %.2f %.3f %.2f %.12f %d %d %d",
  1116.                     getConfigurationId(),
  1117.                     stationUTCOffset * 1e9, stationOscDrift,
  1118.                     transpUTCOffset * 1e9, transpOscDrift,
  1119.                     transpClkRefTime,
  1120.                     stationClockAndDriftApplied, spacecraftClockAndDriftApplied,
  1121.                     isSpacecraftTimeSimplified ? 1 : 0);
  1122.             return CRD.handleNaN(str).replace(',', '.');
  1123.         }

  1124.     }

  1125.     /** Container for software configuration record. */
  1126.     public static class SoftwareConfiguration extends BaseConfiguration {

  1127.         /** Pattern of "[\\s+\\[\\]]". */
  1128.         private static final Pattern PATTERN_WHITESPACE_OR_SQUAREBRACKET = Pattern.compile("[\\s+\\[\\]]");

  1129.         /** Tracking software in measurement path. */
  1130.         private String[] trackingSoftwares;

  1131.         /** Tracking software version(s). */
  1132.         private String[] trackingSoftwareVersions;

  1133.         /** Processing software in measurement path. */
  1134.         private String[] processingSoftwares;

  1135.         /** Processing software version(s). */
  1136.         private String[] processingSoftwareVersions;

  1137.         /** Empty constructor.
  1138.          * <p>
  1139.          * This constructor is not strictly necessary, but it prevents spurious
  1140.          * javadoc warnings with JDK 18 and later.
  1141.          * </p>
  1142.          * @since 12.0
  1143.          */
  1144.         public SoftwareConfiguration() {
  1145.             // nothing to do
  1146.         }

  1147.         /**
  1148.          * Get the software configuration ID.
  1149.          * @return the software configuration ID.
  1150.          */
  1151.         public String getSoftwareId() {
  1152.             return getConfigurationId();
  1153.         }

  1154.         /**
  1155.          * Set the software configuration ID.
  1156.          * @param softwareId the software configuration ID
  1157.          */
  1158.         public void setSoftwareId(final String softwareId) {
  1159.             setConfigurationId(softwareId);
  1160.         }

  1161.         /**
  1162.          * Get the tracking softwares.
  1163.          * @return the tracking softwares
  1164.          */
  1165.         public String[] getTrackingSoftwares() {
  1166.             return trackingSoftwares.clone();
  1167.         }

  1168.         /**
  1169.          * Set the tracking softwares.
  1170.          * @param trackingSoftwares the tracking softwares to set
  1171.          */
  1172.         public void setTrackingSoftwares(final String[] trackingSoftwares) {
  1173.             this.trackingSoftwares = trackingSoftwares.clone();
  1174.         }

  1175.         /**
  1176.          * Get the tracking software versions.
  1177.          * @return the tracking software versions
  1178.          */
  1179.         public String[] getTrackingSoftwareVersions() {
  1180.             return trackingSoftwareVersions.clone();
  1181.         }

  1182.         /**
  1183.          * Set the tracking software versions.
  1184.          * @param trackingSoftwareVersions the tracking software versions to set
  1185.          */
  1186.         public void setTrackingSoftwareVersions(final String[] trackingSoftwareVersions) {
  1187.             this.trackingSoftwareVersions = trackingSoftwareVersions.clone();
  1188.         }

  1189.         /**
  1190.          * Get the processing softwares.
  1191.          * @return the processing softwares
  1192.          */
  1193.         public String[] getProcessingSoftwares() {
  1194.             return processingSoftwares.clone();
  1195.         }

  1196.         /**
  1197.          * Set the processing softwares.
  1198.          * @param processingSoftwares the processing softwares to set
  1199.          */
  1200.         public void setProcessingSoftwares(final String[] processingSoftwares) {
  1201.             this.processingSoftwares = processingSoftwares.clone();
  1202.         }

  1203.         /**
  1204.          * Get the processing software versions.
  1205.          * @return the processing software versions
  1206.          */
  1207.         public String[] getProcessingSoftwareVersions() {
  1208.             return processingSoftwareVersions.clone();
  1209.         }

  1210.         /**
  1211.          * Set the processing software versions.
  1212.          * @param processingSoftwareVersions the processing software versions to set
  1213.          */
  1214.         public void setProcessingSoftwareVersions(final String[] processingSoftwareVersions) {
  1215.             this.processingSoftwareVersions = processingSoftwareVersions.clone();
  1216.         }

  1217.         private static String formatArray(final String[] arr) {
  1218.             // comma delimited
  1219.             // "[Monitor, Sattrk]" ==> "Monitor,Sattrk"
  1220.             // "[conpro, crd_cal, PoissonCRD, gnp]" ==> "conpro,crd_cal,PoissonCRD,gnp"
  1221.             final String s = Arrays.toString(arr);
  1222.             return PATTERN_WHITESPACE_OR_SQUAREBRACKET.matcher(s).replaceAll("");
  1223.         }

  1224.         /** {@inheritDoc} */
  1225.         @Override
  1226.         public String toCrdString() {
  1227.             return String.format(Locale.US, "C5 0 %s", toString());
  1228.         }

  1229.         @Override
  1230.         public String toString() {
  1231.             // CRD suggested format, excluding the record type
  1232.             return String.format(Locale.US, "%s %s %s %s %s", getConfigurationId(),
  1233.                     formatArray(trackingSoftwares),
  1234.                     formatArray(trackingSoftwareVersions),
  1235.                     formatArray(processingSoftwares),
  1236.                     formatArray(processingSoftwareVersions));
  1237.         }

  1238.     }

  1239.     /** Container for meteorological configuration record. */
  1240.     public static class MeteorologicalConfiguration extends BaseConfiguration {

  1241.         /** Pressure Sensor Manufacturer. */
  1242.         private String pressSensorManufacturer;

  1243.         /** Pressure Sensor Model. */
  1244.         private String pressSensorModel;

  1245.         /** Pressure Sensor Serial Number. */
  1246.         private String pressSensorSerialNumber;

  1247.         /** Temperature Sensor Manufacturer. */
  1248.         private String tempSensorManufacturer;

  1249.         /** Temperature Sensor Model. */
  1250.         private String tempSensorModel;

  1251.         /** Temperature Sensor Serial Number. */
  1252.         private String tempSensorSerialNumber;

  1253.         /** Humidity Sensor Manufacturer. */
  1254.         private String humiSensorManufacturer;

  1255.         /** Humidity Sensor Model. */
  1256.         private String humiSensorModel;

  1257.         /** Humidity Sensor Serial Number. */
  1258.         private String humiSensorSerialNumber;

  1259.         /** Empty constructor.
  1260.          * <p>
  1261.          * This constructor is not strictly necessary, but it prevents spurious
  1262.          * javadoc warnings with JDK 18 and later.
  1263.          * </p>
  1264.          * @since 12.0
  1265.          */
  1266.         public MeteorologicalConfiguration() {
  1267.             // nothing to do
  1268.         }

  1269.         /**
  1270.          * Get the meteorological configuration ID.
  1271.          * @return the meteorological configuration ID
  1272.          */
  1273.         public String getMeteorologicalId() {
  1274.             return getConfigurationId();
  1275.         }

  1276.         /**
  1277.          * Set the meteorological configuration ID.
  1278.          * @param meteorologicalId the meteorological configuration ID to set
  1279.          */
  1280.         public void setMeteorologicalId(final String meteorologicalId) {
  1281.             setConfigurationId(meteorologicalId);
  1282.         }

  1283.         /**
  1284.          * Get the pressure sensor manufacturer.
  1285.          * @return the pressure sensor manufacturer
  1286.          */
  1287.         public String getPressSensorManufacturer() {
  1288.             return pressSensorManufacturer;
  1289.         }

  1290.         /**
  1291.          * Set the pressure sensor manufacturer.
  1292.          * @param pressSensorManufacturer the manufacturer to set
  1293.          */
  1294.         public void setPressSensorManufacturer(final String pressSensorManufacturer) {
  1295.             this.pressSensorManufacturer = pressSensorManufacturer;
  1296.         }

  1297.         /**
  1298.          * Get the pressure sensor model.
  1299.          * @return the pressure sensor model
  1300.          */
  1301.         public String getPressSensorModel() {
  1302.             return pressSensorModel;
  1303.         }

  1304.         /**
  1305.          * Set the pressure sensor model.
  1306.          * @param pressSensorModel the model to set
  1307.          */
  1308.         public void setPressSensorModel(final String pressSensorModel) {
  1309.             this.pressSensorModel = pressSensorModel;
  1310.         }

  1311.         /**
  1312.          * Get the pressure sensor serial number.
  1313.          * @return the pressure sensor serial number
  1314.          */
  1315.         public String getPressSensorSerialNumber() {
  1316.             return pressSensorSerialNumber;
  1317.         }

  1318.         /**
  1319.          * Set the pressure sensor serial number.
  1320.          * @param pressSensorSerialNumber the serial number to set
  1321.          */
  1322.         public void setPressSensorSerialNumber(final String pressSensorSerialNumber) {
  1323.             this.pressSensorSerialNumber = pressSensorSerialNumber;
  1324.         }

  1325.         /**
  1326.          * Get the temperature sensor manufacturer.
  1327.          * @return the temperature sensor manufacturer
  1328.          */
  1329.         public String getTempSensorManufacturer() {
  1330.             return tempSensorManufacturer;
  1331.         }

  1332.         /**
  1333.          * Set the temperature sensor manufacturer.
  1334.          * @param tempSensorManufacturer the temperature sensor manufacturer
  1335.          */
  1336.         public void setTempSensorManufacturer(final String tempSensorManufacturer) {
  1337.             this.tempSensorManufacturer = tempSensorManufacturer;
  1338.         }

  1339.         /**
  1340.          * Get the temperature sensor model.
  1341.          * @return the temperature sensor model
  1342.          */
  1343.         public String getTempSensorModel() {
  1344.             return tempSensorModel;
  1345.         }

  1346.         /**
  1347.          * Set the temperature sensor model.
  1348.          * @param tempSensorModel the model to set
  1349.          */
  1350.         public void setTempSensorModel(final String tempSensorModel) {
  1351.             this.tempSensorModel = tempSensorModel;
  1352.         }

  1353.         /**
  1354.          * Get the temperature sensor serial number.
  1355.          * @return the temperature sensor serial number
  1356.          */
  1357.         public String getTempSensorSerialNumber() {
  1358.             return tempSensorSerialNumber;
  1359.         }

  1360.         /**
  1361.          * Set the temperature sensor serial number.
  1362.          * @param tempSensorSerialNumber the serial number to set
  1363.          */
  1364.         public void setTempSensorSerialNumber(final String tempSensorSerialNumber) {
  1365.             this.tempSensorSerialNumber = tempSensorSerialNumber;
  1366.         }

  1367.         /**
  1368.          * Get the humidity sensor manufacturer.
  1369.          * @return the humidity sensor manufacturer
  1370.          */
  1371.         public String getHumiSensorManufacturer() {
  1372.             return humiSensorManufacturer;
  1373.         }

  1374.         /**
  1375.          * Set the humidity sensor manufacturer.
  1376.          * @param humiSensorManufacturer the manufacturer to set
  1377.          */
  1378.         public void setHumiSensorManufacturer(final String humiSensorManufacturer) {
  1379.             this.humiSensorManufacturer = humiSensorManufacturer;
  1380.         }

  1381.         /**
  1382.          * Get the humidity sensor model.
  1383.          * @return the humidity sensor model
  1384.          */
  1385.         public String getHumiSensorModel() {
  1386.             return humiSensorModel;
  1387.         }

  1388.         /**
  1389.          * Set the humidity sensor model.
  1390.          * @param humiSensorModel the model to set
  1391.          */
  1392.         public void setHumiSensorModel(final String humiSensorModel) {
  1393.             this.humiSensorModel = humiSensorModel;
  1394.         }

  1395.         /**
  1396.          * Get the humidity sensor serial number.
  1397.          * @return the humidity sensor serial number
  1398.          */
  1399.         public String getHumiSensorSerialNumber() {
  1400.             return humiSensorSerialNumber;
  1401.         }

  1402.         /**
  1403.          * Set the humidity sensor serial number.
  1404.          * @param humiSensorSerialNumber the serial number to set
  1405.          */
  1406.         public void setHumiSensorSerialNumber(final String humiSensorSerialNumber) {
  1407.             this.humiSensorSerialNumber = humiSensorSerialNumber;
  1408.         }

  1409.         /** {@inheritDoc} */
  1410.         @Override
  1411.         public String toCrdString() {
  1412.             return String.format("C6 0 %s", toString());
  1413.         }

  1414.         @Override
  1415.         public String toString() {
  1416.             // CRD suggested format, excluding the record type
  1417.             return String.format("%s %s %s %s %s %s %s %s %s %s",
  1418.                     getConfigurationId(), pressSensorManufacturer,
  1419.                     pressSensorModel, pressSensorSerialNumber,
  1420.                     tempSensorManufacturer, tempSensorModel,
  1421.                     tempSensorSerialNumber, humiSensorManufacturer,
  1422.                     humiSensorModel, humiSensorSerialNumber);
  1423.         }
  1424.     }

  1425.     /**
  1426.      * Container for calibration target configuration record.
  1427.      * @since 12.0
  1428.      */
  1429.     public static class CalibrationTargetConfiguration extends BaseConfiguration {

  1430.         /** Target name or ID. */
  1431.         private String targetName;

  1432.         /** Surveyed target distance. */
  1433.         private double surveyedTargetDistance;

  1434.         /** Survey error. */
  1435.         private double surveyError;

  1436.         /** Sum of all constant delays (m, one way). */
  1437.         private double sumOfAllConstantDelays;

  1438.         /** Pulse Energy [mJ]. */
  1439.         private double pulseEnergy;

  1440.         /** Processing software name. */
  1441.         private String processingSoftwareName;

  1442.         /** Processing software version. */
  1443.         private String processingSoftwareVersion;

  1444.         /** Empty constructor.
  1445.          * <p>
  1446.          * This constructor is not strictly necessary, but it prevents spurious
  1447.          * javadoc warnings with JDK 18 and later.
  1448.          * </p>
  1449.          * @since 12.0
  1450.          */
  1451.         public CalibrationTargetConfiguration() {
  1452.             // nothing to do
  1453.         }

  1454.         /**
  1455.          * Get the target name or ID.
  1456.          * @return the target name or ID
  1457.          */
  1458.         public String getTargetName() {
  1459.             return targetName;
  1460.         }

  1461.         /**
  1462.          * Set the target name or ID.
  1463.          * @param targetName target name or ID to set
  1464.          */
  1465.         public void setTargetName(final String targetName) {
  1466.             this.targetName = targetName;
  1467.         }

  1468.         /**
  1469.          * Get the surveyed target distance.
  1470.          * @return the surveyed target distance in meters
  1471.          */
  1472.         public double getSurveyedTargetDistance() {
  1473.             return surveyedTargetDistance;
  1474.         }

  1475.         /**
  1476.          * Set the surveyed target distance.
  1477.          * @param surveyedTargetDistance the surveyed target distance to set, in meters
  1478.          */
  1479.         public void setSurveyedTargetDistance(final double surveyedTargetDistance) {
  1480.             this.surveyedTargetDistance = surveyedTargetDistance;
  1481.         }

  1482.         /**
  1483.          * Get the survey error.
  1484.          * @return the survey error in meters
  1485.          */
  1486.         public double getSurveyError() {
  1487.             return surveyError;
  1488.         }

  1489.         /**
  1490.          * Set the survey error.
  1491.          * @param surveyError the survey error to set, in meters
  1492.          */
  1493.         public void setSurveyError(final double surveyError) {
  1494.             this.surveyError = surveyError;
  1495.         }

  1496.         /**
  1497.          * Get the sum of all constant delays (electronic, geometric, optical) that
  1498.          * are not included in the time of flight measurements or time- variant
  1499.          * or point angle-variant delays in the “42” record below (m, one way).
  1500.          * @return the sum of all constant delays
  1501.          */
  1502.         public double getSumOfAllConstantDelays() {
  1503.             return sumOfAllConstantDelays;
  1504.         }

  1505.         /**
  1506.          * Set the sum of all constant delays (electronic, geometric, optical) that
  1507.          * are not included in the time of flight measurements or time- variant
  1508.          * or point angle-variant delays in the “42” record below (m, one way).
  1509.          * @param sumOfAllConstantDelays the sum of all constant delays
  1510.          */
  1511.         public void setSumOfAllConstantDelays(final double sumOfAllConstantDelays) {
  1512.             this.sumOfAllConstantDelays = sumOfAllConstantDelays;
  1513.         }

  1514.         /**
  1515.          * Get the pulse energy.
  1516.          * @return the pulse energy in mJ
  1517.          */
  1518.         public double getPulseEnergy() {
  1519.             return pulseEnergy;
  1520.         }

  1521.         /**
  1522.          * Set the pulse energy.
  1523.          * @param pulseEnergy the pulse energy to set, in mJ
  1524.          */
  1525.         public void setPulseEnergy(final double pulseEnergy) {
  1526.             this.pulseEnergy = pulseEnergy;
  1527.         }

  1528.         /**
  1529.          * Get the processing software name.
  1530.          * @return the processing software name
  1531.          */
  1532.         public String getProcessingSoftwareName() {
  1533.             return processingSoftwareName;
  1534.         }

  1535.         /**
  1536.          * Set the processing software name.
  1537.          * @param processingSoftwareName the processing software name to set
  1538.          */
  1539.         public void setProcessingSoftwareName(final String processingSoftwareName) {
  1540.             this.processingSoftwareName = processingSoftwareName;
  1541.         }

  1542.         /**
  1543.          * Get the processing software version.
  1544.          * @return the processing software version
  1545.          */
  1546.         public String getProcessingSoftwareVersion() {
  1547.             return processingSoftwareVersion;
  1548.         }

  1549.         /**
  1550.          * Set the processing software version.
  1551.          * @param processingSoftwareVersion the processing software version to set
  1552.          */
  1553.         public void setProcessingSoftwareVersion(final String processingSoftwareVersion) {
  1554.             this.processingSoftwareVersion = processingSoftwareVersion;
  1555.         }

  1556.         /** {@inheritDoc} */
  1557.         @Override
  1558.         public String toCrdString() {
  1559.             return String.format("C7 0 %s", toString());
  1560.         }

  1561.         @Override
  1562.         public String toString() {
  1563.             // CRD suggested format, excluding the record type
  1564.             // surveyError: m --> mm
  1565.             final String str = String.format("%s %s %.5f %.2f %.4f %.2f %s %s",
  1566.                     getConfigurationId(), targetName, surveyedTargetDistance,
  1567.                     surveyError * 1e3, sumOfAllConstantDelays, pulseEnergy,
  1568.                     processingSoftwareName, processingSoftwareVersion);
  1569.             return CRD.handleNaN(str).replace(',', '.');
  1570.         }

  1571.     }
  1572. }