Audiofiltering:

Improve filter performance by reducing frequency leakage.
This commit is contained in:
ausocean-david 2022-12-17 02:33:57 +10:30
parent fcc7d72b0b
commit 49db1041d3
1 changed files with 70 additions and 44 deletions

View File

@ -6,6 +6,7 @@ import(
"os" "os"
"encoding/binary" "encoding/binary"
"github.com/mjibson/go-dsp/fft" "github.com/mjibson/go-dsp/fft"
"github.com/mjibson/go-dsp/window"
"math/cmplx" "math/cmplx"
"time" "time"
"sync" "sync"
@ -36,7 +37,7 @@ func main() {
} }
// create filter // create filter
filterLen := 25 filterLen := 500
wg2.Add(1) wg2.Add(1)
ch := make(chan []float64, 1) ch := make(chan []float64, 1)
go HighPass(filterLen, 2000, &wg2, ch) go HighPass(filterLen, 2000, &wg2, ch)
@ -55,12 +56,12 @@ func main() {
filter := <- ch filter := <- ch
// convolve sinc with audio // convolve sinc with audio
wg1.Add(2) wg1.Add(1)
go SaveAudioData(combinedAudio, "unfiltered", &wg1) // go SaveAudioData(combinedAudio, "unfiltered", &wg1)
wg2.Add(1) wg2.Add(1)
filteredAudio := Convolve(combinedAudio, filter, &wg2) filteredAudio := Convolve(combinedAudio, filter, &wg2)
wg2.Wait() wg2.Wait()
go SaveAudioData(filteredAudio, "highpass", &wg1) go SaveAudioData(filteredAudio, "highpass-2KHz", &wg1)
wg1.Wait() wg1.Wait()
fmt.Println(time.Since(start)) fmt.Println(time.Since(start))
@ -100,29 +101,41 @@ func Max (a []float64) float64 {
} }
func LowPass (n int, fc float64, wg *sync.WaitGroup, ch chan []float64) { func LowPass (taps int, fc float64, wg *sync.WaitGroup, ch chan []float64) {
// n is number of points on either side of 0
// determine digital frequency equivalent for fc
fd := (fc*4)/(2*SampleRate)
// create sinc function // create sinc function
ch <- Sinc(n, fd) size := taps + 1
fd := fc/SampleRate
b := (2*math.Pi) * fd
filter := make([]float64, size)
winData := window.FlatTop(size)
for n:=0; n<(taps/2); n++ {
c := float64(n) - float64(taps)/2
y := math.Sin(c*b) / (math.Pi * c)
filter[n] = y * winData[n]
filter[size-1-n] = filter[n]
}
filter[taps/2] = 2*fd*winData[taps/2]
ch <- filter
wg.Done() wg.Done()
} }
func HighPass (n int, fc float64, wg *sync.WaitGroup, ch chan []float64) { func HighPass (taps int, fc float64, wg *sync.WaitGroup, ch chan []float64) {
// n is number of points on either side of 0
// determine digital frequency equivalent for fc
fd := 0.5-((2*fc)/(SampleRate))
fmt.Println(fd)
// create sinc function // create sinc function
filter := Sinc(n, fd) size := taps + 1
// convert lowpass to highpass filter fd := fc/SampleRate
for i:=-n; i<=n; i++ { b := (2*math.Pi) * fd
filter[i+n] = filter[i+n] * math.Pow(-1, float64(i)) filter := make([]float64, size)
winData := window.FlatTop(size)
for n:=0; n<(taps/2); n++ {
c := float64(n) - float64(taps)/2
y := math.Sin(c*b) / (math.Pi * c)
filter[n] = -y * winData[n]
filter[size-1-n] = filter[n]
} }
filter[taps/2] = (1 - 2*fd) * winData[taps/2]
ch <- filter ch <- filter
wg.Done() wg.Done()
@ -130,20 +143,21 @@ func HighPass (n int, fc float64, wg *sync.WaitGroup, ch chan []float64) {
func Convolve (x, h []float64, wg *sync.WaitGroup) []float64 { func Convolve (x, h []float64, wg *sync.WaitGroup) []float64 {
convLen := len(x)+len(h) // conv waitgroup
// var convwg sync.WaitGroup
convLen := len(x)+len(h)-1
y := make([]float64, convLen) y := make([]float64, convLen)
for n:=0; n<convLen; n++ { for n:=0; n<convLen; n++ {
wg.Add(1) go func(n int, y []float64) {
go func (n int, x, h, y []float64, wg *sync.WaitGroup) { var sum float64 = 0
var sum float64 = 0 for k:=0; k<len(x); k++ {
for k:=0; k<len(x); k++ { if n-k >= 0 && n-k < len(h) {
if n-k >= 0 && n-k < len(h) { sum += x[k]*h[n-k]
sum += x[k]*h[n-k] }
} }
}
y[n] = sum y[n] = sum
wg.Done() } (n, y)
}(n, x, h, y, wg)
} }
wg.Done() wg.Done()
return y return y
@ -160,6 +174,10 @@ func SaveAudioData (signal []float64, fileName string, wg1 *sync.WaitGroup) {
for i := range FFTaudio { for i := range FFTaudio {
spectrum[i] = cmplx.Abs(FFTaudio[i])/float64(length) spectrum[i] = cmplx.Abs(FFTaudio[i])/float64(length)
} }
// maximum := Max(signal)
// for i := range signal {
// signal[i] = signal[i]/maximum
// }
maximum := Max(spectrum) maximum := Max(spectrum)
for i := range spectrum { for i := range spectrum {
spectrum[i] = spectrum[i]/maximum spectrum[i] = spectrum[i]/maximum
@ -170,8 +188,8 @@ func SaveAudioData (signal []float64, fileName string, wg1 *sync.WaitGroup) {
go func (fileName string, length int, spectrum []float64, wg1 *sync.WaitGroup) { go func (fileName string, length int, spectrum []float64, wg1 *sync.WaitGroup) {
file := fileName + ".txt" file := fileName + ".txt"
f, _ := os.Create(file) f, _ := os.Create(file)
for i:=0; i<20000; i++ { for i:=0; i<len(spectrum)/2; i++ {
fmt.Fprintf(f, "%v\n", /*20*math.Log10*/(spectrum[i])) fmt.Fprintf(f, "%v\n", 20*math.Log10(spectrum[i]))
} }
fmt.Printf("Saved spectrum values to: %s\n", fileName) fmt.Printf("Saved spectrum values to: %s\n", fileName)
wg1.Done() wg1.Done()
@ -181,8 +199,8 @@ func SaveAudioData (signal []float64, fileName string, wg1 *sync.WaitGroup) {
file := fileName + ".bin" file := fileName + ".bin"
f, _ := os.Create(file) f, _ := os.Create(file)
var buf [8]byte var buf [8]byte
for i:=0; i<length; i++ { for i:=0; i<len(signal); i++ {
binary.LittleEndian.PutUint32(buf[:], math.Float32bits(float32(signal[i]))) binary.LittleEndian.PutUint64(buf[:], math.Float64bits(signal[i]))
_, _ = f.Write(buf[:]) _, _ = f.Write(buf[:])
} }
fmt.Printf("Saved binary values to: %s\n", fileName) fmt.Printf("Saved binary values to: %s\n", fileName)
@ -193,18 +211,26 @@ func SaveAudioData (signal []float64, fileName string, wg1 *sync.WaitGroup) {
} }
func Sinc (nsamps int, fc float64) []float64 { // func SincRedundant (nsamps int, fc float64) []float64 {
// n is number of samples either side of n = 0 // // n is number of samples either side of n = 0
h := make([]float64, nsamps*2 + 1) // h := make([]float64, nsamps*2 + 1)
for n:=-nsamps; n<=nsamps; n++ { // for n:=-nsamps; n<=nsamps; n++ {
if n == 0 { // if n == 0 {
h[n+nsamps] = 2*fc // h[n+nsamps] = 2*fc
} else { // } else {
h[n+nsamps] = math.Sin(2*math.Pi*fc*float64(n))/(math.Pi*float64(n)) // h[n+nsamps] = math.Sin(2*math.Pi*fc*float64(n))/(math.Pi*float64(n))
} // }
} // }
return h // return h
} // }
// func Sinc (x float64) float64 {
// if x == 0 {
// return
// } else {
// h[n+nsamps] = math.Sin(2*math.Pi*fc*float64(n))/(math.Pi*float64(n))
// }
// }