Skip to content

Commit 190a6b7

Browse files
committed
Add impulse_s
1 parent 2d5b8be commit 190a6b7

File tree

17 files changed

+1899
-995
lines changed

17 files changed

+1899
-995
lines changed
File renamed without changes.

plots/y_t_impulse_s.png

121 KB
Loading

src/analysis/imps.rs

Whitespace-only changes.

src/analysis/impulse_s.rs

Lines changed: 241 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,241 @@
1+
use ndarray::Array2;
2+
use num::{complex::ComplexFloat, NumCast, One};
3+
use option_trait::{Maybe, StaticMaybe};
4+
5+
use crate::{quantities::{ContainerOrSingle, List, ListOrSingle, Lists, Matrix, MatrixOrSingle, MaybeList, MaybeLists, MaybeOwnedList, OwnedList, OwnedListOrSingle}, systems::{Sos, Ss, SsAMatrix, SsBMatrix, SsCMatrix, SsDMatrix, Tf, Zpk}, transforms::system::ToSs, util::TwoSidedRange, System};
6+
7+
use super::SimS;
8+
9+
pub trait ImpulseS<L>: System
10+
where
11+
L: List<<Self::Set as ComplexFloat>::Real>,
12+
<L::Length as StaticMaybe<usize>>::Opposite: Sized
13+
{
14+
type OutputI: Lists<Self::Set> + ListOrSingle<L::Mapped<Self::Set>>;
15+
type Output: MatrixOrSingle<L::Mapped<Self::Set>>;
16+
17+
fn impulse_s<T, W>(self, t: T, numtaps: <L::Length as StaticMaybe<usize>>::Opposite, w: W)
18+
-> (L, Self::Output)
19+
where
20+
T: TwoSidedRange<<Self::Set as ComplexFloat>::Real> + Clone,
21+
W: Maybe<Vec<Self::Set>>;
22+
}
23+
24+
impl<T, A, B, C, D, L, YY> ImpulseS<L> for Ss<T, A, B, C, D>
25+
where
26+
T: ComplexFloat,
27+
A: SsAMatrix<T, B, C, D>,
28+
B: SsBMatrix<T, A, C, D>,
29+
C: SsCMatrix<T, A, B, D>,
30+
D: for<'a> SsDMatrix<T, A, B, C, RowView<'a>: List<T>>,
31+
L: OwnedList<T::Real, Mapped<T> = YY>,
32+
<L::Length as StaticMaybe<usize>>::Opposite: Sized + Clone,
33+
D::RowsMapped<YY>: Lists<T>,
34+
YY: OwnedList<T, Length = L::Length> + Clone,
35+
L::Mapped<Vec<T>>: OwnedList<Vec<T>, Length: StaticMaybe<usize, Opposite: Sized>>,
36+
for<'a> Ss<T, A::View<'a>, B::View<'a>, C::View<'a>, D::View<'a>>: System<Set = T> + SimS<T, Array2<T>, Output = D::RowsMapped<Vec<T>>>,
37+
for<'a> A::View<'a>: SsAMatrix<T, B::View<'a>, C::View<'a>, D::View<'a>>,
38+
for<'a> B::View<'a>: SsBMatrix<T, A::View<'a>, C::View<'a>, D::View<'a>>,
39+
for<'a> C::View<'a>: SsCMatrix<T, A::View<'a>, B::View<'a>, D::View<'a>>,
40+
for<'a> D::View<'a>: SsDMatrix<T, A::View<'a>, B::View<'a>, C::View<'a>>,
41+
D::RowsMapped<Vec<T>>: ListOrSingle<Vec<T>, Mapped<YY>: Into<D::RowsMapped<YY>>>,
42+
<D::Transpose as MaybeLists<T>>::RowsMapped<D::RowsMapped<YY>>: OwnedListOrSingle<D::RowsMapped<YY>, Length: StaticMaybe<usize, Opposite: Sized>> + Lists<YY>,
43+
<<D::Transpose as MaybeLists<T>>::RowsMapped<D::RowsMapped<YY>> as Lists<YY>>::CoercedMatrix: Matrix<YY>
44+
{
45+
type OutputI = D::RowsMapped<YY>;
46+
type Output = <<D::Transpose as MaybeLists<T>>::RowsMapped<Self::OutputI> as Lists<YY>>::CoercedMatrix;
47+
48+
fn impulse_s<TT, W>(self, t: TT, numtaps: <L::Length as StaticMaybe<usize>>::Opposite, w: W)
49+
-> (L, Self::Output)
50+
where
51+
TT: TwoSidedRange<T::Real> + Clone,
52+
W: Maybe<Vec<T>>
53+
{
54+
let w = w.into_option();
55+
56+
let d: Array2<T> = self.d.to_array2();
57+
58+
let n = numtaps.into_option()
59+
.unwrap_or(L::LENGTH);
60+
let nuf = <T::Real as NumCast>::from(n).unwrap();
61+
let numaybem1 = if t.is_end_inclusive()
62+
{
63+
nuf - T::Real::one()
64+
}
65+
else
66+
{
67+
nuf
68+
};
69+
70+
let dt = (*t.end() - *t.start())/numaybem1;
71+
72+
let tt = OwnedListOrSingle::from_len_fn(StaticMaybe::maybe_from_fn(|| n), |i| {
73+
let i = <T::Real as NumCast>::from(i).unwrap();
74+
*t.start() + i*dt
75+
});
76+
77+
let dn = d.dim().1;
78+
let y = <D::Transpose as MaybeLists<T>>::RowsMapped::<Self::OutputI>::from_len_fn(StaticMaybe::maybe_from_fn(|| dn), |i| {
79+
let d = d.column(i)
80+
.to_vec();
81+
82+
let w = match w.clone()
83+
{
84+
Some(w) => {
85+
let wn = w.len();
86+
w.into_iter()
87+
.chain(core::iter::repeat(T::zero())
88+
.take(d.len().saturating_sub(wn))
89+
).zip(d)
90+
.map(|(w, b)| w + b)
91+
.collect()
92+
},
93+
None => d
94+
};
95+
96+
let (_, y, _) = self.as_view()
97+
.sim_s(
98+
t.clone(),
99+
Array2::from_elem((dn, n), T::zero()),
100+
w,
101+
false
102+
);
103+
104+
let y: Self::OutputI = y.map_into_owned(|y| {
105+
let ny = y.len();
106+
let mut y = y.into_iter();
107+
OwnedListOrSingle::from_len_fn(StaticMaybe::maybe_from_fn(|| ny), |_| y.next().unwrap())
108+
}).into();
109+
y
110+
})
111+
.coerce_into_matrix(|| panic!("Matrix is not correctly shaped"));
112+
113+
(tt, y)
114+
}
115+
}
116+
117+
impl<T, B, A, L> ImpulseS<L> for Tf<T, B, A>
118+
where
119+
T: ComplexFloat,
120+
B: MaybeLists<T>,
121+
A: MaybeList<T>,
122+
L: List<T::Real>,
123+
<L::Length as StaticMaybe<usize>>::Opposite: Sized,
124+
B::RowsMapped<L::Mapped<T>>: Lists<T> + OwnedListOrSingle<L::Mapped<T>, Length: StaticMaybe<usize, Opposite: Sized>>,
125+
Self: System<Set = T> + ToSs<T, Array2<T>, Array2<T>, Array2<T>, Array2<T>>,
126+
Array2<T>: SsAMatrix<T, Array2<T>, Array2<T>, Array2<T>> + SsBMatrix<T, Array2<T>, Array2<T>, Array2<T>> + SsCMatrix<T, Array2<T>, Array2<T>, Array2<T>> + SsDMatrix<T, Array2<T>, Array2<T>, Array2<T>>,
127+
Ss<T, Array2<T>, Array2<T>, Array2<T>, Array2<T>>: ImpulseS<L, Output = Array2<L::Mapped<T>>> + System<Set = T>
128+
{
129+
type OutputI = B::RowsMapped<L::Mapped<T>>;
130+
type Output = B::RowsMapped<L::Mapped<T>>;
131+
132+
fn impulse_s<TT, W>(self, t: TT, numtaps: <L::Length as StaticMaybe<usize>>::Opposite, w: W)
133+
-> (L, Self::Output)
134+
where
135+
TT: TwoSidedRange<T::Real> + Clone,
136+
W: Maybe<Vec<T>>
137+
{
138+
let (t, y) = self.to_ss()
139+
.impulse_s(t, numtaps, w);
140+
141+
let q = y.len();
142+
let mut y = y.into_iter();
143+
144+
(
145+
t,
146+
OwnedListOrSingle::from_len_fn(StaticMaybe::maybe_from_fn(|| q), |_| y.next().unwrap())
147+
)
148+
}
149+
}
150+
151+
impl<T, Z, P, K, L> ImpulseS<L> for Zpk<T, Z, P, K>
152+
where
153+
T: ComplexFloat,
154+
Z: MaybeList<T>,
155+
P: MaybeList<T>,
156+
K: ComplexFloat<Real = T::Real>,
157+
L: List<T::Real>,
158+
<L::Length as StaticMaybe<usize>>::Opposite: Sized,
159+
L::Mapped<K>: List<K> + ListOrSingle<L::Mapped<K>>,
160+
Self: System<Set = K> + ToSs<K, Array2<K>, Array2<K>, Array2<K>, Array2<K>>,
161+
Array2<K>: SsAMatrix<K, Array2<K>, Array2<K>, Array2<K>> + SsBMatrix<K, Array2<K>, Array2<K>, Array2<K>> + SsCMatrix<K, Array2<K>, Array2<K>, Array2<K>> + SsDMatrix<K, Array2<K>, Array2<K>, Array2<K>>,
162+
Ss<K, Array2<K>, Array2<K>, Array2<K>, Array2<K>>: System<Set = K> + ImpulseS<L, Output = Array2<L::Mapped<K>>>
163+
{
164+
type OutputI = L::Mapped<K>;
165+
type Output = L::Mapped<K>;
166+
167+
fn impulse_s<TT, W>(self, t: TT, numtaps: <L::Length as StaticMaybe<usize>>::Opposite, w: W)
168+
-> (L, Self::Output)
169+
where
170+
TT: TwoSidedRange<T::Real> + Clone,
171+
W: Maybe<Vec<K>>
172+
{
173+
let (t, y) = self.to_ss()
174+
.impulse_s(t, numtaps, w);
175+
176+
(
177+
t,
178+
y.into_iter()
179+
.next()
180+
.unwrap()
181+
)
182+
}
183+
}
184+
185+
impl<T, B, A, S, L> ImpulseS<L> for Sos<T, B, A, S>
186+
where
187+
T: ComplexFloat,
188+
B: Maybe<[T; 3]> + MaybeOwnedList<T>,
189+
A: Maybe<[T; 3]> + MaybeOwnedList<T>,
190+
S: MaybeList<Tf<T, B, A>>,
191+
L: List<T::Real>,
192+
<L::Length as StaticMaybe<usize>>::Opposite: Sized,
193+
L::Mapped<T>: List<T> + ListOrSingle<L::Mapped<T>>,
194+
Self: System<Set = T> + ToSs<T, Array2<T>, Array2<T>, Array2<T>, Array2<T>>,
195+
Array2<T>: SsAMatrix<T, Array2<T>, Array2<T>, Array2<T>> + SsBMatrix<T, Array2<T>, Array2<T>, Array2<T>> + SsCMatrix<T, Array2<T>, Array2<T>, Array2<T>> + SsDMatrix<T, Array2<T>, Array2<T>, Array2<T>>,
196+
Ss<T, Array2<T>, Array2<T>, Array2<T>, Array2<T>>: System<Set = T> + ImpulseS<L, Output = Array2<L::Mapped<T>>>
197+
{
198+
type OutputI = L::Mapped<T>;
199+
type Output = L::Mapped<T>;
200+
201+
fn impulse_s<TT, W>(self, t: TT, numtaps: <L::Length as StaticMaybe<usize>>::Opposite, w: W)
202+
-> (L, Self::Output)
203+
where
204+
TT: TwoSidedRange<T::Real> + Clone,
205+
W: Maybe<Vec<T>>
206+
{
207+
let (t, y) = self.to_ss()
208+
.impulse_s(t, numtaps, w);
209+
210+
(
211+
t,
212+
y.into_iter()
213+
.next()
214+
.unwrap()
215+
)
216+
}
217+
}
218+
219+
#[cfg(test)]
220+
mod test
221+
{
222+
use core::f64::consts::TAU;
223+
224+
use array_math::ArrayOps;
225+
226+
use crate::{analysis::ImpulseS, gen::filter::{BesselF, FilterGenPlane, FilterGenType}, plot, systems::Tf};
227+
228+
#[test]
229+
fn test()
230+
{
231+
let h = Tf::besself(5, [TAU*12.0], FilterGenType::LowPass, FilterGenPlane::S)
232+
.unwrap();
233+
234+
const T: f64 = 1.25;
235+
const N: usize = 200;
236+
let (t, y): ([_; N], _) = h.impulse_s(0.0..T, (), ());
237+
238+
plot::plot_curves("y(t)", "plots/y_t_impulse_s.png", [&t.zip(y)])
239+
.unwrap();
240+
}
241+
}

src/analysis/mod.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ moddef::moddef!(
1212
freqz,
1313
fwhm,
1414
grpdelay,
15+
impulse_s,
1516
impz,
1617
isallpass,
1718
islinphase,
@@ -36,7 +37,7 @@ moddef::moddef!(
3637
real_specgram,
3738
rms,
3839
rssq,
39-
sims,
40+
sim_s,
4041
specgram,
4142
statelevels,
4243
tfestimate,

0 commit comments

Comments
 (0)