nyx_space/od/noise/
white.rs1use std::ops::{Mul, MulAssign};
20
21use anise::constants::SPEED_OF_LIGHT_KM_S;
22use hifitime::{Duration, Epoch};
23use rand::Rng;
24use rand_distr::Normal;
25use serde_derive::{Deserialize, Serialize};
26
27use super::Stochastics;
28
29#[derive(Copy, Clone, Debug, Default, PartialEq, Serialize, Deserialize)]
31pub struct WhiteNoise {
32 pub mean: f64,
34 pub sigma: f64,
36}
37
38impl WhiteNoise {
39 pub fn new(process_noise: f64, integration_time: Duration) -> Self {
42 Self {
43 sigma: process_noise / integration_time.to_seconds(),
44 ..Default::default()
45 }
46 }
47
48 pub fn constant_white_noise(process_noise: f64) -> Self {
51 Self {
52 sigma: process_noise,
53 ..Default::default()
54 }
55 }
56
57 pub fn from_pr_n0(pr_n0: f64, bandwidth_hz: f64) -> Self {
65 Self {
66 sigma: SPEED_OF_LIGHT_KM_S / (2.0 * bandwidth_hz * (pr_n0).sqrt()),
67 mean: 0.0,
68 }
69 }
70}
71
72impl Stochastics for WhiteNoise {
73 fn covariance(&self, _epoch: Epoch) -> f64 {
74 self.sigma.powi(2)
75 }
76
77 fn sample<R: Rng>(&mut self, _epoch: Epoch, rng: &mut R) -> f64 {
78 rng.sample(Normal::new(self.mean, self.sigma).unwrap())
79 }
80}
81
82impl Mul<f64> for WhiteNoise {
83 type Output = Self;
84
85 fn mul(mut self, rhs: f64) -> Self::Output {
87 self.sigma *= rhs;
88 self
89 }
90}
91
92impl MulAssign<f64> for WhiteNoise {
93 fn mul_assign(&mut self, rhs: f64) {
94 *self = *self * rhs;
95 }
96}
97
98#[cfg(test)]
99mod ut_wn {
100 use hifitime::{Epoch, TimeUnits};
101 use rand_pcg::Pcg64Mcg;
102
103 use super::{Stochastics, WhiteNoise};
104
105 #[test]
106 fn white_noise_test() {
107 let sigma = 10.0_f64;
108 let mut wn = WhiteNoise { mean: 0.0, sigma };
109
110 let mut larger_wn = WhiteNoise {
111 mean: 0.0,
112 sigma: sigma * 10.0,
113 };
114
115 let epoch = Epoch::now().unwrap();
116
117 let mut rng = Pcg64Mcg::new(1000);
118 let mut cnt_above_3sigma = 0;
119 let mut cnt_below_3sigma = 0;
120 let mut larger_cnt_above_3sigma = 0;
121 let mut larger_cnt_below_3sigma = 0;
122 for seconds in 0..1000_i64 {
123 let bias = wn.sample(epoch + seconds.seconds(), &mut rng);
124
125 if bias > 3.0 * sigma {
126 cnt_above_3sigma += 1;
127 } else if bias < -3.0 * sigma {
128 cnt_below_3sigma += 1;
129 }
130
131 let larger_bias = larger_wn.sample(epoch + seconds.seconds(), &mut rng);
132 if larger_bias > 30.0 * sigma {
133 larger_cnt_above_3sigma += 1;
134 } else if larger_bias < -30.0 * sigma {
135 larger_cnt_below_3sigma += 1;
136 }
137 }
138
139 assert!(dbg!(cnt_above_3sigma) <= 3);
140 assert!(dbg!(cnt_below_3sigma) <= 3);
141
142 assert!(dbg!(larger_cnt_above_3sigma) <= 3);
143 assert!(dbg!(larger_cnt_below_3sigma) <= 3);
144 }
145}