pictorus_blocks/core_blocks/
squarewave_block.rs1use crate::traits::Float;
2use pictorus_block_data::BlockData;
3use pictorus_traits::GeneratorBlock;
4
5pub struct Parameters<T: Float> {
6 pub amplitude: T,
7 pub on_duration: T,
8 pub off_duration: T,
9 pub phase: T,
10 pub bias: T,
11}
12
13impl<T: Float> Parameters<T> {
14 pub fn new(amplitude: T, on_duration: T, off_duration: T, phase: T, bias: T) -> Self {
15 Self {
16 amplitude,
17 on_duration,
18 off_duration,
19 phase,
20 bias,
21 }
22 }
23}
24
25pub struct SquarewaveBlock<T: Float> {
27 phantom_output_type: core::marker::PhantomData<T>,
28 pub data: BlockData,
29}
30
31impl<T: Float> Default for SquarewaveBlock<T>
32where
33 f64: From<T>,
34{
35 fn default() -> Self {
36 Self {
37 phantom_output_type: core::marker::PhantomData,
38 data: BlockData::from_scalar(T::zero().into()),
39 }
40 }
41}
42
43impl<T> GeneratorBlock for SquarewaveBlock<T>
44where
45 T: Float,
46 f64: From<T>,
47{
48 type Output = T;
49 type Parameters = Parameters<T>;
50
51 fn generate(
52 &mut self,
53 parameters: &Self::Parameters,
54 context: &dyn pictorus_traits::Context,
55 ) -> pictorus_traits::PassBy<Self::Output> {
56 let adjusted_time = Self::Output::from_duration(context.time()) - parameters.phase;
57 let pulse_time = parameters.on_duration + parameters.off_duration;
58 let mut time_since_last_pulse_start: Self::Output = adjusted_time % pulse_time;
59
60 if time_since_last_pulse_start < T::zero() {
61 time_since_last_pulse_start += pulse_time
63 };
64
65 let output = if time_since_last_pulse_start > parameters.on_duration {
66 parameters.bias
67 } else {
68 parameters.bias + parameters.amplitude
69 };
70 self.data = BlockData::from_scalar(f64::from(output));
71 output
72 }
73}
74
75#[cfg(test)]
76mod tests {
77 use crate::testing::StubRuntime;
78
79 use super::*;
80 use core::time::Duration;
81
82 #[test]
83 fn test_squarewave_block_f64() {
84 let amplitude = 2.0;
85 let on_duration = 1.0;
86 let off_duration = 2.0;
87 let bias = 0.25;
88 let phase = 0.5;
89
90 let p = Parameters::new(amplitude, on_duration, off_duration, phase, bias);
91
92 let mut block = SquarewaveBlock::<f64>::default();
93
94 let mut runtime = StubRuntime::default();
95
96 block.generate(&p, &runtime.context());
97 assert_eq!(block.generate(&p, &runtime.context()), bias);
98 assert_eq!(block.data.scalar(), bias);
99
100 runtime.set_time(Duration::from_millis(500));
101 assert_eq!(block.generate(&p, &runtime.context()), bias + amplitude);
102 assert_eq!(block.data.scalar(), bias + amplitude);
103
104 runtime.set_time(Duration::from_secs_f64(1.0));
105 assert_eq!(block.generate(&p, &runtime.context()), bias + amplitude);
106 assert_eq!(block.data.scalar(), bias + amplitude);
107
108 runtime.set_time(Duration::from_secs_f64(1.499));
109 assert_eq!(block.generate(&p, &runtime.context()), bias + amplitude);
110 assert_eq!(block.data.scalar(), bias + amplitude);
111
112 runtime.set_time(Duration::from_secs_f64(1.5));
113 assert_eq!(block.generate(&p, &runtime.context()), bias + amplitude);
114 assert_eq!(block.data.scalar(), bias + amplitude);
115
116 runtime.set_time(Duration::from_secs_f64(2.5));
118 assert_eq!(block.generate(&p, &runtime.context()), bias);
119 assert_eq!(block.data.scalar(), bias);
120
121 runtime.set_time(Duration::from_secs_f64(3.499));
122 assert_eq!(block.generate(&p, &runtime.context()), bias);
123 assert_eq!(block.data.scalar(), bias);
124
125 runtime.set_time(Duration::from_secs_f64(3.5));
127 assert_eq!(block.generate(&p, &runtime.context()), bias + amplitude);
128 assert_eq!(block.data.scalar(), bias + amplitude);
129 }
130
131 #[test]
132 fn test_squarewave_block_f32() {
133 let amplitude = 2.0;
134 let on_duration = 1.0;
135 let off_duration = 2.0;
136 let bias = 0.5;
137 let phase = 0.5;
138
139 let p = Parameters::new(amplitude, on_duration, off_duration, phase, bias);
140
141 let mut block = SquarewaveBlock::<f32>::default();
142
143 let mut runtime = StubRuntime::default();
144
145 block.generate(&p, &runtime.context());
146 assert_eq!(block.generate(&p, &runtime.context()), bias);
147 assert_eq!(block.data.scalar() as f32, bias);
148
149 runtime.set_time(Duration::from_millis(500));
150 assert_eq!(block.generate(&p, &runtime.context()), bias + amplitude);
151 assert_eq!(block.data.scalar() as f32, bias + amplitude);
152
153 runtime.set_time(Duration::from_secs_f32(1.0));
154 assert_eq!(block.generate(&p, &runtime.context()), bias + amplitude);
155 assert_eq!(block.data.scalar() as f32, bias + amplitude);
156
157 runtime.set_time(Duration::from_secs_f32(1.499));
158 assert_eq!(block.generate(&p, &runtime.context()), bias + amplitude);
159 assert_eq!(block.data.scalar() as f32, bias + amplitude);
160
161 runtime.set_time(Duration::from_secs_f32(1.5));
162 assert_eq!(block.generate(&p, &runtime.context()), bias + amplitude);
163 assert_eq!(block.data.scalar() as f32, bias + amplitude);
164
165 runtime.set_time(Duration::from_secs_f32(2.5));
167 assert_eq!(block.generate(&p, &runtime.context()), bias);
168 assert_eq!(block.data.scalar() as f32, bias);
169
170 runtime.set_time(Duration::from_secs_f32(3.499));
171 assert_eq!(block.generate(&p, &runtime.context()), bias);
172 assert_eq!(block.data.scalar() as f32, bias);
173
174 runtime.set_time(Duration::from_secs_f32(3.5));
176 assert_eq!(block.generate(&p, &runtime.context()), bias + amplitude);
177 assert_eq!(block.data.scalar() as f32, bias + amplitude);
178 }
179
180 #[test]
181 fn test_squarewave_phase() {
182 let amplitude = 1.0;
184 let on_duration = 1.0;
185 let off_duration = 2.0;
186 let bias = 0.0;
187 let phase = 1.5;
188
189 let mut p = Parameters::new(amplitude, on_duration, off_duration, phase, bias);
190
191 let mut block = SquarewaveBlock::<f32>::default();
192
193 let runtime = StubRuntime::default();
194
195 p.phase = 1.5;
196 block.generate(&p, &runtime.context());
197 assert_eq!(block.generate(&p, &runtime.context()), bias);
198
199 p.phase = 0.0;
200 assert_eq!(block.generate(&p, &runtime.context()), bias + amplitude);
201
202 p.phase = 0.5;
203 assert_eq!(block.generate(&p, &runtime.context()), bias);
204
205 p.phase = 2.5;
206 assert_eq!(block.generate(&p, &runtime.context()), bias + amplitude);
207
208 }
226
227 #[test]
228 fn test_squarewave_bias() {
229 let amplitude = 1.0;
230 let on_duration = 1.0;
231 let off_duration = 2.0;
232 let bias = 1.0;
233 let phase = 0.0;
234
235 let p = Parameters::new(amplitude, on_duration, off_duration, phase, bias);
236 let mut block = SquarewaveBlock::<f32>::default();
237
238 let mut runtime = StubRuntime::default();
239
240 let output = block.generate(&p, &runtime.context());
241 assert_eq!(output, bias + amplitude);
242
243 runtime.set_time(Duration::from_secs_f32(1.5));
244 let output = block.generate(&p, &runtime.context());
245 assert_eq!(output, bias);
246 }
247}