CustomMeasurement#
- class CustomMeasurement(name: str, instrument: Instrument, observable, sigma: ArrayWUnits = None, units=None, dimension: int = 1, parameters: list | None = None, partial_by_position=None, partial_by_velocity=None, depends_on_position: bool | None = None, depends_on_velocity: bool | None = None, position_step: float | None = None, velocity_step: float | None = None, state_definition=None, sequence_definition=None)#
Bases:
MeasurementUser-supplied measurement model, defined entirely from a script.
CustomMeasurementis the observation-side counterpart ofCustomDynamicModel: it turns a plain Python function into a first-class Scarabaeus measurement, so a new observable — and any biases or calibration terms it carries — can be added and estimated without changing the library source.The model computes
\[y = h(\mathbf{r}_\text{rel},\, \dot{\mathbf{r}}_\text{rel},\, \mathbf{p},\, t)\]where \(\mathbf{r}_\text{rel}\) is the target position relative to the observing instrument and \(\mathbf{p}\) are the declared
CustomParameterobjects. It supplies the corresponding row(s) of the measurement Jacobian\[\tilde{H} = \left[ \frac{\partial h}{\partial \mathbf r},\; \frac{\partial h}{\partial \dot{\mathbf r}},\; \frac{\partial h}{\partial \mathbf p} \right]\]with a zero block for every state component the model does not depend on. Any Jacobian not given analytically is evaluated by central finite differences of the user function, so a working model needs only observable.
Sign convention. The relative state is
r_target - r_instrument. The Jacobian is therefore+dh/drfor the target’s position column and-dh/drfor the observer’s, matching the built-in models.Calling convention. Every user callable is invoked with keyword arguments; declare only the ones you need, in any order:
position(3,)target position relative to the instrument, kmvelocity(3,)relative velocity, km/srelative_state(6,)the two stackedepochmeasurement epoch, TDB seconds past J2000
paramsdictof this model’s parameters at their current estimated values (or their defaults)targetthe observed body
instrumentthe observing instrument
framereference
Framemodelthis
CustomMeasurementinstanceA callable declaring
**kwargsreceives all of them.- Parameters:
- namestr
Name of the measurement model.
- instrumentInstrument
Observing instrument (ground station, camera, …).
- observablecallable
Returns the computed measurement: a scalar, or a
(dimension,)array for a multi-component observable. Required.- sigmaArrayWUnits
Measurement noise standard deviation, also used to generate noise.
- unitsUnits, optional
Units of the observable. Defaults to the units of sigma.
- dimensionint, optional
Number of components the observable returns. Defaults to 1.
- parameterslist, optional
Solve-for parameters this measurement depends on, as
CustomParameterobjects or plain names. Theirpartialcallable, when supplied, is \(\partial h / \partial p\) with shape(dimension, p_dim).- partial_by_positioncallable, optional
\(\partial h / \partial \mathbf r\) as
(dimension, 3). Defaults to a central finite difference of observable.- partial_by_velocitycallable, optional
\(\partial h / \partial \dot{\mathbf r}\) as
(dimension, 3). Defaults to a central finite difference of observable.- depends_on_position, depends_on_velocitybool, optional
Whether the observable depends on relative position / velocity. Inferred from the signature of observable when
None.- position_stepfloat, optional
Absolute finite-difference step on position, km. Defaults to
1e-6 * max(|r_i|, 1)per component.- velocity_stepfloat, optional
Absolute finite-difference step on velocity, km/s. Defaults to
1e-9 * max(|v_i|, 1)per component.- state_definitionlist, optional
State layout used to build the Jacobian columns. Normally supplied by
update_reference_state().- sequence_definitionMissionSequence, optional
Sequence whose per-leg state definitions are used instead.
- Attributes:
- AUX_KEYS
component_labelsNames of the two components of a vector observable.
computed_measurements_dictAuxiliary TRK-2-34 tracking-data dictionary needed for the generation of the computed measurements of a real radiometric model.
default_dataset_nameDataset name used when the caller does not supply one.
depends_on_positionTruewhen the observable is a function of relative position.depends_on_velocityTruewhen the observable is a function of relative velocity.dimensionNumber of components the observable returns.
dl_station_calDownlink station calibration [RU] written into simulated auxiliary data.
dsn_bandsDSN frequency-band parameters of this model, a read-only mapping from band letter to
DSNBand.epoch_secObservation epochs expressed as seconds of day.
instrumentThe instrument.
media_correctionsTropospheric and ionospheric path-delay model, or
Noneif not set.nameThe name of the model.
parametersDeclared solve-for parameters, keyed by name.
ramp_entriesNumber of entries of a simulated ramp table, at least 2.
ramp_marginSpan [s] a simulated ramp table extends before the first and after the last observation.
ramp_rateUplink frequency ramp rate [Hz/s] of the ramp table the
default_*_auxbuilders simulate.ramp_typeSFDU 9
ramp_typecode of the segments of a simulated ramp table.rcv_time_tag_delayReceive time-tag delay [s] written into simulated auxiliary data.
sigmaThe standard deviation of the measurement model.
solar_corona_coefficientCoefficient of the solar-corona group delay [us GHz^2 m^2] of a real model built with
solar_corona=True.transponder_delaySpacecraft transponder delay [RU] written into simulated auxiliary data by the
default_*_auxbuilders.ul_station_calUplink station calibration [RU] written into simulated auxiliary data.
unitsUnits of the computed measurement.
Methods
align_aux_to_epochs(source, key, target[, ...])Sample a TRK-2-34 record at the epochs of another record by time tag.
compute_partials(target, epoch_array, frame)Stacks together measurement _partials for an epoch array at different epochs.
computed_measurements(target, epoch_array, ...)Evaluate the user observable over an epoch array.
generate_measurement_dataset(dataset_name, ...)Generates a MeasurementDataSet object that can be used by filters downstream.
observed_measurements(file_name, meas_name, ...)Reads measurements from a .json file.
residuals(observed_meas, computed_meas)Generates the measurement model's residuals given observed and computed ArrayWFrames.
resolve_elevation_mask(elevation_mask)Normalise an elevation mask to degrees.
rtlt_grad_pos_exact(n_hat_dn, n_hat_up, ...)Exact round-trip light-time gradient with respect to the spacecraft position.
rtlt_grad_station_exact(n_hat_dn, n_hat_up, ...)Exact round-trip light-time gradients with respect to the station position.
rtlt_leg_weights(n_hat_dn, n_hat_up, v_sc, ...)Sensitivity of the round-trip light time to a delay inside each leg's solution.
set_pass_epochs(pass_epochs)Enable per-pass biases.
set_trajectory(trajectory)Attach the reference trajectory supplying the STMs.
transponder_delay_seconds(delay_RU, ...)Convert a spacecraft transponder delay from range units to seconds.
update_reference_state(state_vector)Attach the estimated state the model should read its parameters from.
validate_aux(aux[, label])Check that an auxiliary-data dictionary is internally consistent.
write_observed_measurements(target, ...)Generates synthetic measurements and write them as a .json file.
See also
scarabaeus.CustomParameterDeclaration of an estimable custom parameter.
scarabaeus.CustomDynamicModelThe dynamics-side counterpart.
scarabaeus.RangeIdealBuilt-in model this one mirrors structurally.
Notes
Positions and velocities are handed over in km and km/s. The observable is returned in units (or the units of sigma).
Examples
Range with an estimated station bias, written from a script:
import numpy as np import scarabaeus as scb km = scb.Units.get_units("km") bias = scb.CustomParameter("station_bias", units=km, default=0.0) def biased_range(position, params): return np.linalg.norm(position) + params["station_bias"][0] model = scb.CustomMeasurement( "GS1 Custom Range", instrument = gs, observable = biased_range, sigma = scb.ArrayWUnits(1e-3, km), parameters = [bias], )
The bias is estimated by adding it to the state definition:
state_def = (scb.StateDefinition() .position(sc, pos_0) .velocity(sc, vel_0) .custom_param("station_bias", gs, scb.ArrayWFrame(0.0, km, None)) )
- static align_aux_to_epochs(source: dict, key: str, target: dict, invalid=None) ndarray#
Sample a TRK-2-34 record at the epochs of another record by time tag.
Each SFDU record of a tracking file has its own cadence (e.g. the uplink z-height correction every second, the ranging aux at the ranging cadence), so its rows do not correspond to the measurement rows. The value in force at each target epoch is the latest source entry at or before it (zero-order hold); target epochs earlier than the whole source take its first entry.
- Parameters:
- sourcedict
Record holding
year,doy,secandkey.- keystr
Field of
sourceto sample.- targetdict
Record holding the
year,doy,sectime tags to sample at, typically the measurement record (e.g.trk["2W_doppler"]).- invalidfloat, optional
Source entries equal to this value are skipped (e.g.
0for the uplink frequency of rows with no uplink).
- Returns:
- np.ndarray
source[key]at each target epoch, of lengthlen(target["sec"]).
- Raises:
- Measurement.AuxDataError
If
sourceholds no valid entry ofkey.
- static resolve_elevation_mask(elevation_mask: ArrayWUnits | float) float#
Normalise an elevation mask to degrees.
- Parameters:
- elevation_maskArrayWUnits or float
Minimum elevation angle. An
ArrayWUnitsis converted from its own units, so radians work as well as degrees. A bare number is taken to be in degrees, which is what the parameter has always meant and what every default (10.0) is.
- Returns:
- float
The mask in degrees.
- Raises:
- ElevationMaskError
If the mask is not a number or an angle, or is outside 0 to 90 degrees. Also if it is a bare number that is not a whole number of degrees and is no more than pi/2: 0.17 could be 0.17 deg or 10 deg meant in radians, and reading it the wrong way silently keeps or drops the observations near the horizon. Such a mask has to carry its units. A larger bare number is read as degrees, since as radians it would be above 90 deg and be refused anyway.
Examples
Measurement.resolve_elevation_mask(10.0) # 10.0 Measurement.resolve_elevation_mask(ArrayWUnits(0.2, rad)) # 11.459... Measurement.resolve_elevation_mask(ArrayWUnits(0.5, deg)) # 0.5 Measurement.resolve_elevation_mask(0.5) # ElevationMaskError
- static rtlt_grad_pos_exact(n_hat_dn: ndarray, n_hat_up: ndarray, v_sc: ndarray, v_gs: ndarray, c: float) ndarray#
Exact round-trip light-time gradient with respect to the spacecraft position.
Chains Moyer (2000) Eqs. 12-12 (downleg) and 12-17 (upleg) through the reflection time \(t_2\), holding the reception time \(t_3\) fixed, so that \(\rho = t_3 - t_1\) and \(\partial \rho / \partial \mathbf{r}_{SC} = -\partial t_1 / \partial \mathbf{r}_{SC}\) [s/km]. With the Eq. 8-59/8-60 definitions, the spacecraft transmits on the downleg and the station on the upleg:
\[ \begin{align}\begin{aligned}\dot{p}_{23} = \hat{\mathbf{r}}_{23} \cdot \mathbf{v}_{SC} / c = -\hat{\mathbf{n}}_{dn} \cdot \mathbf{v}_{SC} / c, \qquad \dot{p}_{12} = \hat{\mathbf{r}}_{12} \cdot \mathbf{v}_{GS} / c = \hat{\mathbf{n}}_{up} \cdot \mathbf{v}_{GS} / c\\\dot{r}_{12} = \hat{\mathbf{n}}_{up} \cdot (\mathbf{v}_{SC} - \mathbf{v}_{GS}) / c, \qquad \dot{r}_{12} + \dot{p}_{12} = \hat{\mathbf{n}}_{up} \cdot \mathbf{v}_{SC} / c\end{aligned}\end{align} \]where the station terms cancel in the last sum. The gradient is then
\[\frac{\partial t_2}{\partial \mathbf{r}_{SC}} = -\frac{\hat{\mathbf{n}}_{dn}}{c\,(1 - \dot{p}_{23})}, \qquad \frac{\partial \rho}{\partial \mathbf{r}_{SC}} = -\frac{(1 - \dot{r}_{12} - \dot{p}_{12})\, \partial t_2 / \partial \mathbf{r}_{SC} - \hat{\mathbf{n}}_{up} / c} {1 - \dot{p}_{12}}\]- Parameters:
- n_hat_dnnumpy.ndarray, shape (3,)
Unit vector GS to SC on the downleg, \(\hat{\mathbf{n}}_{dn} = (\mathbf{r}_{SC}(t_2) - \mathbf{r}_{GS}(t_3)) / \rho_{dn}\).
- n_hat_upnumpy.ndarray, shape (3,)
Unit vector GS to SC on the upleg, \(\hat{\mathbf{n}}_{up} = (\mathbf{r}_{SC}(t_2) - \mathbf{r}_{GS}(t_1)) / \rho_{up}\).
- v_scnumpy.ndarray, shape (3,)
Spacecraft velocity at \(t_2\) [km/s], in the space-time frame the light time is solved in (see
_light_time_velocity()).- v_gsnumpy.ndarray, shape (3,)
Ground station velocity at \(t_1\) [km/s], in the same frame.
- cfloat
Speed of light [km/s].
- Returns:
- numpy.ndarray, shape (3,)
\(\partial \rho / \partial \mathbf{r}_{SC}\) [s/km].
References
[1]Moyer, T. D. (2000). Formulation for Observed and Computed Values of Deep Space Network Data Types for Navigation. JPL Publication 00-7.
- static rtlt_grad_station_exact(n_hat_dn: ndarray, n_hat_up: ndarray, v_sc: ndarray, v_gs: ndarray, c: float) tuple#
Exact round-trip light-time gradients with respect to the station position.
The station enters at reception \(t_3\) and at transmission \(t_1\), through the same Moyer (2000) 12-12/12-17 chain as
rtlt_grad_pos_exact(). Displacing the receiver at \(t_3\) moves the reflection time \(t_2\) (Eq. 12-12, with the station as the receiver), and the upleg carries that change to \(t_1\) through its own \(\dot{p}_{12}\) denominator (Eq. 12-17); displacing the transmitter at \(t_1\) enters the upleg only:\[\frac{\partial \rho}{\partial \mathbf{r}_{GS}(t_3)} = -\frac{(1 - \dot{r}_{12} - \dot{p}_{12})\,\hat{\mathbf{n}}_{dn}} {c\,(1 - \dot{p}_{23})(1 - \dot{p}_{12})}, \qquad \frac{\partial \rho}{\partial \mathbf{r}_{GS}(t_1)} = -\frac{\hat{\mathbf{n}}_{up}}{c\,(1 - \dot{p}_{12})}\]with \(\dot{p}\) and \(\dot{r}\) as defined in
rtlt_grad_pos_exact(): each leg’s range over c weighted byrtlt_leg_weights(). Their sum is-rtlt_grad_pos_exact(...): a common translation of station and spacecraft leaves the light time unchanged. Dropping the denominators, i.e. using \(-\hat{\mathbf{n}}/c\) on each leg, is off by the transmitters’ velocities over c, about 1e-4 relative with heliocentric velocities.- Parameters:
- n_hat_dnnumpy.ndarray, shape (3,)
Unit vector GS to SC on the downleg.
- n_hat_upnumpy.ndarray, shape (3,)
Unit vector GS to SC on the upleg.
- v_scnumpy.ndarray, shape (3,)
Spacecraft velocity at \(t_2\) [km/s].
- v_gsnumpy.ndarray, shape (3,)
Ground station velocity at \(t_1\) [km/s].
- cfloat
Speed of light [km/s].
- Returns:
- grad_t3numpy.ndarray, shape (3,)
\(\partial \rho / \partial \mathbf{r}_{GS}(t_3)\) [s/km], in the frame of the input vectors.
- grad_t1numpy.ndarray, shape (3,)
\(\partial \rho / \partial \mathbf{r}_{GS}(t_1)\) [s/km], in the same frame.
See also
rtlt_grad_pos_exactdefinitions of the inputs.
- static rtlt_leg_weights(n_hat_dn: ndarray, n_hat_up: ndarray, v_sc: ndarray, v_gs: ndarray, c: float) tuple#
Sensitivity of the round-trip light time to a delay inside each leg’s solution.
Uses the Moyer (2000) 12-12/12-17 chain of
rtlt_grad_pos_exact(). A delay \(\delta\tau_{23}\) in the downleg equation moves the reflection time \(t_2\), and the upleg carries that change to \(t_1\); a delay \(\delta\tau_{12}\) in the upleg equation moves \(t_1\) only:\[\frac{\partial \rho}{\partial \tau_{23}} = \frac{1 - \dot{r}_{12} - \dot{p}_{12}}{(1 - \dot{p}_{23})(1 - \dot{p}_{12})}, \qquad \frac{\partial \rho}{\partial \tau_{12}} = \frac{1}{1 - \dot{p}_{12}}\]with \(\dot{p}\) and \(\dot{r}\) as defined in
rtlt_grad_pos_exact(). Both are 1 to within the transmitters’ velocities over c, about 1e-4 with heliocentric velocities. They apply to what the iteration solves for, the geometric range and the Shapiro delay, and not to the media, corona and electronic delays, which are added after it converges.- Parameters:
- n_hat_dnnumpy.ndarray, shape (3,)
Unit vector GS to SC on the downleg.
- n_hat_upnumpy.ndarray, shape (3,)
Unit vector GS to SC on the upleg.
- v_scnumpy.ndarray, shape (3,)
Spacecraft velocity at \(t_2\) [km/s].
- v_gsnumpy.ndarray, shape (3,)
Ground station velocity at \(t_1\) [km/s].
- cfloat
Speed of light [km/s].
- Returns:
- w_dnfloat
\(\partial \rho / \partial \tau_{23}\), dimensionless.
- w_upfloat
\(\partial \rho / \partial \tau_{12}\), dimensionless.
See also
rtlt_grad_pos_exactdefinitions of the inputs.
- static transponder_delay_seconds(delay_RU: float, reference_frequency: float, range_unit: float) float#
Convert a spacecraft transponder delay from range units to seconds.
The delay is divided by
range_unit * reference_frequency, the rate of the clock the delay is counted against.- Parameters:
- delay_RUfloat
Transponder delay as the mission specifies it [RU].
- reference_frequencyfloat
The band’s range-unit reference frequency [1/s], i.e.
Measurement.DSNBand.ru_reference_frequency.- range_unitfloat
The range unit, from the pass’s exciter scalars.
- Returns:
- float
The delay [s].
Notes
Pass the band’s reference frequency, not its uplink frequency. The two differ by 18% in X band, and the delay enters the round-trip light time directly rather than acting as a scale factor, so substituting the uplink makes the delay 2.4 us longer – 1.4 km of two-way range. Tried on real tracking data, that drove the sequential-ranging residuals from 55-206 RU to 2330-2694 RU, so the reference frequency is what the data supports. Why a downlink-scale reference is the right one is an open question; see the attribute’s own note.
- static validate_aux(aux: dict, label: str = '') None#
Check that an auxiliary-data dictionary is internally consistent.
An aux dict describes two things sampled on two different grids: one value per observation, and one entry per ramp-table segment. Everything in each group has to be the same length, and a value meant to be per-observation has to be a sequence rather than a bare number.
Nothing checks that on the way in otherwise, and the failures it prevents surface far from their cause:
Mismatched lengths reach
RampTableManager.integrate(), which indexesramp_freqwith an index derived fromramp_secand raisedIndexError: index 9 is out of bounds for axis 0 with size 5from inside the forward model.A ragged per-observation group reaches
write_observed_measurements(), whose own check then refuses to write the file – correct, but one step later than here.
- Parameters:
- auxdict
The dictionary to check, as a
default_*_auxhelper or_read_aux()produces it.- labelstr, optional
Named in the error, to say which dictionary was wrong.
- Raises:
- TypeError
If aux is not a dict.
Noneis reported specifically, since that means the model was never given its auxiliary data.- ValueError
If the per-observation group or the ramp group is ragged. The message groups the keys by the length they have, since the odd one out is usually obvious once they are laid side by side.
Examples
aux = doppler_model.default_doppler_aux(t0, tf, N=20, band="S") scb.Measurement.validate_aux(aux, label="DSS-25 Range Rate")
- compute_partials(target: Spacecraft, epoch_array: EpochArray, frame: Frame = J2000 (0 - SOLAR SYSTEM BARYCENTER)) list#
Stacks together measurement _partials for an epoch array at different epochs.
- Parameters:
- targetSpacecraft
The target spacecraft.
- epoch_arrayEpochArray
The epochs.
- frameFrame, optional
The reference frame. Defaults to a J2000 Frame object.
- Returns:
- _partialslist
A list with all the _partials evaluated at different epochs in the
epoch_array.
- computed_measurements(target, epoch_array: EpochArray = None, epoch_start: EpochArray = None, epoch_end: EpochArray = None, tstep: float = 1, frame: Frame = J2000 (0 - SOLAR SYSTEM BARYCENTER), noisy: bool = False, pass_epochs: list[list] | None = None)#
Evaluate the user observable over an epoch array.
- Parameters:
- targetBody
The observed body.
- epoch_arrayEpochArray, optional
Epochs at which to evaluate. Overrides the start/end/step form.
- epoch_start, epoch_endEpochArray, optional
Bounds used when epoch_array is not given.
- tstepfloat, optional
Step in seconds for the start/end form. Defaults to 1.
- frameFrame, optional
Reference frame of the relative state. Defaults to J2000.
- noisybool, optional
Add Gaussian noise of standard deviation
sigma.- pass_epochslist of list, optional
Pass grouping, forwarded to
set_pass_epochs().
- Returns:
- tuple
(t1, t2, t3, measurements)— the three time tags (identical for an ideal model) and the computed measurements as anArrayWFrame.
- generate_measurement_dataset(dataset_name: str | None = None, target: Body = None, observed_meas: tuple | list | None = None, epochs: EpochArray | None = None, frame: Frame = J2000 (0 - SOLAR SYSTEM BARYCENTER), noisy: bool = False) list[MeasurementDataSet]#
Generates a MeasurementDataSet object that can be used by filters downstream.
- Parameters:
- dataset_namestr, optional
The name of the MeasurementDataSet, which becomes the residual key in
solution.json. Defaults todefault_dataset_name—"<instrument>_<measurement_type>".- targetSpacecraft
The target spacecraft.
- observed_meastuple or list, optional
Observed measurements as
(epoch_array, meas_sec, meas_obs, outlier_flag). The computed values are evaluated atepoch_array. Give this orepochs, not both. Defaults toNone.- epochsEpochArray, optional
Epochs to simulate the measurements at, with no outliers flagged. Give this or
observed_meas, not both. Defaults toNone.- frameFrame, optional
The reference frame. Defaults to a J2000 Frame object.
- noisybool, optional
Indicates if noise is added to the measurements or not. Defaults to
False.
- Returns:
- mds_listlist[MeasurementDataSet]
A list of MeasurementDataSet objects representing the measurements with their key properties to be used by a filter.
- Raises:
- ValueError
If neither or both of
observed_measandepochsare given, ifobserved_meascarries fewer than four entries (the fourth is the outlier-flag array, without which the observations cannot be kept on one index set with their flags), or if the model has more than two components.
Notes
This is the single bridge from a measurement model to the estimator:
fit()andcompute()both come through here, andMeasurementDataSetis populated nowhere else. It pairs each observation with its computed value, residual, partial and sigma on one consistent set of indices, which is what lets several models with different epochs and different observables be combined into one filter update.That is also why it, rather than the caller, unpacks
t1, t2, t3fromcomputed_measurements(). The estimator needs the epochs alongside the observable –t2to match measurements across models,t1to detrend residuals during outlier rejection – so they have to survive the trip into the dataset. Seecomputed_measurements()for what each epoch means and why a single-epoch observable collapses all three.The MeasurementDataSet output is generated in 6 steps:
Computed measurements
Partials
Residuals
Sigmas
Outlier flag
Pack everything in a list
Pack the list in a MeasurementDataSet object
- observed_measurements(file_name, meas_name: str = 'meas_sim', units: Units = unitless, frame: Frame = J2000 (0 - SOLAR SYSTEM BARYCENTER), **read_kwargs) ObsData#
Reads measurements from a .json file.
- Parameters:
- file_namestr
The filename of the .json file containig the measurement information.
- meas_namestr, optional
The name of the measurement data to access from the dictionary. Defaults to
'meas_sim'. Files written before the rename use'meas_ideal'; either name resolves to whichever block the file actually contains, with a DeprecationWarning on the fallback.- unitsUnits, optional
Units to be used to write the output AWU. Defaults to
unitless.- frameFrame, optional
Frame to be used to write the output AWF. Defaults to a J2000 Frame object.
- **read_kwargs
Options for the model’s own
_read_aux(), forwarded unchanged. Models with no auxiliary data to read ignore them.This is where
sc_transponder_delay_RUgoes for the DSN radiometric models, which is the only such option today. It is not a named parameter here because this signature is shared by every measurement model, optical ones included.
- Returns:
- ObsData
A
ObsDatanamed tuple with five fields, addressable by name or index:[0]meas_time_etEpochArrayObservation epochs. Built from the file’s UTC station tag via
YDS2et(); see the comment at the conversion below for why this carries SPICE’s time model deliberately.
[1]meas_secnumpy.ndarrayThe observation times as seconds of day, as given in the file.
[2]meas_obsArrayWFrameThe observed quantities, with units and frame attached.
[3]meas_outliersnumpy.ndarrayPer-observation outlier flags, 1 = reject. Seeded from the file’s own
outlier_flagand additionally set here for records carrying the-1no-data sentinel and for the rows the model knows to be invalid (_flag_invalid_rows()). Downstream this is the authoritative flag array: it is what the filter,outlier_flags()and the editors gate on, andgenerate_measurement_dataset()writes into it when the forward model cannot compute an observation.
[4]aux_dictdictAncillary per-observation data read by the model’s
_read_aux(ramp tables, transponder ratios, electronic delays, …). None for models that need none.
Notes
The writing of the json assumes or requires units and frames.
Every row in the file is returned, including rows flagged bad. Nothing is dropped here, so the observations, the
aux_dictand any later outlier rejection all stay on one consistent set of indices.
- residuals(observed_meas: ArrayWFrame, computed_meas: ArrayWFrame) ArrayWFrame#
Generates the measurement model’s residuals given observed and computed ArrayWFrames.
- Parameters:
- observed_measArrayWFrame
The observed measurements values (O).
- computed_measArrayWFrame
The computed measurements values (C).
- Returns:
- residualsArrayWFrame
AWF with the residual O-C.
- set_pass_epochs(pass_epochs: list[list] | None)#
Enable per-pass biases.
- Parameters:
- pass_epochslist[list[float]] | None
Observation epochs grouped by pass, e.g.
[[t0, t1], [t10, t11]]. PassNoneto revert to global-bias mode.
- set_trajectory(trajectory)#
Attach the reference trajectory supplying the STMs.
Read only by the analytical light-time partials, which map a deviation between the endpoints of an observable (see
_short_arc_stm()).- Parameters:
- trajectoryTrajectory
Trajectory carrying the STMs. Must span every epoch the model evaluates.
- update_reference_state(state_vector: StateArray)#
Attach the estimated state the model should read its parameters from.
Call this once per iteration, before
generate_measurement_dataset(). The model then pulls the entries belonging to this instrument, matched on its SPICE ID:meas_bias_ideal_*, as anArrayWUnits.gs_delta_location_ECEF_*, as anArrayWFrame.
- Parameters:
- state_vectorStateArray
The current estimated state. Its layout is also recorded, so that the partials can build a column for every estimated parameter beyond position and velocity.
- write_observed_measurements(target: Spacecraft, epoch_array: EpochArray = None, epoch_start: EpochArray = None, epoch_end: EpochArray = None, tstep: float = 1, frame: Frame = J2000 (0 - SOLAR SYSTEM BARYCENTER), noisy: bool = False, file_name: str = 'ideal_measurement', check_visibility: bool = False, elevation_mask: ArrayWUnits | float = 10.0, folder_path_override: str = None, fmt: str = 'json') None#
Generates synthetic measurements and write them as a .json file. The input of this method encapsulate the ones needed for the “computed_meas” method in each measurement model class.
- Parameters:
- targetSpacecraft
The target spacecraft for which the range measurement is to be computed.
- epoch_arrayEpochArray, optional
An array of epochs (times) at which the range measurements should be computed. If provided, overrides
epoch_start,epoch_end, andtstep.- epoch_startEpochArray, optional
The starting epoch for the range measurement computations. Required if
epoch_arrayis not provided.- epoch_endEpochArray, optional
The ending epoch for the range measurement computations. Required if
epoch_arrayis not provided.- tstepfloat, optional
The time step, in seconds, between consecutive range measurements. If epoch_array is not provided. Defaults to
1second.- frameFrame , optional
The reference frame in which the range computation is performed. Defaults to
None.- noisybool , optional
Whether to add noise to the computed range measurement. Defaults to
False.- file_namestr, optional
The filename of the JSON in which the measurement is saved, Defaults to
'ideal_measurement'.- check_visibilitybool, optional
When
True, epochs where the instrument cannot observe the target are removed before generating measurements. The specific check is instrument-dependent:GroundStationuses an elevation-angle test;Camerauses a FOV projection test. Defaults toFalse.- elevation_maskArrayWUnits or float, optional
Minimum elevation angle used by the
GroundStationvisibility check. AnArrayWUnitsis converted from its own units; a bare number is read as degrees (seeresolve_elevation_mask(), which refuses a bare one that could be radians). Ignored forCamerainstruments. Only relevant whencheck_visibility=True. Defaults to10.0degrees.- folder_path_overridestr, optional
If provided, the JSON file is saved directly to this path instead of the default
data/measurements/radiometricordata/measurements/opticalfolder. The directory is created automatically if it does not exist. Defaults toNone.- fmt{“json”, “pickle”}, optional
On-disk format; selects the
.jsonor.pklextension appended tofile_name. Read back transparently byobserved_measurements(). Defaults to"json".
- Returns:
- None
- AUX_KEYS = None#
- DL_STATION_CAL = 850000.0#
Default downlink station calibration [RU] of simulated auxiliary data, the starting
dl_station_calof a model.Representative, not physical: real passes carry the station value.
- DSN_BANDS = {'S': Measurement.DSNBand(name='S', uplink_multiplier=221, downlink_multiplier=240, turnaround_num=240, turnaround_den=221, exciter_scalar_num=221.0, exciter_scalar_den=7072.0, uplink_frequency=2110362223.0 Hz, ru_reference_frequency=2303391185.181818 Hz), 'X': Measurement.DSNBand(name='X', uplink_multiplier=749, downlink_multiplier=880, turnaround_num=880, turnaround_den=749, exciter_scalar_num=221.0, exciter_scalar_den=23968.0, uplink_frequency=7152313596.9977 Hz, ru_reference_frequency=8445767679.0 Hz)}#
Default DSN frequency-band parameters, keyed by band letter, each a
DSNBand. A model starts with these asdsn_bands.Supported bands are
'X'and'S'.'X'holds the values the measurement models used as literals before they were collected here, so it is the default everywhere and reproduces the previous numbers exactly.[1]Moyer, T. D., Formulation for Observed and Computed Values of Deep Space Network Data Types for Navigation, JPL Publication 00-7, Monograph 2, Deep Space Communications and Navigation Series, Chapter 13.
[2]DSN Telecommunications Link Design Handbook, 810-005, Module 201, Frequency and Channel Assignments.
- LIGHT_TIME_FRAMES = ('barycentric', 'geocentric')#
- LIGHT_TIME_SETTINGS = {'et_tai_iterations': 2, 'max_iterations': 10, 'tolerance': 1e-12}#
Default settings of the round-trip light-time solution of the real measurement models, which take a dictionary with any of these keys as
light_time_settings. They apply to both solvers,_compute_precise_RTLT()and_compute_geocentric_RTLT()."tolerance"[s]: each leg (t3 to t2, then t2 to t1) is corrected with Moyer 2000 eq. 8-72 until the correction is no larger than this. 1e-12 s is 0.3 mm of one-way path. The correction cannot fall much below the float spacing of the one-way light time: 9.1e-13 s from 4096 s (8.2 AU), 1.8e-12 s from 8192 s (16 AU). A tolerance under that floor makes every leg run to"max_iterations", so raise it for distant spacecraft."max_iterations": iteration cap of each leg. A leg that reaches it keeps its last estimate and does not raise."et_tai_iterations": evaluations of the ET - TAI series (Moyer 2000 eq. 2-26) when the reception time is converted from TAI to ET. Each one is made at the ET the previous one gave. The first starts from the approximate series, eq. 2-27.
[1]Moyer, T.D. (2000). Formulation for Observed and Computed Values of Deep Space Network Data Types for Navigation. JPL Publication 00-7, Monograph 2, Deep Space Communications and Navigation Series, Sec. 8.3.6 and Eq. 2-26.
- PARTIALS_METHODS = ('fd', 'analytical')#
- RAMP_AUX_KEYS = ('ramp_sec', 'ramp_day', 'ramp_freq', 'ramp_rate', 'ramp_type')#
Auxiliary-data keys of the ramp table every real radiometric model carries: start second of day, day of year, frequency, rate and type of each ramp segment.
- RAMP_ENTRIES = 12#
Default number of entries of a simulated ramp table, the starting
ramp_entriesof a model.
- RAMP_MARGIN = 3600.0 sec#
Default span a simulated ramp table extends before the first and after the last observation, the starting
ramp_marginof a model.The uplink transmit time precedes the first tag by the round-trip light time, so a table that starts at the first tag raises
RampCoverageError. One hour clears a spacecraft out to the asteroid belt.
- RAMP_RATE = 0.2826 sec^-2#
Default uplink frequency ramp rate of a simulated ramp table, the starting
ramp_rateof a model.A representative DSN ramp slope, not a physical constant: real passes carry their measured rate in the ramp table.
- RAMP_TYPE = 1#
Default ramp type of a simulated ramp table, the SFDU 9
ramp_typecode of a ramped segment; the startingramp_typeof a model.
- RAMP_YEAR_KEY = 'ramp_year'#
Auxiliary-data key of the year of each ramp segment. Optional: a table read without it is assumed to lie in the year of the observations.
- RCV_TIME_TAG_DELAY = 0.0008 sec#
Default receive time-tag delay of simulated auxiliary data, the starting
rcv_time_tag_delayof a model.Representative, not physical: real passes carry the station value.
- TRANSPONDER_DELAY = 1e-05#
Default spacecraft transponder delay [RU] of simulated auxiliary data, the starting
transponder_delayof a model.Representative, not physical: real passes carry the calibrated delay.
- UL_STATION_CAL = 5000.0#
Default uplink station calibration [RU] of simulated auxiliary data, the starting
ul_station_calof a model.Representative, not physical: real passes carry the station value.
- property component_labels: tuple[str, str]#
Names of the two components of a vector observable.
A two-component measurement is split into one scalar dataset per component, and these are the suffixes those datasets carry — so they end up as the residual keys in
solution.json. Each model sets them in its__init__beside_measurement_type:AngularIdealmeasures("ra", "dec"),CentroidingIdeal("sample", "line").
- property computed_measurements_dict: dict#
Auxiliary TRK-2-34 tracking-data dictionary needed for the generation of the computed measurements of a real radiometric model. See the
computed_measurements_dictparameter ofDopplerRealandSequentialRangingRealfor the keys each requires.
- property default_dataset_name: str#
Dataset name used when the caller does not supply one.
"<instrument>_<measurement_type>", which is the convention the radiometric datasets already read as —DSS-14_RangeIdeal— and now the optical ones too. For a camera-based model the instrument is the camera, so a centroiding dataset comes out asNAC_CentroidingIdeal.Note that an
AngularIdealobserver is the spacecraft, not the camera (its name is resolved through SPICE), so a run that images with several cameras should passdataset_nameexplicitly to tell them apart.
- property dl_station_cal: float#
Downlink station calibration [RU] written into simulated auxiliary data. Starts as
DL_STATION_CAL.
- property dsn_bands: MappingProxyType#
DSN frequency-band parameters of this model, a read-only mapping from band letter to
DSNBand. Starts asDSN_BANDS.The
bandof a real model is looked up here, for the reference frequency that converts the transponder delay to seconds and the range unit of a tracking file without exciter scalars, and so is the band of thedefault_*_auxbuilders, which take its turnaround ratio, exciter scalars and uplink frequency.Set a whole new mapping to change it; its keys are upper-cased.
Examples
X = model.dsn_bands["X"] model.dsn_bands = { **model.dsn_bands, "X": dataclasses.replace(X, uplink_frequency=scb.ArrayWUnits(7.18e9, 1 / sec)), }
- property epoch_sec: EpochArray#
Observation epochs expressed as seconds of day.
- property instrument: Instrument#
The instrument.
- property media_corrections#
Tropospheric and ionospheric path-delay model, or
Noneif not set.
- property ramp_entries: int#
Number of entries of a simulated ramp table, at least 2. Starts as
RAMP_ENTRIES.
- property ramp_margin: ArrayWUnits#
Span [s] a simulated ramp table extends before the first and after the last observation. Starts as
RAMP_MARGIN; see_default_aux_grids()for why it is needed.Set an ArrayWUnits time, or a bare, non-negative number of seconds.
- property ramp_rate: ArrayWUnits#
Uplink frequency ramp rate [Hz/s] of the ramp table the
default_*_auxbuilders simulate. Starts asRAMP_RATE.Set an ArrayWUnits, converted to 1/s^2, or a bare number in Hz/s.
- property ramp_type: int#
SFDU 9
ramp_typecode of the segments of a simulated ramp table. Starts asRAMP_TYPE.
- property rcv_time_tag_delay: ArrayWUnits#
Receive time-tag delay [s] written into simulated auxiliary data. Starts as
RCV_TIME_TAG_DELAY.Set an ArrayWUnits time, or a bare number of seconds.
- property sigma: ArrayWUnits#
The standard deviation of the measurement model.
- property solar_corona_coefficient: float#
Coefficient of the solar-corona group delay [us GHz^2 m^2] of a real model built with
solar_corona=True. Starts asMediaCorrections.SOLAR_CORONA_DELAY_COEFF; seeMediaCorrections._compute_SC_lt.A fixed change of the delay model. To estimate a correction from the data, estimate
solar_corona_scaleinstead.
- station_eps_defaults = {'body_orientation_delta': 0.0001 rad, 'eop_delta_celestial_pole_x': 0.0001 rad, 'eop_delta_celestial_pole_y': 0.0001 rad, 'eop_delta_pole_x': 0.0001 rad, 'eop_delta_pole_y': 0.0001 rad, 'eop_delta_ut1': 1.0 sec, 'gs_delta_location_CYL': 1.0 km, 'gs_delta_location_ECEF': 1.0 km, 'iono_zenith_delay': 10.0 m, 'love_h2': 100.0, 'pole_dec': 0.0001 rad, 'pole_pm': 1e-06, 'pole_ra': 0.0001 rad, 'pole_w0': 0.0001 rad, 'shida_l2': 100.0, 'tropo_zenith_delay': 10.0 m}#
Finite-difference perturbations for station parameters, used only by
partials_method="fd"(_compute_partials_with_fd()); every analytical path differentiates the station in closed form. They live in the sameeps_dictas the spacecraftdx/dvxentries, keyed by StateDefinition parameter kind, so a model has one perturbation dictionary rather than two. The values are large because an RTLT solution and ramp integration lose significance in a small perturbation; they are numerical choices, not prior sigmas. The light time carries about 1e-13 s of noise per leg (SSB positions near 1.5e8 km), and a unit Love number moves a station by centimetres, so a Doppler fed by a step near one is mostly that noise. The tide and the zenith delays are exactly linear in their parameters, so their steps are as large as needed.
- property transponder_delay: float#
Spacecraft transponder delay [RU] written into simulated auxiliary data by the
default_*_auxbuilders. Starts asTRANSPONDER_DELAY.Only simulated data: a real pass takes the
sc_transponder_delay_RUgiven toobserved_measurements, or else the delay in its tracking file.
- property ul_station_cal: float#
Uplink station calibration [RU] written into simulated auxiliary data. Starts as
UL_STATION_CAL.
- property units#
Units of the computed measurement.
- exception DuplicateParameterError#
Bases:
ValueErrorRaised when the same parameter name is declared twice by one model.
- exception ShapeError#
Bases:
ValueErrorRaised when a user callable returns an array of unexpected shape.