1+ using .. DSP: _zeropad
2+
13const PFB{T} = Matrix{T} # polyphase filter bank
24
35abstract type FIRKernel{T} end
@@ -132,11 +134,11 @@ end
132134FIRArbitrary (h:: Vector , rate:: Real , Nϕ:: Integer ) = FIRArbitrary (h, convert (Float64, rate), convert (Int, Nϕ))
133135
134136# FIRFilter - the kernel does the heavy lifting
135- mutable struct FIRFilter{Tk<: FIRKernel }
136- kernel:: Tk
137+ mutable struct FIRFilter{Tk<: FIRKernel ,T}
138+ const kernel:: Tk
139+ const h:: Vector{T}
140+ const historyLen:: Int
137141 history:: Vector
138- historyLen:: Int
139- h:: Vector
140142end
141143
142144# Constructor for single-rate, decimating, interpolating, and rational resampling filters
@@ -172,7 +174,7 @@ function FIRFilter(h::Vector, resampleRatio::Union{Integer,Rational} = 1)
172174
173175 history = zeros (historyLen)
174176
175- FIRFilter (kernel, history , historyLen, h )
177+ FIRFilter (kernel, h , historyLen, history )
176178end
177179
178180# Constructor for arbitrary resampling filter (polyphase interpolator w/ intra-phase linear interpolation)
@@ -193,7 +195,7 @@ function FIRFilter(h::Vector, rate::AbstractFloat, Nϕ::Integer=32)
193195 kernel = FIRArbitrary (h, rate, Nϕ)
194196 historyLen = kernel. tapsPerϕ - 1
195197 history = zeros (historyLen)
196- FIRFilter (kernel, history , historyLen, h )
198+ FIRFilter (kernel, h , historyLen, history )
197199end
198200
199201# Constructor for a resampling FIR filter, where the user needs only to set the sampling rate
@@ -623,31 +625,34 @@ function filt!(
623625 return bufIdx
624626end
625627
626- function filt (self:: FIRFilter{Tk} , x:: AbstractVector{Tx} ) where {Th,Tx,Tk<: FIRKernel{Th} }
627- bufLen = outputlength (self, length (x))
628+ function filt (self:: FIRFilter{Tk} , x:: AbstractVector ) where Tk<: FIRKernel
629+ buffer = allocate_output (self, x)
630+ bufLen = length (buffer)
631+ samplesWritten = filt! (buffer, self, x)
632+ if Tk <: FIRArbitrary
633+ samplesWritten == bufLen || resize! (buffer, samplesWritten)
634+ else
635+ samplesWritten == bufLen || throw (AssertionError (" Length of resampled output different from expectation." ))
636+ end
637+ return buffer
638+ end
639+
640+ function allocate_output (sf:: FIRFilter{Tk} , x:: AbstractVector{Tx} ) where {Th,Tx,Tk<: FIRKernel{Th} }
628641 # In some cases when `filt(::FIRFilter{FIRArbitrary}, x)` is called
629642 # with certain values of `x`, `filt!(buffer, ::FIRFilter{FIRArbitrary}, x)`
630643 # tries to write one sample too many to the buffer and a `BoundsError`
631- # is thrown. Add one extra sample to catch these exceptional cases.
644+ # is thrown. Add one extra sample to catch these exceptional cases.
632645 #
633646 # See https://github.com/JuliaDSP/DSP.jl/issues/317
634647 #
635648 # FIXME : Remove this if and when the code in
636649 # `filt!(buffer, ::FIRFilter{FIRArbitrary}, x)`
637650 # is updated to properly account for pathological arbitrary rates.
651+ outLen = outputlength (sf, length (x))
638652 if Tk <: FIRArbitrary
639- bufLen += 1
653+ outLen += 1
640654 end
641- buffer = Vector {promote_type(Th,Tx)} (undef, bufLen)
642- samplesWritten = filt! (buffer, self, x)
643-
644- if Tk <: FIRArbitrary
645- samplesWritten == bufLen || resize! (buffer, samplesWritten)
646- else
647- @assert samplesWritten == bufLen
648- end
649-
650- return buffer
655+ return Vector {promote_type(Th, Tx)} (undef, outLen)
651656end
652657
653658
@@ -689,24 +694,34 @@ function resample(x::AbstractVector, rate::AbstractFloat, h::Vector, Nϕ::Intege
689694 _resample! (x, rate, FIRFilter (h, rate, Nϕ))
690695end
691696
692- function _resample! (x:: AbstractVector , rate:: Real , self:: FIRFilter )
697+ function _resample! (x:: AbstractVector , rate:: Real , sf:: FIRFilter )
698+ undelay! (sf)
699+ outLen = ceil (Int, length (x) * rate)
700+ xPadded = _zeropad (x, inputlength (sf, outLen, RoundUp))
701+
702+ buffer = allocate_output (sf, xPadded)
703+ samplesWritten = filt! (buffer, sf, xPadded)
704+ return checked_resample_output! (buffer, outLen, samplesWritten, sf)
705+ end
706+
707+ function undelay! (sf:: FIRFilter )
693708 # Get delay, in # of samples at the output rate, caused by filtering processes
694- τ = timedelay (self )
709+ τ = timedelay (sf )
695710
696711 # Use setphase! to
697712 # a) adjust the input samples to skip over before producing and output (integer part of τ)
698713 # b) set the ϕ index of the PFB (fractional part of τ)
699- setphase! (self, τ)
700-
701- # Calculate the number of 0's required
702- outLen = ceil (Int, length (x) * rate)
703- reqInlen = inputlength (self, outLen, RoundUp)
704- reqZerosLen = reqInlen - length (x)
705- xPadded = [x; zeros (eltype (x), reqZerosLen)]
714+ setphase! (sf, τ)
715+ end
706716
707- y = filt (self, xPadded)
708- @assert length (y) >= outLen
709- length (y) > outLen && resize! (y, outLen)
717+ function checked_resample_output! (y:: AbstractVector , outLen, samplesWritten, :: FIRFilter{Tk} ) where Tk<: FIRKernel
718+ if ! (Tk <: FIRArbitrary )
719+ samplesWritten == length (y) || throw (AssertionError (" Length of resampled output different from expectation." ))
720+ end
721+ # outLen: the desired output length ceil(Int, rate * length(input)), but we can overshoot
722+ # samplesWritten: number of samples actually written to y; if longer, y[samplesWritten+1:end] contains invalid data
723+ samplesWritten >= outLen || throw (AssertionError (" Resample output shorter than expected." ))
724+ length (y) == outLen || resize! (y, outLen)
710725 return y
711726end
712727
@@ -742,11 +757,23 @@ end
742757resample (x:: AbstractArray , rate:: Real , args:: Real... ; dims) =
743758 _resample! (x, rate, FIRFilter (rate, args... ); dims)
744759
745- _resample! (x:: AbstractArray , rate:: Real , sf:: FIRFilter ; dims) =
746- mapslices (x; dims) do v
747- reset! (sf)
748- _resample! (v, rate, sf)
760+ function _resample! (x:: AbstractArray{T} , rate:: Real , sf:: FIRFilter ; dims:: Int ) where T
761+ undelay! (sf)
762+ size_v = size (x, dims)
763+ outLen = ceil (Int, size_v * rate)
764+ xPadded = Vector {T} (undef, inputlength (sf, outLen, RoundUp))
765+ xPadded[size_v+ 1 : end ] .= zero (T)
766+ buffer = allocate_output (sf, xPadded)
767+ bufLen = length (buffer)
768+
769+ mapslices (x; dims) do v:: AbstractVector
770+ undelay! (reset! (sf))
771+ length (buffer) == bufLen || resize! (buffer, bufLen)
772+ copyto! (xPadded, v)
773+ samplesWritten = filt! (buffer, sf, xPadded)
774+ return checked_resample_output! (buffer, outLen, samplesWritten, sf)
749775 end
776+ end
750777
751778#
752779# References
0 commit comments