pub struct KF<T, A, M>where
A: DimName,
M: DimName,
T: State,
DefaultAllocator: Allocator<M> + Allocator<<T as State>::Size> + Allocator<<T as State>::VecLength> + Allocator<A> + Allocator<M, M> + Allocator<M, <T as State>::Size> + Allocator<<T as State>::Size, <T as State>::Size> + Allocator<A, A> + Allocator<<T as State>::Size, A> + Allocator<A, <T as State>::Size>,
<DefaultAllocator as Allocator<<T as State>::Size>>::Buffer<f64>: Copy,
<DefaultAllocator as Allocator<<T as State>::Size, <T as State>::Size>>::Buffer<f64>: Copy,{
pub prev_estimate: KfEstimate<T>,
pub process_noise: Vec<SNC<A>>,
pub ekf: bool,
/* private fields */
}
Expand description
Defines both a Classical and an Extended Kalman filter (CKF and EKF) T: Type of state A: Acceleration size (for SNC) M: Measurement size (used for the sensitivity matrix)
Fields§
§prev_estimate: KfEstimate<T>
The previous estimate used in the KF computations.
process_noise: Vec<SNC<A>>
A sets of process noise (usually noted Q), must be ordered chronologically
ekf: bool
Determines whether this KF should operate as a Conventional/Classical Kalman filter or an Extended Kalman Filter. Recall that one should switch to an Extended KF only once the estimate is good (i.e. after a few good measurement updates on a CKF).
Implementations§
Source§impl<T, A, M> KF<T, A, M>where
A: DimName,
M: DimName,
T: State,
DefaultAllocator: Allocator<M> + Allocator<<T as State>::Size> + Allocator<<T as State>::VecLength> + Allocator<A> + Allocator<M, M> + Allocator<M, <T as State>::Size> + Allocator<<T as State>::Size, M> + Allocator<<T as State>::Size, <T as State>::Size> + Allocator<A, A> + Allocator<<T as State>::Size, A> + Allocator<A, <T as State>::Size>,
<DefaultAllocator as Allocator<<T as State>::Size>>::Buffer<f64>: Copy,
<DefaultAllocator as Allocator<<T as State>::Size, <T as State>::Size>>::Buffer<f64>: Copy,
impl<T, A, M> KF<T, A, M>where
A: DimName,
M: DimName,
T: State,
DefaultAllocator: Allocator<M> + Allocator<<T as State>::Size> + Allocator<<T as State>::VecLength> + Allocator<A> + Allocator<M, M> + Allocator<M, <T as State>::Size> + Allocator<<T as State>::Size, M> + Allocator<<T as State>::Size, <T as State>::Size> + Allocator<A, A> + Allocator<<T as State>::Size, A> + Allocator<A, <T as State>::Size>,
<DefaultAllocator as Allocator<<T as State>::Size>>::Buffer<f64>: Copy,
<DefaultAllocator as Allocator<<T as State>::Size, <T as State>::Size>>::Buffer<f64>: Copy,
Sourcepub fn new(initial_estimate: KfEstimate<T>, process_noise: SNC<A>) -> Self
pub fn new(initial_estimate: KfEstimate<T>, process_noise: SNC<A>) -> Self
Initializes this KF with an initial estimate, measurement noise, and one process noise
Examples found in repository?
33fn main() -> Result<(), Box<dyn Error>> {
34 pel::init();
35
36 // ====================== //
37 // === ALMANAC SET UP === //
38 // ====================== //
39
40 // Dynamics models require planetary constants and ephemerides to be defined.
41 // Let's start by grabbing those by using ANISE's MetaAlmanac.
42
43 let data_folder: PathBuf = [env!("CARGO_MANIFEST_DIR"), "examples", "04_lro_od"]
44 .iter()
45 .collect();
46
47 let meta = data_folder.join("lro-dynamics.dhall");
48
49 // Load this ephem in the general Almanac we're using for this analysis.
50 let mut almanac = MetaAlmanac::new(meta.to_string_lossy().to_string())
51 .map_err(Box::new)?
52 .process(true)
53 .map_err(Box::new)?;
54
55 let mut moon_pc = almanac.planetary_data.get_by_id(MOON)?;
56 moon_pc.mu_km3_s2 = 4902.74987;
57 almanac.planetary_data.set_by_id(MOON, moon_pc)?;
58
59 let mut earth_pc = almanac.planetary_data.get_by_id(EARTH)?;
60 earth_pc.mu_km3_s2 = 398600.436;
61 almanac.planetary_data.set_by_id(EARTH, earth_pc)?;
62
63 // Save this new kernel for reuse.
64 // In an operational context, this would be part of the "Lock" process, and should not change throughout the mission.
65 almanac
66 .planetary_data
67 .save_as(&data_folder.join("lro-specific.pca"), true)?;
68
69 // Lock the almanac (an Arc is a read only structure).
70 let almanac = Arc::new(almanac);
71
72 // Orbit determination requires a Trajectory structure, which can be saved as parquet file.
73 // In our case, the trajectory comes from the BSP file, so we need to build a Trajectory from the almanac directly.
74 // To query the Almanac, we need to build the LRO frame in the J2000 orientation in our case.
75 // Inspecting the LRO BSP in the ANISE GUI shows us that NASA has assigned ID -85 to LRO.
76 let lro_frame = Frame::from_ephem_j2000(-85);
77
78 // To build the trajectory we need to provide a spacecraft template.
79 let sc_template = Spacecraft::builder()
80 .mass(Mass::from_dry_and_prop_masses(1018.0, 900.0)) // Launch masses
81 .srp(SRPData {
82 // SRP configuration is arbitrary, but we will be estimating it anyway.
83 area_m2: 3.9 * 2.7,
84 coeff_reflectivity: 0.96,
85 })
86 .orbit(Orbit::zero(MOON_J2000)) // Setting a zero orbit here because it's just a template
87 .build();
88 // Now we can build the trajectory from the BSP file.
89 // We'll arbitrarily set the tracking arc to 24 hours with a five second time step.
90 let traj_as_flown = Traj::from_bsp(
91 lro_frame,
92 MOON_J2000,
93 almanac.clone(),
94 sc_template,
95 5.seconds(),
96 Some(Epoch::from_str("2024-01-01 00:00:00 UTC")?),
97 Some(Epoch::from_str("2024-01-02 00:00:00 UTC")?),
98 Aberration::LT,
99 Some("LRO".to_string()),
100 )?;
101
102 println!("{traj_as_flown}");
103
104 // ====================== //
105 // === MODEL MATCHING === //
106 // ====================== //
107
108 // Set up the spacecraft dynamics.
109
110 // Specify that the orbital dynamics must account for the graviational pull of the Earth and the Sun.
111 // The gravity of the Moon will also be accounted for since the spaceraft in a lunar orbit.
112 let mut orbital_dyn = OrbitalDynamics::point_masses(vec![EARTH, SUN, JUPITER_BARYCENTER]);
113
114 // We want to include the spherical harmonics, so let's download the gravitational data from the Nyx Cloud.
115 // We're using the GRAIL JGGRX model.
116 let mut jggrx_meta = MetaFile {
117 uri: "http://public-data.nyxspace.com/nyx/models/Luna_jggrx_1500e_sha.tab.gz".to_string(),
118 crc32: Some(0x6bcacda8), // Specifying the CRC32 avoids redownloading it if it's cached.
119 };
120 // And let's download it if we don't have it yet.
121 jggrx_meta.process(true)?;
122
123 // Build the spherical harmonics.
124 // The harmonics must be computed in the body fixed frame.
125 // We're using the long term prediction of the Moon principal axes frame.
126 let moon_pa_frame = MOON_PA_FRAME.with_orient(31008);
127 let sph_harmonics = Harmonics::from_stor(
128 almanac.frame_from_uid(moon_pa_frame)?,
129 HarmonicsMem::from_shadr(&jggrx_meta.uri, 80, 80, true)?,
130 );
131
132 // Include the spherical harmonics into the orbital dynamics.
133 orbital_dyn.accel_models.push(sph_harmonics);
134
135 // We define the solar radiation pressure, using the default solar flux and accounting only
136 // for the eclipsing caused by the Earth and Moon.
137 // Note that by default, enabling the SolarPressure model will also enable the estimation of the coefficient of reflectivity.
138 let srp_dyn = SolarPressure::new(vec![EARTH_J2000, MOON_J2000], almanac.clone())?;
139
140 // Finalize setting up the dynamics, specifying the force models (orbital_dyn) separately from the
141 // acceleration models (SRP in this case). Use `from_models` to specify multiple accel models.
142 let dynamics = SpacecraftDynamics::from_model(orbital_dyn, srp_dyn);
143
144 println!("{dynamics}");
145
146 // Now we can build the propagator.
147 let setup = Propagator::default_dp78(dynamics.clone());
148
149 // For reference, let's build the trajectory with Nyx's models from that LRO state.
150 let (sim_final, traj_as_sim) = setup
151 .with(*traj_as_flown.first(), almanac.clone())
152 .until_epoch_with_traj(traj_as_flown.last().epoch())?;
153
154 println!("SIM INIT: {:x}", traj_as_flown.first());
155 println!("SIM FINAL: {sim_final:x}");
156 // Compute RIC difference between SIM and LRO ephem
157 let sim_lro_delta = sim_final
158 .orbit
159 .ric_difference(&traj_as_flown.last().orbit)?;
160 println!("{traj_as_sim}");
161 println!(
162 "SIM v LRO - RIC Position (m): {:.3}",
163 sim_lro_delta.radius_km * 1e3
164 );
165 println!(
166 "SIM v LRO - RIC Velocity (m/s): {:.3}",
167 sim_lro_delta.velocity_km_s * 1e3
168 );
169
170 traj_as_sim.ric_diff_to_parquet(
171 &traj_as_flown,
172 "./04_lro_sim_truth_error.parquet",
173 ExportCfg::default(),
174 )?;
175
176 // ==================== //
177 // === OD SIMULATOR === //
178 // ==================== //
179
180 // After quite some time trying to exactly match the model, we still end up with an oscillatory difference on the order of 150 meters between the propagated state
181 // and the truth LRO state.
182
183 // Therefore, we will actually run an estimation from a dispersed LRO state.
184 // The sc_seed is the true LRO state from the BSP.
185 let sc_seed = *traj_as_flown.first();
186
187 // Load the Deep Space Network ground stations.
188 // Nyx allows you to build these at runtime but it's pretty static so we can just load them from YAML.
189 let ground_station_file: PathBuf = [
190 env!("CARGO_MANIFEST_DIR"),
191 "examples",
192 "04_lro_od",
193 "dsn-network.yaml",
194 ]
195 .iter()
196 .collect();
197
198 let devices = GroundStation::load_named(ground_station_file)?;
199
200 // Typical OD software requires that you specify your own tracking schedule or you'll have overlapping measurements.
201 // Nyx can build a tracking schedule for you based on the first station with access.
202 let trkconfg_yaml: PathBuf = [
203 env!("CARGO_MANIFEST_DIR"),
204 "examples",
205 "04_lro_od",
206 "tracking-cfg.yaml",
207 ]
208 .iter()
209 .collect();
210
211 let configs: BTreeMap<String, TrkConfig> = TrkConfig::load_named(trkconfg_yaml)?;
212
213 // Build the tracking arc simulation to generate a "standard measurement".
214 let mut trk = TrackingArcSim::<Spacecraft, GroundStation>::new(
215 devices.clone(),
216 traj_as_flown.clone(),
217 configs,
218 )?;
219
220 trk.build_schedule(almanac.clone())?;
221 let arc = trk.generate_measurements(almanac.clone())?;
222 // Save the simulated tracking data
223 arc.to_parquet_simple("./04_lro_simulated_tracking.parquet")?;
224
225 // We'll note that in our case, we have continuous coverage of LRO when the vehicle is not behind the Moon.
226 println!("{arc}");
227
228 // Now that we have simulated measurements, we'll run the orbit determination.
229
230 // ===================== //
231 // === OD ESTIMATION === //
232 // ===================== //
233
234 let sc = SpacecraftUncertainty::builder()
235 .nominal(sc_seed)
236 .frame(LocalFrame::RIC)
237 .x_km(0.5)
238 .y_km(0.5)
239 .z_km(0.5)
240 .vx_km_s(5e-3)
241 .vy_km_s(5e-3)
242 .vz_km_s(5e-3)
243 .build();
244
245 // Build the filter initial estimate, which we will reuse in the filter.
246 let initial_estimate = sc.to_estimate()?;
247
248 println!("== FILTER STATE ==\n{sc_seed:x}\n{initial_estimate}");
249
250 let kf = KF::new(
251 // Increase the initial covariance to account for larger deviation.
252 initial_estimate,
253 // Until https://github.com/nyx-space/nyx/issues/351, we need to specify the SNC in the acceleration of the Moon J2000 frame.
254 SNC3::from_diagonal(10 * Unit::Minute, &[1e-12, 1e-12, 1e-12]),
255 );
256
257 // We'll set up the OD process to reject measurements whose residuals are move than 3 sigmas away from what we expect.
258 let mut odp = SpacecraftODProcess::ckf(
259 setup.with(initial_estimate.state().with_stm(), almanac.clone()),
260 kf,
261 devices,
262 Some(ResidRejectCrit::default()),
263 almanac.clone(),
264 );
265
266 odp.process_arc(&arc)?;
267
268 let ric_err = traj_as_flown
269 .at(odp.estimates.last().unwrap().epoch())?
270 .orbit
271 .ric_difference(&odp.estimates.last().unwrap().orbital_state())?;
272 println!("== RIC at end ==");
273 println!("RIC Position (m): {}", ric_err.radius_km * 1e3);
274 println!("RIC Velocity (m/s): {}", ric_err.velocity_km_s * 1e3);
275
276 odp.to_parquet(&arc, "./04_lro_od_results.parquet", ExportCfg::default())?;
277
278 // In our case, we have the truth trajectory from NASA.
279 // So we can compute the RIC state difference between the real LRO ephem and what we've just estimated.
280 // Export the OD trajectory first.
281 let od_trajectory = odp.to_traj()?;
282 // Build the RIC difference.
283 od_trajectory.ric_diff_to_parquet(
284 &traj_as_flown,
285 "./04_lro_od_truth_error.parquet",
286 ExportCfg::default(),
287 )?;
288
289 Ok(())
290}
Sourcepub fn with_sncs(
initial_estimate: KfEstimate<T>,
process_noises: Vec<SNC<A>>,
) -> Self
pub fn with_sncs( initial_estimate: KfEstimate<T>, process_noises: Vec<SNC<A>>, ) -> Self
Initializes this KF with an initial estimate, measurement noise, and several process noise WARNING: SNCs MUST be ordered chronologically! They will be selected automatically by walking the list of SNCs backward until one can be applied!
Source§impl<T, M> KF<T, U3, M>where
M: DimName,
T: State,
DefaultAllocator: Allocator<M> + Allocator<<T as State>::Size> + Allocator<<T as State>::VecLength> + Allocator<M, M> + Allocator<M, <T as State>::Size> + Allocator<<T as State>::Size, M> + Allocator<<T as State>::Size, <T as State>::Size> + Allocator<U3, U3> + Allocator<<T as State>::Size, U3> + Allocator<U3, <T as State>::Size>,
<DefaultAllocator as Allocator<<T as State>::Size>>::Buffer<f64>: Copy,
<DefaultAllocator as Allocator<<T as State>::Size, <T as State>::Size>>::Buffer<f64>: Copy,
impl<T, M> KF<T, U3, M>where
M: DimName,
T: State,
DefaultAllocator: Allocator<M> + Allocator<<T as State>::Size> + Allocator<<T as State>::VecLength> + Allocator<M, M> + Allocator<M, <T as State>::Size> + Allocator<<T as State>::Size, M> + Allocator<<T as State>::Size, <T as State>::Size> + Allocator<U3, U3> + Allocator<<T as State>::Size, U3> + Allocator<U3, <T as State>::Size>,
<DefaultAllocator as Allocator<<T as State>::Size>>::Buffer<f64>: Copy,
<DefaultAllocator as Allocator<<T as State>::Size, <T as State>::Size>>::Buffer<f64>: Copy,
Sourcepub fn no_snc(initial_estimate: KfEstimate<T>) -> Self
pub fn no_snc(initial_estimate: KfEstimate<T>) -> Self
Initializes this KF without SNC
Examples found in repository?
26fn main() -> Result<(), Box<dyn Error>> {
27 pel::init();
28 // Dynamics models require planetary constants and ephemerides to be defined.
29 // Let's start by grabbing those by using ANISE's latest MetaAlmanac.
30 // For details, refer to https://github.com/nyx-space/anise/blob/master/data/latest.dhall.
31
32 // Download the regularly update of the James Webb Space Telescope reconstucted (or definitive) ephemeris.
33 // Refer to https://naif.jpl.nasa.gov/pub/naif/JWST/kernels/spk/aareadme.txt for details.
34 let mut latest_jwst_ephem = MetaFile {
35 uri: "https://naif.jpl.nasa.gov/pub/naif/JWST/kernels/spk/jwst_rec.bsp".to_string(),
36 crc32: None,
37 };
38 latest_jwst_ephem.process(true)?;
39
40 // Load this ephem in the general Almanac we're using for this analysis.
41 let almanac = Arc::new(
42 MetaAlmanac::latest()
43 .map_err(Box::new)?
44 .load_from_metafile(latest_jwst_ephem, true)?,
45 );
46
47 // By loading this ephemeris file in the ANISE GUI or ANISE CLI, we can find the NAIF ID of the JWST
48 // in the BSP. We need this ID in order to query the ephemeris.
49 const JWST_NAIF_ID: i32 = -170;
50 // Let's build a frame in the J2000 orientation centered on the JWST.
51 const JWST_J2000: Frame = Frame::from_ephem_j2000(JWST_NAIF_ID);
52
53 // Since the ephemeris file is updated regularly, we'll just grab the latest state in the ephem.
54 let (earliest_epoch, latest_epoch) = almanac.spk_domain(JWST_NAIF_ID)?;
55 println!("JWST defined from {earliest_epoch} to {latest_epoch}");
56 // Fetch the state, printing it in the Earth J2000 frame.
57 let jwst_orbit = almanac.transform(JWST_J2000, EARTH_J2000, latest_epoch, None)?;
58 println!("{jwst_orbit:x}");
59
60 // Build the spacecraft
61 // SRP area assumed to be the full sunshield and mass if 6200.0 kg, c.f. https://webb.nasa.gov/content/about/faqs/facts.html
62 // SRP Coefficient of reflectivity assumed to be that of Kapton, i.e. 2 - 0.44 = 1.56, table 1 from https://amostech.com/TechnicalPapers/2018/Poster/Bengtson.pdf
63 let jwst = Spacecraft::builder()
64 .orbit(jwst_orbit)
65 .srp(SRPData {
66 area_m2: 21.197 * 14.162,
67 coeff_reflectivity: 1.56,
68 })
69 .mass(Mass::from_dry_mass(6200.0))
70 .build();
71
72 // Build up the spacecraft uncertainty builder.
73 // We can use the spacecraft uncertainty structure to build this up.
74 // We start by specifying the nominal state (as defined above), then the uncertainty in position and velocity
75 // in the RIC frame. We could also specify the Cr, Cd, and mass uncertainties, but these aren't accounted for until
76 // Nyx can also estimate the deviation of the spacecraft parameters.
77 let jwst_uncertainty = SpacecraftUncertainty::builder()
78 .nominal(jwst)
79 .frame(LocalFrame::RIC)
80 .x_km(0.5)
81 .y_km(0.3)
82 .z_km(1.5)
83 .vx_km_s(1e-4)
84 .vy_km_s(0.6e-3)
85 .vz_km_s(3e-3)
86 .build();
87
88 println!("{jwst_uncertainty}");
89
90 // Build the Kalman filter estimate.
91 // Note that we could have used the KfEstimate structure directly (as seen throughout the OD integration tests)
92 // but this approach requires quite a bit more boilerplate code.
93 let jwst_estimate = jwst_uncertainty.to_estimate()?;
94
95 // Set up the spacecraft dynamics.
96 // We'll use the point masses of the Earth, Sun, Jupiter (barycenter, because it's in the DE440), and the Moon.
97 // We'll also enable solar radiation pressure since the James Webb has a huge and highly reflective sun shield.
98
99 let orbital_dyn = OrbitalDynamics::point_masses(vec![MOON, SUN, JUPITER_BARYCENTER]);
100 let srp_dyn = SolarPressure::new(vec![EARTH_J2000, MOON_J2000], almanac.clone())?;
101
102 // Finalize setting up the dynamics.
103 let dynamics = SpacecraftDynamics::from_model(orbital_dyn, srp_dyn);
104
105 // Build the propagator set up to use for the whole analysis.
106 let setup = Propagator::default(dynamics);
107
108 // All of the analysis will use this duration.
109 let prediction_duration = 6.5 * Unit::Day;
110
111 // === Covariance mapping ===
112 // For the covariance mapping / prediction, we'll use the common orbit determination approach.
113 // This is done by setting up a spacecraft OD process, and predicting for the analysis duration.
114
115 let ckf = KF::no_snc(jwst_estimate);
116
117 // Build the propagation instance for the OD process.
118 let prop = setup.with(jwst.with_stm(), almanac.clone());
119 let mut odp = SpacecraftODProcess::ckf(prop, ckf, BTreeMap::new(), None, almanac.clone());
120
121 // Define the prediction step, i.e. how often we want to know the covariance.
122 let step = 1_i64.minutes();
123 // Finally, predict, and export the trajectory with covariance to a parquet file.
124 odp.predict_for(step, prediction_duration)?;
125 odp.to_parquet(
126 &TrackingDataArc::default(),
127 "./02_jwst_covar_map.parquet",
128 ExportCfg::default(),
129 )?;
130
131 // === Monte Carlo framework ===
132 // Nyx comes with a complete multi-threaded Monte Carlo frame. It's blazing fast.
133
134 let my_mc = MonteCarlo::new(
135 jwst, // Nominal state
136 jwst_estimate.to_random_variable()?,
137 "02_jwst".to_string(), // Scenario name
138 None, // No specific seed specified, so one will be drawn from the computer's entropy.
139 );
140
141 let num_runs = 5_000;
142 let rslts = my_mc.run_until_epoch(
143 setup,
144 almanac.clone(),
145 jwst.epoch() + prediction_duration,
146 num_runs,
147 );
148
149 assert_eq!(rslts.runs.len(), num_runs);
150 // Finally, export these results, computing the eclipse percentage for all of these results.
151
152 // For all of the resulting trajectories, we'll want to compute the percentage of penumbra and umbra.
153 let eclipse_loc = EclipseLocator::cislunar(almanac.clone());
154 let umbra_event = eclipse_loc.to_umbra_event();
155 let penumbra_event = eclipse_loc.to_penumbra_event();
156
157 rslts.to_parquet(
158 "02_jwst_monte_carlo.parquet",
159 Some(vec![&umbra_event, &penumbra_event]),
160 ExportCfg::default(),
161 almanac,
162 )?;
163
164 Ok(())
165}
Trait Implementations§
Source§impl<T, A, M> Clone for KF<T, A, M>where
A: DimName + Clone,
M: DimName + Clone,
T: State + Clone,
DefaultAllocator: Allocator<M> + Allocator<<T as State>::Size> + Allocator<<T as State>::VecLength> + Allocator<A> + Allocator<M, M> + Allocator<M, <T as State>::Size> + Allocator<<T as State>::Size, <T as State>::Size> + Allocator<A, A> + Allocator<<T as State>::Size, A> + Allocator<A, <T as State>::Size>,
<DefaultAllocator as Allocator<<T as State>::Size>>::Buffer<f64>: Copy,
<DefaultAllocator as Allocator<<T as State>::Size, <T as State>::Size>>::Buffer<f64>: Copy,
impl<T, A, M> Clone for KF<T, A, M>where
A: DimName + Clone,
M: DimName + Clone,
T: State + Clone,
DefaultAllocator: Allocator<M> + Allocator<<T as State>::Size> + Allocator<<T as State>::VecLength> + Allocator<A> + Allocator<M, M> + Allocator<M, <T as State>::Size> + Allocator<<T as State>::Size, <T as State>::Size> + Allocator<A, A> + Allocator<<T as State>::Size, A> + Allocator<A, <T as State>::Size>,
<DefaultAllocator as Allocator<<T as State>::Size>>::Buffer<f64>: Copy,
<DefaultAllocator as Allocator<<T as State>::Size, <T as State>::Size>>::Buffer<f64>: Copy,
Source§impl<T, A, M> Debug for KF<T, A, M>where
A: DimName + Debug,
M: DimName + Debug,
T: State + Debug,
DefaultAllocator: Allocator<M> + Allocator<<T as State>::Size> + Allocator<<T as State>::VecLength> + Allocator<A> + Allocator<M, M> + Allocator<M, <T as State>::Size> + Allocator<<T as State>::Size, <T as State>::Size> + Allocator<A, A> + Allocator<<T as State>::Size, A> + Allocator<A, <T as State>::Size>,
<DefaultAllocator as Allocator<<T as State>::Size>>::Buffer<f64>: Copy,
<DefaultAllocator as Allocator<<T as State>::Size, <T as State>::Size>>::Buffer<f64>: Copy,
impl<T, A, M> Debug for KF<T, A, M>where
A: DimName + Debug,
M: DimName + Debug,
T: State + Debug,
DefaultAllocator: Allocator<M> + Allocator<<T as State>::Size> + Allocator<<T as State>::VecLength> + Allocator<A> + Allocator<M, M> + Allocator<M, <T as State>::Size> + Allocator<<T as State>::Size, <T as State>::Size> + Allocator<A, A> + Allocator<<T as State>::Size, A> + Allocator<A, <T as State>::Size>,
<DefaultAllocator as Allocator<<T as State>::Size>>::Buffer<f64>: Copy,
<DefaultAllocator as Allocator<<T as State>::Size, <T as State>::Size>>::Buffer<f64>: Copy,
Source§impl<T, A, M> Filter<T, A, M> for KF<T, A, M>where
A: DimName,
M: DimName,
T: State,
DefaultAllocator: Allocator<M> + Allocator<<T as State>::Size> + Allocator<<T as State>::VecLength> + Allocator<A> + Allocator<M, M> + Allocator<M, <T as State>::Size> + Allocator<<T as State>::Size, M> + Allocator<<T as State>::Size, <T as State>::Size> + Allocator<A, A> + Allocator<<T as State>::Size, A> + Allocator<A, <T as State>::Size> + Allocator<Const<1>, M>,
<DefaultAllocator as Allocator<<T as State>::Size>>::Buffer<f64>: Copy,
<DefaultAllocator as Allocator<<T as State>::Size, <T as State>::Size>>::Buffer<f64>: Copy,
impl<T, A, M> Filter<T, A, M> for KF<T, A, M>where
A: DimName,
M: DimName,
T: State,
DefaultAllocator: Allocator<M> + Allocator<<T as State>::Size> + Allocator<<T as State>::VecLength> + Allocator<A> + Allocator<M, M> + Allocator<M, <T as State>::Size> + Allocator<<T as State>::Size, M> + Allocator<<T as State>::Size, <T as State>::Size> + Allocator<A, A> + Allocator<<T as State>::Size, A> + Allocator<A, <T as State>::Size> + Allocator<Const<1>, M>,
<DefaultAllocator as Allocator<<T as State>::Size>>::Buffer<f64>: Copy,
<DefaultAllocator as Allocator<<T as State>::Size, <T as State>::Size>>::Buffer<f64>: Copy,
Source§fn previous_estimate(&self) -> &Self::Estimate
fn previous_estimate(&self) -> &Self::Estimate
Returns the previous estimate
Source§fn update_h_tilde(&mut self, h_tilde: OMatrix<f64, M, <T as State>::Size>)
fn update_h_tilde(&mut self, h_tilde: OMatrix<f64, M, <T as State>::Size>)
Update the sensitivity matrix (or “H tilde”). This function must be called prior to each
call to measurement_update
.
Source§fn time_update(&mut self, nominal_state: T) -> Result<Self::Estimate, ODError>
fn time_update(&mut self, nominal_state: T) -> Result<Self::Estimate, ODError>
Computes a time update/prediction (i.e. advances the filter estimate with the updated STM).
May return a FilterError if the STM was not updated.
Source§fn measurement_update(
&mut self,
nominal_state: T,
real_obs: &OVector<f64, M>,
computed_obs: &OVector<f64, M>,
r_k: OMatrix<f64, M, M>,
resid_rejection: Option<ResidRejectCrit>,
) -> Result<(Self::Estimate, Residual<M>), ODError>
fn measurement_update( &mut self, nominal_state: T, real_obs: &OVector<f64, M>, computed_obs: &OVector<f64, M>, r_k: OMatrix<f64, M, M>, resid_rejection: Option<ResidRejectCrit>, ) -> Result<(Self::Estimate, Residual<M>), ODError>
Computes the measurement update with a provided real observation and computed observation.
May return a FilterError if the STM or sensitivity matrices were not updated.
Source§fn set_process_noise(&mut self, snc: SNC<A>)
fn set_process_noise(&mut self, snc: SNC<A>)
Overwrites all of the process noises to the one provided
type Estimate = KfEstimate<T>
Source§fn set_previous_estimate(&mut self, est: &Self::Estimate)
fn set_previous_estimate(&mut self, est: &Self::Estimate)
Source§fn is_extended(&self) -> bool
fn is_extended(&self) -> bool
Source§fn set_extended(&mut self, status: bool)
fn set_extended(&mut self, status: bool)
Auto Trait Implementations§
impl<T, A, M> !Freeze for KF<T, A, M>
impl<T, A, M> !RefUnwindSafe for KF<T, A, M>
impl<T, A, M> !Send for KF<T, A, M>
impl<T, A, M> !Sync for KF<T, A, M>
impl<T, A, M> !Unpin for KF<T, A, M>
impl<T, A, M> !UnwindSafe for KF<T, A, M>
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
§impl<T> Instrument for T
impl<T> Instrument for T
§fn instrument(self, span: Span) -> Instrumented<Self>
fn instrument(self, span: Span) -> Instrumented<Self>
§fn in_current_span(self) -> Instrumented<Self>
fn in_current_span(self) -> Instrumented<Self>
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self>
fn into_either(self, into_left: bool) -> Either<Self, Self>
self
into a Left
variant of Either<Self, Self>
if into_left
is true
.
Converts self
into a Right
variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
self
into a Left
variant of Either<Self, Self>
if into_left(&self)
returns true
.
Converts self
into a Right
variant of Either<Self, Self>
otherwise. Read more§impl<T> Pointable for T
impl<T> Pointable for T
§impl<SS, SP> SupersetOf<SS> for SPwhere
SS: SubsetOf<SP>,
impl<SS, SP> SupersetOf<SS> for SPwhere
SS: SubsetOf<SP>,
§fn to_subset(&self) -> Option<SS>
fn to_subset(&self) -> Option<SS>
self
from the equivalent element of its
superset. Read more§fn is_in_subset(&self) -> bool
fn is_in_subset(&self) -> bool
self
is actually part of its subset T
(and can be converted to it).§fn to_subset_unchecked(&self) -> SS
fn to_subset_unchecked(&self) -> SS
self.to_subset
but without any property checks. Always succeeds.§fn from_subset(element: &SS) -> SP
fn from_subset(element: &SS) -> SP
self
to the equivalent element of its superset.