1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
//! This crate implements several [adaptive filters] for digital signal processing.
//!
//! Unlike a regular filter, which is the same for every input signal, an adaptive
//! filter updates its inner state to the input signal(s) using a cost function,
//! and is thus able to adapt over time.
//!
//! An example application is [Adaptive Noise Cancelling (ANC)], where an adaptive
//! filter is used to remove noise from an audio signal by adapting to a reference
//! noise signal.
//!
//! [adaptive filters]: https://en.wikipedia.org/wiki/Adaptive_filter
//! [Adaptive Noise Cancelling (ANC)]: https://en.wikipedia.org/wiki/Adaptive_noise_cancelling
//!
//! # Overview
//!
//! Currently, the following filters are available:
//! - [`LmsFilter`], which uses a [least mean squares] algorithm.
//! - [`NlmsFilter`], which uses a [normalized least mean squares] algorithm.
//! - [`RlsFilter`], which uses a [recursive least squares] algorithm.
//!
//! [`LmsFilter`]: filters/struct.LmsFilter.html
//! [`NlmsFilter`]: filters/struct.NlmsFilter.html
//! [`RlsFilter`]: filters/struct.RlsFilter.html
//!
//! [least mean squares]: https://en.wikipedia.org/wiki/Least_mean_squares_filter
//! [normalized least mean squares]: https://en.wikipedia.org/wiki/Least_mean_squares_filter#Normalized_least_mean_squares_filter_(NLMS)
//! [recursive least squares]: https://en.wikipedia.org/wiki/Recursive_least_squares_filter
//!
//! It is also possible to create custom algorithms by implementing the [`Algorithm`]
//! trait. An object that implements [`Algorithm`] can be used with [`FilterBase`]
//! to create a working filter.
//!
//! [`FilterBase`]: filters/struct.FilterBase.html
//!
//! There are also Python bindings available for this crate.
//! See the [Python package] of the same name.
//!
//! [Python package]: https://pypi.org/project/adaptif
//!
//! # Usage
//!
//! Add `adaptif` as a project dependency with Cargo:
//!
//! ```sh
//! $ cargo add adaptif
//! ```
//!
//! To use a filter:
//!
//! ``` rust
//! # use adaptif::Error;
//! use adaptif::filters::{LmsFilter, LmsOptions, ProcessingMode};
//! use adaptif::types::{InputSignal, NoiseReference};
//!
//! // Initialize the filter
//! let mut lms = LmsFilter::new(
//! LmsOptions {
//! step_size: 0.1, // How fast the filter adapts
//! window_size: 16, // How many samples the filter processes at a time
//! },
//! ProcessingMode::Sample,
//! )?;
//!
//! // Sample inputs
//! let input_signal = InputSignal::new(vec![1.0, -2.5, 3.0])?;
//! let noise_ref = NoiseReference::new(vec![2.0, -1.2, -3.8])?;
//!
//! // Adapt the filter to the inputs.
//! let cleaned_signal = lms.adapt(&input_signal, &noise_ref)?;
//!
//! // ... or apply the previously adapted filter without updating it.
//! let cleaned_signal = lms.filter(&input_signal, &noise_ref)?;
//!
//! # Ok::<(), Error>(())
//! ```
//!
//! To implement a custom algorithm:
//!
//! ``` rust
//! # use adaptif::Error;
//! use adaptif::Algorithm;
//! use adaptif::filters::FilterBase;
//! use adaptif::types::NoiseWindowView;
//! use adaptif::types::{BlockSize, WindowSize};
//! use adaptif::types::{InputSignal, NoiseReference};
//!
//! // Create a struct to hold any required parameters or state
//! pub struct MyAlgorithm {
//! // Some parameter
//! pub alpha: f64,
//! // The algorithm's window size
//! pub window_size: WindowSize,
//! }
//! // Implement the Algorithm trait so the algorithm can be used with FilterBase
//! impl Algorithm<f64> for MyAlgorithm {
//! // This function is called every iteration during adaptation to update the weights
//! fn update_step(&mut self, weights: &mut [f64], error: f64, noise_window: NoiseWindowView<f64>) {
//! for (w, x) in weights.iter_mut().zip(noise_window.iter()) {
//! *w += self.alpha * error * x;
//! }
//! }
//!
//! // Certain algorithms need to know the filter's window size to initialize buffers, etc.
//! // To make sure `FilterBase` has the same window size as the algorithm object, we
//! // have to define this function so that it can be access when constructing `FilterBase`.
//! fn window_size(&self) -> WindowSize {
//! self.window_size
//! }
//! }
//!
//! // Define the algorithm parameters
//! let algorithm_cfg = MyAlgorithm {
//! alpha: 1.0,
//! window_size: WindowSize::new(16)?,
//! };
//!
//! // Instantiate the filter using FilterBase and our custom algorithm
//! let mut filter = FilterBase::new(algorithm_cfg, BlockSize::new(1)?);
//!
//! // Sample inputs
//! let input_signal = InputSignal::new(vec![1.0, -2.5, 3.0])?;
//! let noise_ref = NoiseReference::new(vec![2.0, -1.2, -3.8])?;
//!
//! // Adapt the filter using our algorithm's update rules
//! let output = filter.adapt(&input_signal, &noise_ref)?;
//!
//! # Ok::<(), Error>(())
//! ```
pub use Algorithm;
pub use ;