statrs/generate.rs
1//! Provides utility functions for generating data sequences
2
3use crate::euclid::Modulus;
4use std::f64::consts;
5/// Generates a base 10 log spaced vector of the given length between the
6/// specified decade exponents (inclusive). Equivalent to MATLAB logspace
7///
8/// # Examples
9///
10/// ```
11/// use statrs::generate;
12///
13/// let x = generate::log_spaced(5, 0.0, 4.0);
14/// assert_eq!(x, [1.0, 10.0, 100.0, 1000.0, 10000.0]);
15/// ```
16pub fn log_spaced(length: usize, start_exp: f64, stop_exp: f64) -> Vec<f64> {
17 match length {
18 0 => Vec::new(),
19 1 => vec![10f64.powf(stop_exp)],
20 _ => {
21 let step = (stop_exp - start_exp) / (length - 1) as f64;
22 let mut vec = (0..length)
23 .map(|x| 10f64.powf(start_exp + (x as f64) * step))
24 .collect::<Vec<f64>>();
25 vec[length - 1] = 10f64.powf(stop_exp);
26 vec
27 }
28 }
29}
30
31/// Infinite iterator returning floats that form a periodic wave
32pub struct InfinitePeriodic {
33 amplitude: f64,
34 step: f64,
35 phase: f64,
36 k: f64,
37}
38
39impl InfinitePeriodic {
40 /// Constructs a new infinite periodic wave generator
41 ///
42 /// # Examples
43 ///
44 /// ```
45 /// use statrs::generate::InfinitePeriodic;
46 ///
47 /// let x = InfinitePeriodic::new(8.0, 2.0, 10.0, 1.0,
48 /// 2).take(10).collect::<Vec<f64>>();
49 /// assert_eq!(x, [6.0, 8.5, 1.0, 3.5, 6.0, 8.5, 1.0, 3.5, 6.0, 8.5]);
50 /// ```
51 pub fn new(
52 sampling_rate: f64,
53 frequency: f64,
54 amplitude: f64,
55 phase: f64,
56 delay: i64,
57 ) -> InfinitePeriodic {
58 let step = frequency / sampling_rate * amplitude;
59 InfinitePeriodic {
60 amplitude,
61 step,
62 phase: (phase - delay as f64 * step).modulus(amplitude),
63 k: 0.0,
64 }
65 }
66
67 /// Constructs a default infinite periodic wave generator
68 ///
69 /// # Examples
70 ///
71 /// ```
72 /// use statrs::generate::InfinitePeriodic;
73 ///
74 /// let x = InfinitePeriodic::default(8.0,
75 /// 2.0).take(10).collect::<Vec<f64>>();
76 /// assert_eq!(x, [0.0, 0.25, 0.5, 0.75, 0.0, 0.25, 0.5, 0.75, 0.0, 0.25]);
77 /// ```
78 pub fn default(sampling_rate: f64, frequency: f64) -> InfinitePeriodic {
79 Self::new(sampling_rate, frequency, 1.0, 0.0, 0)
80 }
81}
82
83impl Iterator for InfinitePeriodic {
84 type Item = f64;
85
86 fn next(&mut self) -> Option<f64> {
87 let mut x = self.phase + self.k * self.step;
88 if x >= self.amplitude {
89 x %= self.amplitude;
90 self.phase = x;
91 self.k = 0.0;
92 }
93 self.k += 1.0;
94 Some(x)
95 }
96}
97
98/// Infinite iterator returning floats that form a sinusoidal wave
99pub struct InfiniteSinusoidal {
100 amplitude: f64,
101 mean: f64,
102 step: f64,
103 phase: f64,
104 i: usize,
105}
106
107impl InfiniteSinusoidal {
108 /// Constructs a new infinite sinusoidal wave generator
109 ///
110 /// # Examples
111 ///
112 /// ```
113 /// use statrs::generate::InfiniteSinusoidal;
114 ///
115 /// let x = InfiniteSinusoidal::new(8.0, 2.0, 1.0, 5.0, 2.0,
116 /// 1).take(10).collect::<Vec<f64>>();
117 /// assert_eq!(x,
118 /// [5.416146836547142, 5.909297426825682, 4.583853163452858,
119 /// 4.090702573174318, 5.416146836547142, 5.909297426825682,
120 /// 4.583853163452858, 4.090702573174318, 5.416146836547142,
121 /// 5.909297426825682]);
122 /// ```
123 pub fn new(
124 sampling_rate: f64,
125 frequency: f64,
126 amplitude: f64,
127 mean: f64,
128 phase: f64,
129 delay: i64,
130 ) -> InfiniteSinusoidal {
131 let pi2 = consts::PI * 2.0;
132 let step = frequency / sampling_rate * pi2;
133 InfiniteSinusoidal {
134 amplitude,
135 mean,
136 step,
137 phase: (phase - delay as f64 * step) % pi2,
138 i: 0,
139 }
140 }
141
142 /// Constructs a default infinite sinusoidal wave generator
143 ///
144 /// # Examples
145 ///
146 /// ```
147 /// use statrs::generate::InfiniteSinusoidal;
148 ///
149 /// let x = InfiniteSinusoidal::default(8.0, 2.0,
150 /// 1.0).take(10).collect::<Vec<f64>>();
151 /// assert_eq!(x,
152 /// [0.0, 1.0, 0.00000000000000012246467991473532,
153 /// -1.0, -0.00000000000000024492935982947064, 1.0,
154 /// 0.00000000000000036739403974420594, -1.0,
155 /// -0.0000000000000004898587196589413, 1.0]);
156 /// ```
157 pub fn default(sampling_rate: f64, frequency: f64, amplitude: f64) -> InfiniteSinusoidal {
158 Self::new(sampling_rate, frequency, amplitude, 0.0, 0.0, 0)
159 }
160}
161
162impl Iterator for InfiniteSinusoidal {
163 type Item = f64;
164
165 fn next(&mut self) -> Option<f64> {
166 let x = self.mean + self.amplitude * (self.phase + self.i as f64 * self.step).sin();
167 self.i += 1;
168 if self.i == 1000 {
169 self.i = 0;
170 self.phase = (self.phase + 1000.0 * self.step) % (consts::PI * 2.0);
171 }
172 Some(x)
173 }
174}
175
176/// Infinite iterator returning floats forming a square wave starting
177/// with the high phase
178pub struct InfiniteSquare {
179 periodic: InfinitePeriodic,
180 high_duration: f64,
181 high_value: f64,
182 low_value: f64,
183}
184
185impl InfiniteSquare {
186 /// Constructs a new infinite square wave generator
187 ///
188 /// # Examples
189 ///
190 /// ```
191 /// use statrs::generate::InfiniteSquare;
192 ///
193 /// let x = InfiniteSquare::new(3, 7, 1.0, -1.0,
194 /// 1).take(12).collect::<Vec<f64>>();
195 /// assert_eq!(x, [-1.0, 1.0, 1.0, 1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0,
196 /// -1.0, 1.0])
197 /// ```
198 pub fn new(
199 high_duration: i64,
200 low_duration: i64,
201 high_value: f64,
202 low_value: f64,
203 delay: i64,
204 ) -> InfiniteSquare {
205 let duration = (high_duration + low_duration) as f64;
206 InfiniteSquare {
207 periodic: InfinitePeriodic::new(1.0, 1.0 / duration, duration, 0.0, delay),
208 high_duration: high_duration as f64,
209 high_value,
210 low_value,
211 }
212 }
213}
214
215impl Iterator for InfiniteSquare {
216 type Item = f64;
217
218 fn next(&mut self) -> Option<f64> {
219 self.periodic.next().map(|x| {
220 if x < self.high_duration {
221 self.high_value
222 } else {
223 self.low_value
224 }
225 })
226 }
227}
228
229/// Infinite iterator returning floats forming a triangle wave starting with
230/// the raise phase from the lowest sample
231pub struct InfiniteTriangle {
232 periodic: InfinitePeriodic,
233 raise_duration: f64,
234 raise: f64,
235 fall: f64,
236 high_value: f64,
237 low_value: f64,
238}
239
240impl InfiniteTriangle {
241 /// Constructs a new infinite triangle wave generator
242 ///
243 /// # Examples
244 ///
245 /// ```
246 /// #[macro_use]
247 /// extern crate statrs;
248 ///
249 /// use statrs::generate::InfiniteTriangle;
250 ///
251 /// # fn main() {
252 /// let x = InfiniteTriangle::new(4, 7, 1.0, -1.0,
253 /// 1).take(12).collect::<Vec<f64>>();
254 /// let expected: [f64; 12] = [-0.714, -1.0, -0.5, 0.0, 0.5, 1.0, 0.714,
255 /// 0.429, 0.143, -0.143, -0.429, -0.714];
256 /// for (&left, &right) in x.iter().zip(expected.iter()) {
257 /// assert_almost_eq!(left, right, 1e-3);
258 /// }
259 /// # }
260 /// ```
261 pub fn new(
262 raise_duration: i64,
263 fall_duration: i64,
264 high_value: f64,
265 low_value: f64,
266 delay: i64,
267 ) -> InfiniteTriangle {
268 let duration = (raise_duration + fall_duration) as f64;
269 let height = high_value - low_value;
270 InfiniteTriangle {
271 periodic: InfinitePeriodic::new(1.0, 1.0 / duration, duration, 0.0, delay),
272 raise_duration: raise_duration as f64,
273 raise: height / raise_duration as f64,
274 fall: height / fall_duration as f64,
275 high_value,
276 low_value,
277 }
278 }
279}
280
281impl Iterator for InfiniteTriangle {
282 type Item = f64;
283
284 fn next(&mut self) -> Option<f64> {
285 self.periodic.next().map(|x| {
286 if x < self.raise_duration {
287 self.low_value + x * self.raise
288 } else {
289 self.high_value - (x - self.raise_duration) * self.fall
290 }
291 })
292 }
293}
294
295/// Infinite iterator returning floats forming a sawtooth wave
296/// starting with the lowest sample
297pub struct InfiniteSawtooth {
298 periodic: InfinitePeriodic,
299 low_value: f64,
300}
301
302impl InfiniteSawtooth {
303 /// Constructs a new infinite sawtooth wave generator
304 ///
305 /// # Examples
306 ///
307 /// ```
308 /// use statrs::generate::InfiniteSawtooth;
309 ///
310 /// let x = InfiniteSawtooth::new(5, 1.0, -1.0,
311 /// 1).take(12).collect::<Vec<f64>>();
312 /// assert_eq!(x, [1.0, -1.0, -0.5, 0.0, 0.5, 1.0, -1.0, -0.5, 0.0, 0.5,
313 /// 1.0, -1.0]);
314 /// ```
315 pub fn new(period: i64, high_value: f64, low_value: f64, delay: i64) -> InfiniteSawtooth {
316 let height = high_value - low_value;
317 let period = period as f64;
318 InfiniteSawtooth {
319 periodic: InfinitePeriodic::new(
320 1.0,
321 1.0 / period,
322 height * period / (period - 1.0),
323 0.0,
324 delay,
325 ),
326 low_value: low_value as f64,
327 }
328 }
329}
330
331impl Iterator for InfiniteSawtooth {
332 type Item = f64;
333
334 fn next(&mut self) -> Option<f64> {
335 self.periodic.next().map(|x| x + self.low_value)
336 }
337}