Skip to content

Commit 7b962a4

Browse files
authored
Add Exponential Moving Average Filter (TheAlgorithms#6075)
1 parent a676ebc commit 7b962a4

File tree

2 files changed

+89
-0
lines changed

2 files changed

+89
-0
lines changed
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
package com.thealgorithms.audiofilters;
2+
3+
/**
4+
* Exponential Moving Average (EMA) Filter for smoothing audio signals.
5+
*
6+
* <p>This filter applies an exponential moving average to a sequence of audio
7+
* signal values, making it useful for smoothing out rapid fluctuations.
8+
* The smoothing factor (alpha) controls the degree of smoothing.
9+
*
10+
* <p>Based on the definition from
11+
* <a href="https://en.wikipedia.org/wiki/Moving_average">Wikipedia link</a>.
12+
*/
13+
public class EMAFilter {
14+
private final double alpha;
15+
private double emaValue;
16+
/**
17+
* Constructs an EMA filter with a given smoothing factor.
18+
*
19+
* @param alpha Smoothing factor (0 < alpha <= 1)
20+
* @throws IllegalArgumentException if alpha is not in (0, 1]
21+
*/
22+
public EMAFilter(double alpha) {
23+
if (alpha <= 0 || alpha > 1) {
24+
throw new IllegalArgumentException("Alpha must be between 0 and 1.");
25+
}
26+
this.alpha = alpha;
27+
this.emaValue = 0.0;
28+
}
29+
/**
30+
* Applies the EMA filter to an audio signal array.
31+
*
32+
* @param audioSignal Array of audio samples to process
33+
* @return Array of processed (smoothed) samples
34+
*/
35+
public double[] apply(double[] audioSignal) {
36+
if (audioSignal.length == 0) {
37+
return new double[0];
38+
}
39+
double[] emaSignal = new double[audioSignal.length];
40+
emaValue = audioSignal[0];
41+
emaSignal[0] = emaValue;
42+
for (int i = 1; i < audioSignal.length; i++) {
43+
emaValue = alpha * audioSignal[i] + (1 - alpha) * emaValue;
44+
emaSignal[i] = emaValue;
45+
}
46+
return emaSignal;
47+
}
48+
}
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
package com.thealgorithms.audiofilters;
2+
3+
import static org.junit.jupiter.api.Assertions.assertArrayEquals;
4+
5+
import org.junit.jupiter.api.Test;
6+
7+
public class EMAFilterTest {
8+
9+
@Test
10+
public void testApplyBasicSignal() {
11+
EMAFilter emaFilter = new EMAFilter(0.2);
12+
double[] audioSignal = {0.1, 0.5, 0.8, 0.6, 0.3, 0.9, 0.4};
13+
double[] expectedOutput = {0.1, 0.18, 0.304, 0.3632, 0.35056, 0.460448, 0.4483584};
14+
double[] result = emaFilter.apply(audioSignal);
15+
assertArrayEquals(expectedOutput, result, 1e-5);
16+
}
17+
18+
@Test
19+
public void testApplyEmptySignal() {
20+
EMAFilter emaFilter = new EMAFilter(0.2);
21+
double[] audioSignal = {};
22+
double[] expectedOutput = {};
23+
double[] result = emaFilter.apply(audioSignal);
24+
assertArrayEquals(expectedOutput, result);
25+
}
26+
27+
@Test
28+
public void testAlphaBounds() {
29+
EMAFilter emaFilterMin = new EMAFilter(0.01);
30+
EMAFilter emaFilterMax = new EMAFilter(1.0);
31+
double[] audioSignal = {1.0, 1.0, 1.0, 1.0};
32+
33+
// Minimal smoothing (alpha close to 0)
34+
double[] resultMin = emaFilterMin.apply(audioSignal);
35+
assertArrayEquals(audioSignal, resultMin, 1e-5);
36+
37+
// Maximum smoothing (alpha = 1, output should match input)
38+
double[] resultMax = emaFilterMax.apply(audioSignal);
39+
assertArrayEquals(audioSignal, resultMax, 1e-5);
40+
}
41+
}

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy