feature/high-low-pass-filter (#2)
Co-authored-by: Bastian Bührig <bastian.buehrig@2bconsult.eu> Reviewed-on: #2
This commit was merged in pull request #2.
This commit is contained in:
@@ -341,3 +341,115 @@ func FadeOutLinear(data []float64, fadeSamples int) []float64 {
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
// ApplyLowpassButterworth applies a 2nd-order Butterworth low-pass filter to the data.
|
||||
// cutoffHz: cutoff frequency in Hz, sampleRate: sample rate in Hz.
|
||||
func ApplyLowpassButterworth(data []float64, sampleRate int, cutoffHz float64) []float64 {
|
||||
if cutoffHz <= 0 || cutoffHz >= float64(sampleRate)/2 {
|
||||
return data
|
||||
}
|
||||
// Biquad coefficients
|
||||
w0 := 2 * math.Pi * cutoffHz / float64(sampleRate)
|
||||
cosw0 := math.Cos(w0)
|
||||
sinw0 := math.Sin(w0)
|
||||
Q := 1.0 / math.Sqrt(2) // Butterworth Q
|
||||
alpha := sinw0 / (2 * Q)
|
||||
|
||||
b0 := (1 - cosw0) / 2
|
||||
b1 := 1 - cosw0
|
||||
b2 := (1 - cosw0) / 2
|
||||
a0 := 1 + alpha
|
||||
a1 := -2 * cosw0
|
||||
a2 := 1 - alpha
|
||||
|
||||
// Normalize
|
||||
b0 /= a0
|
||||
b1 /= a0
|
||||
b2 /= a0
|
||||
a1 /= a0
|
||||
a2 /= a0
|
||||
|
||||
// Apply filter (Direct Form I)
|
||||
out := make([]float64, len(data))
|
||||
var x1, x2, y1, y2 float64
|
||||
for i := 0; i < len(data); i++ {
|
||||
x0 := data[i]
|
||||
y0 := b0*x0 + b1*x1 + b2*x2 - a1*y1 - a2*y2
|
||||
out[i] = y0
|
||||
x2 = x1
|
||||
x1 = x0
|
||||
y2 = y1
|
||||
y1 = y0
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
// ApplyHighpassButterworth applies a 2nd-order Butterworth high-pass filter to the data.
|
||||
// cutoffHz: cutoff frequency in Hz, sampleRate: sample rate in Hz.
|
||||
func ApplyHighpassButterworth(data []float64, sampleRate int, cutoffHz float64) []float64 {
|
||||
if cutoffHz <= 0 || cutoffHz >= float64(sampleRate)/2 {
|
||||
return data
|
||||
}
|
||||
// Biquad coefficients
|
||||
w0 := 2 * math.Pi * cutoffHz / float64(sampleRate)
|
||||
cosw0 := math.Cos(w0)
|
||||
sinw0 := math.Sin(w0)
|
||||
Q := 1.0 / math.Sqrt(2) // Butterworth Q
|
||||
alpha := sinw0 / (2 * Q)
|
||||
|
||||
b0 := (1 + cosw0) / 2
|
||||
b1 := -(1 + cosw0)
|
||||
b2 := (1 + cosw0) / 2
|
||||
a0 := 1 + alpha
|
||||
a1 := -2 * cosw0
|
||||
a2 := 1 - alpha
|
||||
|
||||
// Normalize
|
||||
b0 /= a0
|
||||
b1 /= a0
|
||||
b2 /= a0
|
||||
a1 /= a0
|
||||
a2 /= a0
|
||||
|
||||
// Apply filter (Direct Form I)
|
||||
out := make([]float64, len(data))
|
||||
var x1, x2, y1, y2 float64
|
||||
for i := 0; i < len(data); i++ {
|
||||
x0 := data[i]
|
||||
y0 := b0*x0 + b1*x1 + b2*x2 - a1*y1 - a2*y2
|
||||
out[i] = y0
|
||||
x2 = x1
|
||||
x1 = x0
|
||||
y2 = y1
|
||||
y1 = y0
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
// CascadeLowcut applies the low-cut (high-pass) filter multiple times for steeper slopes.
|
||||
// slopeDb: 12, 24, 36, ... (dB/octave)
|
||||
func CascadeLowcut(data []float64, sampleRate int, cutoffHz float64, slopeDb int) []float64 {
|
||||
if slopeDb < 12 {
|
||||
slopeDb = 12
|
||||
}
|
||||
n := slopeDb / 12
|
||||
out := data
|
||||
for i := 0; i < n; i++ {
|
||||
out = ApplyHighpassButterworth(out, sampleRate, cutoffHz)
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
// CascadeHighcut applies the high-cut (low-pass) filter multiple times for steeper slopes.
|
||||
// slopeDb: 12, 24, 36, ... (dB/octave)
|
||||
func CascadeHighcut(data []float64, sampleRate int, cutoffHz float64, slopeDb int) []float64 {
|
||||
if slopeDb < 12 {
|
||||
slopeDb = 12
|
||||
}
|
||||
n := slopeDb / 12
|
||||
out := data
|
||||
for i := 0; i < n; i++ {
|
||||
out = ApplyLowpassButterworth(out, sampleRate, cutoffHz)
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user