Skip to content

Commit ce1c4a7

Browse files
committed
sameold: stop flipping coefficients around
Previously, `FilterCoeff` were stored in reverse order, with feedforward lag 0 stored *last*. This was convenient when `Window` coerced to slice. Now that we iterate over `Window` in reverse order, reversing the filter taps does not serve us. It is also confusing: the taps are in "normal" order in `FilterCoeff::from_slice()`, but later reads via `as_slice()` show them reversed. Ick. Put filter taps in their proper order.
1 parent edb7ecf commit ce1c4a7

2 files changed

Lines changed: 13 additions & 30 deletions

File tree

crates/sameold/src/receiver/equalize.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -358,7 +358,7 @@ where
358358
{
359359
let window = window.into_iter();
360360
let gain = nlms_gain(relaxation, regularization, window.clone());
361-
for (coeff, data) in filter.iter_mut().zip(window) {
361+
for (coeff, data) in filter.iter_mut().zip(window.rev()) {
362362
*coeff += gain * error * data;
363363
}
364364
}

crates/sameold/src/receiver/filter.rs

Lines changed: 12 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -85,18 +85,12 @@ where
8585
/// Creates FIR filter coefficients with the specified impulse
8686
/// response `h`. The coefficients `h` use the same representation
8787
/// as GNU Octave's `filter()` function.
88-
///
89-
/// Internally, the coefficients are stored reversed. This improves
90-
/// performance against most types of queues for the input signal.
9188
pub fn from_slice<S>(h: S) -> Self
9289
where
9390
S: AsRef<[T]>,
9491
{
9592
let inp = h.as_ref();
96-
FilterCoeff(DVector::from_iterator(
97-
inp.len(),
98-
inp.iter().rev().map(|d| *d),
99-
))
93+
FilterCoeff(DVector::from_iterator(inp.len(), inp.iter().copied()))
10094
}
10195

10296
/// Create an identity filter
@@ -107,7 +101,7 @@ where
107101
len,
108102
std::iter::repeat(T::zero()).take(len),
109103
));
110-
out.0[len - 1] = T::one();
104+
out.0[0] = T::one();
111105
out
112106
}
113107

@@ -143,42 +137,31 @@ where
143137
/// The filter coefficients are reset to a "no-op" identity
144138
/// filter.
145139
pub fn identity(&mut self) {
146-
let len = self.0.len();
147140
for coeff in self.0.iter_mut() {
148141
*coeff = T::zero();
149142
}
150-
self.0[len - 1] = T::one();
143+
self.0[0] = T::one();
151144
}
152145

153146
/// Return filter coefficients as slice
154-
///
155-
/// The filter coefficients are in *reverse* order
156-
/// from their Octave representation.
157147
#[inline]
158148
pub fn as_slice(&self) -> &[T] {
159149
self.0.as_slice()
160150
}
161151

162152
/// Return filter coefficients as mutable slice
163-
///
164-
/// The filter coefficients are in *reverse* order
165-
/// from their Octave representation.
166153
#[inline]
167154
pub fn as_mut_slice(&mut self) -> &mut [T] {
168155
self.0.as_mut_slice()
169156
}
170157

171158
/// Obtain filter coefficients
172-
///
173-
/// The coefficients are output in reverse order.
174159
#[inline]
175160
pub fn inner(&self) -> &DVector<T> {
176161
&self.0
177162
}
178163

179164
/// Obtain filter coefficients (mutable)
180-
///
181-
/// The coefficients are output in reverse order.
182165
#[inline]
183166
pub fn inner_mut(&mut self) -> &mut DVector<T> {
184167
&mut self.0
@@ -372,11 +355,11 @@ where
372355
// `history` contains the sample history. The most recent sample
373356
// is stored in `history[N-1]`, and the least recent sample in the
374357
// history is stored in `history[0]`. The filter coefficients are
375-
// stored *reversed* in `rev_coeff`, with `rev_coeff[N-1]` being
376-
// the zeroth filter coefficient.
358+
// stored in `coeff`, with `coeff[0]` being the zeroth filter
359+
// coefficient.
377360
//
378361
// The two inputs need not be the same length. If `history` is shorter
379-
// than `rev_coeff`, then the sample history is assumed to be zero
362+
// than `coeff`, then the sample history is assumed to be zero
380363
// outside of its range.
381364
//
382365
// To perform FIR filtering, new samples are shifted onto the end of
@@ -385,7 +368,7 @@ where
385368
//
386369
// The output value is returned. Any compatible arithmetic types may
387370
// be used, including complex numbers.
388-
fn multiply_accumulate<W, In, Coeff, Out>(history: W, rev_coeff: &[Coeff]) -> Out
371+
fn multiply_accumulate<W, In, Coeff, Out>(history: W, coeff: &[Coeff]) -> Out
389372
where
390373
W: IntoIterator<Item = In>,
391374
W::IntoIter: DoubleEndedIterator,
@@ -395,7 +378,7 @@ where
395378
{
396379
let history = history.into_iter();
397380
let mut out = Out::zero();
398-
for (hi, co) in history.rev().zip(rev_coeff.iter().rev()) {
381+
for (hi, co) in history.rev().zip(coeff.iter()) {
399382
out += hi * *co;
400383
}
401384
out
@@ -418,11 +401,11 @@ mod tests {
418401
// simple multiplies; we clip to the end
419402
let out = multiply_accumulate(&[20.0f32, 1.0f32], &[1.0f32]);
420403
assert_eq!(1.0f32, out);
421-
let out = multiply_accumulate(&[1.0f32], &[20.0f32, 1.0f32]);
404+
let out = multiply_accumulate(&[1.0f32], &[1.0f32, 20.0f32]);
422405
assert_eq!(1.0f32, out);
423406

424407
// more complicated multiply
425-
let out = multiply_accumulate(&[20.0f32, 20.0f32], &[-1.0f32, 1.0f32]);
408+
let out = multiply_accumulate(&[20.0f32, 20.0f32], &[1.0f32, -1.0f32]);
426409
assert_approx_eq!(0.0f32, out);
427410
}
428411

@@ -442,13 +425,13 @@ mod tests {
442425

443426
#[test]
444427
fn test_filter_identity() {
445-
const EXPECT: &[f32] = &[0.0f32, 0.0f32, 0.0f32, 1.0f32];
428+
const EXPECT: &[f32] = &[1.0f32, 0.0f32, 0.0f32, 0.0f32];
446429

447430
let mut filter = FilterCoeff::<f32>::from_identity(4);
448431
assert_eq!(EXPECT, filter.as_ref());
449432
assert_eq!(10.0f32, filter.filter(&[10.0f32]));
450433

451-
filter[2] = 5.0f32;
434+
filter[3] = 5.0f32;
452435
filter.identity();
453436
assert_eq!(EXPECT, filter.as_ref());
454437
}

0 commit comments

Comments
 (0)