linear_predictive_coding/
lib.rs1use ndarray::prelude::*;
10pub fn correlate(a: ArrayView1<f64>) -> Array1<f64> {
19 a.iter()
20 .enumerate()
21 .map(|(n, _)| {
22 a.slice(s![n..])
23 .iter()
24 .zip(a.iter())
25 .map(|(x, y)| x * y)
26 .sum::<f64>()
27 })
28 .collect()
29}
30
31pub fn calc_lpc_by_levinson_durbin(a: ArrayView1<f64>, depth: usize) -> Option<(Array1<f64>, f64)> {
59 if a.len() < depth {
60 return None;
61 }
62
63 let r = correlate(a);
64 let r = r.slice(s![..=depth]);
66 fn calc_lpc_by_high_speed_inner(
69 a: ArrayView1<f64>,
70 depth: usize,
71 r: ArrayView1<f64>,
72 ) -> (Array1<f64>, f64) {
73 if depth == 1 {
74 let a = Array1::from_iter(vec![1.0, -r[1] as f64 / r[0]]);
75 let e = a.dot(&r.slice(s![..2]));
76
77 (a, e)
80 } else {
81 let (aa, ee) = calc_lpc_by_high_speed_inner(a, depth - 1, r);
82
83 let kk = -aa.dot(&r.slice(s![1..=depth; -1])) / ee;
84
85 let large_u = ndarray::concatenate![Axis(0), aa.view(), Array1::from_elem(1, 0.0)];
86
87 let large_v = large_u.slice(s![..; -1]);
88
89 let a = large_u.clone() + large_v.mapv(|x| x * kk);
90
91 let e = ee * (1.0 - kk * kk);
92
93 (a, e)
94 }
95 }
96
97 let (a, e) = calc_lpc_by_high_speed_inner(a, depth, r.view());
98
99 Some((a.slice_move(s![1..]), e))
100}
101
102pub fn calc_lpc_by_burg(x: ArrayView1<f64>, depth: usize) -> Option<Array1<f64>> {
104 if x.len() < depth {
105 return None;
106 }
107
108 let mut a = Array1::<f64>::zeros(depth + 1);
109
110 let mut k = Array1::<f64>::zeros(depth);
111
112 a[0] = 1.0;
113
114 let mut f = x.to_owned();
115
116 let mut b = x.to_owned();
117
118 let n = x.len();
119
120 for p in 0..depth {
121 let kf = f.slice(s![p + 1..]);
122 let kb = b.slice(s![..n - p - 1]);
123 let d = kf.iter().map(|x| x * x).sum::<f64>() + kb.iter().map(|x| x * x).sum::<f64>();
125 k[p] = -2.0 * kf.iter().zip(kb.iter()).map(|(x, y)| x * y).sum::<f64>() / d;
126 let u = a.slice(s![..=p + 1]);
127 let v = u.slice(s![..; -1]);
128
129 let added = &u + &v.mapv(|x| x * k[p]);
133 a.slice_mut(s![..=p + 1]).assign(&added.view());
134 let fu = b.slice(s![..n - p - 1]).mapv(|x| x * k[p]);
135 let bu = f.slice(s![p + 1..]).mapv(|x| x * k[p]);
136 f.slice_mut(s![p + 1..])
137 .iter_mut()
138 .zip(fu.iter())
139 .for_each(|(x, fu)| *x += *fu);
140 b.slice_mut(s![..n - p - 1])
141 .iter_mut()
142 .zip(bu.iter())
143 .for_each(|(x, bu)| *x += bu);
144 }
145
146 Some(a.slice_move(s![1..]))
147}
148
149#[cfg(test)]
150mod tests {
151 use super::*;
152
153 #[test]
154 fn test_correlate() {
155 let a = Array1::from(vec![2., 3., -1., -2., 1., 4., 1.]);
156 let expected = Array1::from(vec![36.0, 11.0, -16.0, -7.0, 13.0, 11.0, 2.0]);
157 assert_eq!(correlate(a.view()), expected);
158 }
159
160 #[test]
173 fn test_calc_lpc_by_high_speed() {
174 let a = Array1::from(vec![2., 3., -1., -2., 1., 4., 1.]);
175 let depth = 3;
176 let expected = Array1::from(vec![
177 -0.6919053749597684,
178 0.7615062761506278,
179 -0.3457515288059223,
180 ]);
181 assert_eq!(
182 calc_lpc_by_levinson_durbin(a.view(), depth).unwrap().0,
183 expected
184 );
185 }
186
187 #[test]
188 fn test_calc_lpc_by_burg() {
189 let a = Array1::from(vec![2., 3., -1., -2., 1., 4., 1.]);
190 let depth = 3;
191 let expected = Array1::from(vec![
192 -1.0650404360323664,
193 1.157238171254371,
194 -0.5771692748969812,
195 ]);
196 assert_eq!(calc_lpc_by_burg(a.view(), depth), Some(expected));
197 }
198}