From 717ae628c33e28fa4b2515044706a188ae64c63b Mon Sep 17 00:00:00 2001 From: Remy Prechelt Date: Wed, 16 Mar 2016 19:09:13 -0500 Subject: [PATCH 1/3] Initial implementation of single-channel biquad filters --- src/DSP.jl | 69 ++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 67 insertions(+), 2 deletions(-) diff --git a/src/DSP.jl b/src/DSP.jl index 536a762..53f78bf 100644 --- a/src/DSP.jl +++ b/src/DSP.jl @@ -11,6 +11,12 @@ type DFTSetup{T} end end +immutable Biquad{T} + setup::Ptr{Void} + sections::Integer +end + +## === FUNCTIONS == ## ## === FUNCTIONS == ## for (T, suff) in ((Float64, "D"), (Float32, "")) @@ -62,7 +68,6 @@ for (T, suff) in ((Float64, "D"), (Float32, "")) end end - """ Cross-correlation of two Vector{T}'s 'X' and 'Y'. Result vector should have at least length(X) + length(Y) - 1 elements @@ -121,9 +126,69 @@ for (T, suff) in ((Float64, "D"), (Float32, "")) xcorr(X, X) end end - end +## == Biquadratic/IIR filtering +for (T, suff) in ((Float64, "D"), (Float32, "")) + + """ + Initializes a vDSP_biquad_setup for use with vDSP_biquad. A multi-section filter + can be initialized with a single call to biquad_create_setup. coefficients must + contain 5 coefficients for each section. The three feed-forward coefficients are + specified first, followed by the two feedback coefficients. Returns a Biquad object. + + Returns: Biquad{T} + """ + @eval begin + function createbiquad(coefficients::Vector{$T}, sections::Integer) + if length(coefficients) < 5*sections + error("Incomplete biquad specification provided - coefficients must + contain 5 elements for each filter section") + end + setup = ccall(($(string("vDSP_biquad_CreateSetup", suff), libacc)), Ptr{Void}, + (Ptr{$T}, UInt64), + coefficients, sections) + return Biquad{$T}(setup, sections) + end + end + + + """ + Filters an input array X with the specified Biquad filter and filter delay values provided + in delays; only numelem elements are filtered. After execution, delays contains the final + state data of the filter. + + Returns: Vector{T} + """ + @eval begin + function biquad(X::Vector{$T}, delays::Vector{$T}, numelem::Integer, biquad::Biquad) + if length(delays) < (2*(biquad.sections)+2) + error("Incomplete delay specification provided - delays must contain 2*M + 2 + values where M is the number of sections in the biquad") + end + result::Vector{$T} = similar(X) + ccall(($(string("vDSP_biquad", suff), libacc)), Void, + (Ptr{Void}, Ptr{$T}, Ptr{$T}, Int64, Ptr{$T}, Int64, UInt64), + biquad.setup, delays, X, 1, result, 1, numelem) + return result + end + end + + + """ + Frees all resources associated with a particular Biquad previously + created through a call to biquad_create_setup + + Returns: Void + """ + @eval begin + function destroybiquad(biquad::Biquad{$T}) + ccall(($(string("vDSP_biquad_DestroySetup", suff), libacc)), Void, + (Ptr{Void}, ), + biquad.setup) + end + end +end ## == WINDOW GENERATION == ## for (T, suff) in ((Float32, ""), (Float64, "D")) From 78c31d0491ac28acbc83b8058c77f8d2ae282048 Mon Sep 17 00:00:00 2001 From: Remy Prechelt Date: Thu, 17 Mar 2016 11:51:47 -0500 Subject: [PATCH 2/3] Added tests for biquads --- test/REQUIRE | 1 + test/runtests.jl | 18 ++++++++++++++++-- 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/test/REQUIRE b/test/REQUIRE index 94e516f..58b056f 100644 --- a/test/REQUIRE +++ b/test/REQUIRE @@ -1 +1,2 @@ BaseTestNext +DSP diff --git a/test/runtests.jl b/test/runtests.jl index 1960bdf..72addef 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -1,4 +1,5 @@ using AppleAccelerate +using DSP if VERSION >= v"0.5-" using Base.Test @@ -112,8 +113,8 @@ end for T in (Float32, Float64) @testset "Convolution & Correlation::$T" begin - X::Array{T} = randn(N) - Y::Array{T} = randn(N) + X::Vector{T} = randn(N) + Y::Vector{T} = randn(N) @testset "Testing $f::$T" for f in [:conv, :xcorr] @eval fb = $f @eval fa = AppleAccelerate.$f @@ -128,6 +129,19 @@ for T in (Float32, Float64) end end +for T in (Float32, Float64) + @testset "Biquadratic Flitering::$T" begin + @testset "Single Section::$T" begin + X::Vector{T} = randn(10) + d::Vector{T} = zeros(4) + c::Vector{T} = [0.5, 0.5, 0.5, 0.5, 0.5] + fdsp = DSP.Biquad(c[1], c[2], c[3], c[4], c[5]) + fa = AppleAccelerate.createbiquad(c, 1) + @test filt(fdsp, X) ≈ AppleAccelerate.biquad(X, d, length(X), fa) + end + end +end + for T in (Float32, Float64) @testset "Window Functions::$T" begin From 9dae7274051a2d074fa610d3647525aebf008f56 Mon Sep 17 00:00:00 2001 From: Remy Prechelt Date: Sun, 20 Mar 2016 10:05:02 -0500 Subject: [PATCH 3/3] Removed Float32 from biquads due to Accelerate bug --- src/DSP.jl | 21 ++++++++++++++------- test/runtests.jl | 8 ++++---- 2 files changed, 18 insertions(+), 11 deletions(-) diff --git a/src/DSP.jl b/src/DSP.jl index 53f78bf..e5828c6 100644 --- a/src/DSP.jl +++ b/src/DSP.jl @@ -11,9 +11,15 @@ type DFTSetup{T} end end -immutable Biquad{T} +type Biquad{T} setup::Ptr{Void} - sections::Integer + sections::Int + + function Biquad(setup::Ptr{Void}, sections::Int) + biquadsetup = new(setup, sections) + finalizer(biquadsetup, biquaddestroy) + biquadsetup + end end ## === FUNCTIONS == ## @@ -129,7 +135,7 @@ for (T, suff) in ((Float64, "D"), (Float32, "")) end ## == Biquadratic/IIR filtering -for (T, suff) in ((Float64, "D"), (Float32, "")) +for (T, suff) in ((Float64, "D"), ) """ Initializes a vDSP_biquad_setup for use with vDSP_biquad. A multi-section filter @@ -140,7 +146,7 @@ for (T, suff) in ((Float64, "D"), (Float32, "")) Returns: Biquad{T} """ @eval begin - function createbiquad(coefficients::Vector{$T}, sections::Integer) + function biquadcreate(coefficients::Vector{$T}, sections::Int) if length(coefficients) < 5*sections error("Incomplete biquad specification provided - coefficients must contain 5 elements for each filter section") @@ -161,7 +167,7 @@ for (T, suff) in ((Float64, "D"), (Float32, "")) Returns: Vector{T} """ @eval begin - function biquad(X::Vector{$T}, delays::Vector{$T}, numelem::Integer, biquad::Biquad) + function biquad(X::Vector{$T}, delays::Vector{$T}, numelem::Int, biquad::Biquad{$T}) if length(delays) < (2*(biquad.sections)+2) error("Incomplete delay specification provided - delays must contain 2*M + 2 values where M is the number of sections in the biquad") @@ -177,12 +183,13 @@ for (T, suff) in ((Float64, "D"), (Float32, "")) """ Frees all resources associated with a particular Biquad previously - created through a call to biquad_create_setup + created through a call to biquad_create_setup. This is called automatically + when the setup object is no longer visible to the garbage collector. Returns: Void """ @eval begin - function destroybiquad(biquad::Biquad{$T}) + function biquaddestroy(biquad::Biquad{$T}) ccall(($(string("vDSP_biquad_DestroySetup", suff), libacc)), Void, (Ptr{Void}, ), biquad.setup) diff --git a/test/runtests.jl b/test/runtests.jl index 72addef..eba9f04 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -129,15 +129,15 @@ for T in (Float32, Float64) end end -for T in (Float32, Float64) +for T in (Float64, ) @testset "Biquadratic Flitering::$T" begin @testset "Single Section::$T" begin X::Vector{T} = randn(10) d::Vector{T} = zeros(4) - c::Vector{T} = [0.5, 0.5, 0.5, 0.5, 0.5] + c::Vector{T} = [x%0.5 for x in randn(5)] fdsp = DSP.Biquad(c[1], c[2], c[3], c[4], c[5]) - fa = AppleAccelerate.createbiquad(c, 1) - @test filt(fdsp, X) ≈ AppleAccelerate.biquad(X, d, length(X), fa) + fa = AppleAccelerate.biquadcreate(c, 1) + @test DSP.filt(fdsp, X) ≈ AppleAccelerate.biquad(X, d, length(X), fa) end end end