DSP.jl
DSP.jl copied to clipboard
Got "BoundsError" while trying to use `resample` function.
using DSP
a_sig = sin.([1:1:35546; ])
resample(a_sig, 1/55.55)
And we will get:
ERROR: BoundsError: attempt to access 640-element Array{Float64,1} at index [641]
Stacktrace:
[1] setindex! at .\array.jl:767 [inlined]
[2] filt!(::Array{Float64,1}, ::FIRFilter{DSP.Filters.FIRArbitrary{Float64}}, ::Array{Float64,1}) at C:\Users\Losses\.juliapro\JuliaPro_v1.1.1.1\packages\DSP\wwKNu\src\Filters\stream_filt.jl:660
[3] filt(::FIRFilter{DSP.Filters.FIRArbitrary{Float64}}, ::Array{Float64,1}) at C:\Users\Losses\.juliapro\JuliaPro_v1.1.1.1\packages\DSP\wwKNu\src\Filters\stream_filt.jl:673
[4] resample(::Array{Float64,1}, ::Float64, ::Array{Float64,1}) at C:\Users\Losses\.juliapro\JuliaPro_v1.1.1.1\packages\DSP\wwKNu\src\Filters\stream_filt.jl:728
[5] resample(::Array{Float64,1}, ::Float64) at C:\Users\Losses\.juliapro\JuliaPro_v1.1.1.1\packages\DSP\wwKNu\src\Filters\stream_filt.jl:733
[6] top-level scope at none:0
@JayKickliter It looks like you wrote this code originally. I'd have to spend a bit of time reading it to understand why the indexing logic doesn't work in this instance. Do you have time to take a look at it?
My first guess is that it’s floating point rounding problem, but I’ll take a closer look. I haven’t written a single line of Julia in several years, so it’ll take me little time to get back up to speed.
Thanks! I'll also take a look.
#262 is the same bug.
Another MWE, if it helps:
using DSP
x = randn(1822)
resample(x, 0.9802414928649834) # works
resample(x, 0.9802414928649835) # fails
I'm also hitting this problem on Julia 1.9 beta and DSP v0.7.8:
julia> using DSP
julia> resample(1:16_367_000*2, 10_000_000/16_367_000)
ERROR: BoundsError: attempt to access 20000000-element Vector{Float64} at index [20000001]
Stacktrace:
[1] setindex!
@ ./array.jl:969 [inlined]
[2] filt!(buffer::Vector{Float64}, self::FIRFilter{DSP.Filters.FIRArbitrary{Float64}}, x::Vector{Int64})
@ DSP.Filters ~/.julia/packages/DSP/wENjI/src/Filters/stream_filt.jl:660
[3] filt(self::FIRFilter{DSP.Filters.FIRArbitrary{Float64}}, x::Vector{Int64})
@ DSP.Filters ~/.julia/packages/DSP/wENjI/src/Filters/stream_filt.jl:673
[4] resample(x::UnitRange{Int64}, rate::Float64, h::Vector{Float64})
@ DSP.Filters ~/.julia/packages/DSP/wENjI/src/Filters/stream_filt.jl:728
[5] resample(x::UnitRange{Int64}, rate::Float64)
@ DSP.Filters ~/.julia/packages/DSP/wENjI/src/Filters/stream_filt.jl:733
[6] top-level scope
@ REPL[6]:1
I have hit this multiple times now. My own reproducer is
import DSP
DSP.resample(zeros(1000), 0.012)
It does appear that somewhere with the FIRArbitrary constructor or its filt! method there is some sort of rounding problem which means that kernel.xIdx gets to the length of the input vector after one point too many (making the buffer index go out of bounds). I don't believe the problem is with outputlength(::FIRArbitrary, inputlength), as this gives the same value as ceil(Int, inputlength*rate) for all the problem cases above. That leaves the issue potentially in update(::FIRArbitrary) (why not update!, btw?).
Given that filt(::FIRFilter{FIRArbitrary}, x) (src/Filters/stream_filt.jl:670) creates a buffer and then maybe shrinks it anyway, perhaps it makes sense to create a buffer there which is 1 element longer? The downside here is that in almost all cases the array will be shrunk by one. But given that there are lots of allocations happening in a call to filt anyway and resize! can be cheap, this probably doesn't matter.
For what it's worth, this version of filt(::FITFilter{FIRArbitrary}}, x) works for all the failing examples above:
function filt(self::FIRFilter{FIRArbitrary{Th}}, x::AbstractVector{Tx}) where {Th,Tx}
bufLen = DSP.outputlength(self, length(x)) + 1 # Note extra element here
buffer = Vector{promote_type(Th,Tx)}(undef, bufLen)
samplesWritten = filt!(buffer, self, x)
samplesWritten == bufLen || resize!(buffer, samplesWritten)
return buffer
end
@anowacki It's been years since I wrote this code, and I'd do a lot differently now. I also barely remember any Julia, let alone anything post 0.5. I do think your findings are correct and suggest opening a PR.