mirror of https://bitbucket.org/ausocean/av.git
Audiofiltering:
Improve filter performance by reducing frequency leakage.
This commit is contained in:
parent
fcc7d72b0b
commit
49db1041d3
|
@ -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))
|
||||||
|
// }
|
||||||
|
// }
|
Loading…
Reference in New Issue