Hey,
I was trying to implement a sinc interpolation based on FFTs.
One way (as far as I know) is to zero pad the frequency spectrum and calculate the IFFT of the spectrum to get a sinc interpolated signal.
I ended up with the following implementation:
function sinc_interpolate(arr::AbstractArray{T}, new_size) where T<:Complex
arr_f = fftshift(fft(arr))
out_f = zeros(eltype(arr_f), new_size)
center_set!(out_f, arr_f)
out = ifft(ifftshift(out_f)) ./ length(arr) .* length(out_f)
return real(out)
end
center_set!
is a function which sets the signal to the center of the array (in the FFT convention).
To compare the method, I also implemented a slow, sum based sinc interpolation:
function sinc_interpolate_sum(arr, new_size)
out = zeros(eltype(arr), new_size)
T = 1 / size(arr)[1]
t_arr = LinRange(0, 1.0 - T, size(out)[1])
for (j, t) in enumerate(t_arr)
v = zero(eltype(arr))
for n = 1:size(arr)[1]
v += arr[n] * sinc((t - (n-1) * T) / T)
end
out[j] = v
end
return out
end
The FFT based method basically works and I’m familiar with the fact, that this kind of interpolation assumes a infinite signal and a finite frequency support.
However, I observe certain artifacts with simple examples:
#prepare x pos and function
xs_low = LinRange(0, 16Ď€ - 16Ď€/140, 140)
f(x) = sin(0.5*x) + cos(x) + cos(2 * x) + sin(0.25*x)
#calculate low resolution
arr_low = f.(xs_low)
#interpolation
N = 1000
xs_interp = LinRange(0, xs_low[end], N)
arr_interp = sinc_interpolate(arr_low, N)
arr_interp_s = sinc_interpolate_sum(arr_low, N)
We can plot everything:
scatter(xs_low, arr_low, legend=:bottomleft, markersize=2, label="data")
plot!(xs_interp, arr_interp, label="FFT sinc interp")
plot!(xs_interp, arr_interp_s, label="sum sinc interp")
We see that the FFT based curve (orange) seems to have a slight, growing offset despite I’ve chosen the data arr_low
to be periodic.
My questions would be:
- Is this shift due to the finite signal?
- Can we fix this shift somehow? For example, by stretching the signal, it fits better.
- Is this even a proper sinc interpolation? Of course, I was searching in the web, but I often find vague, unprecise information People mention sometimes the aliased sinc or dirichlet kernel. Can anybody refer a good theoretical resource?
Thanks,
Felix