Skip to content

aliasing issue with floating-point resampling ratio #620

Description

@ericphanson

When calling resample with a floating-point value, it takes a different codepath than with a rational value. The floating-point version seems more susceptible to aliasing issues.

Here is an example, minimized from a real-world issue, that demonstrates the problem:

using DSP, CairoMakie

function hpf(x, freq; fs)
    return filtfilt(digitalfilter(Highpass(freq; fs), Butterworth(4)), x)
end

function lpf(x, freq; fs)
    return filtfilt(digitalfilter(Lowpass(freq; fs), Butterworth(4)), x)
end

function middle_third(x)
    third = div(length(x), 3)
    return x[third:(2 * third + 1)]
end

function plt_filters(x; fs)
    x = lpf(x, 35.0; fs)
    x = hpf(x, 0.5; fs)
    return x
end

sine_wave(freq_hz) = sin.(2π .* freq_hz .* ts)

n = 45 # seconds
fs = 250
ts = range(0, n; length=fs * n)
data = 0.05 * sine_wave(0.75) + 0.01 * sine_wave(5.0) + 0.025 * sine_wave(10.0) +
       # lots of high frequency noise
       sum(100 * sine_wave(f) for f in 90:125)

resampling_ratio = 1 / 1.00592
resampled = resample(data, resampling_ratio)
ts_resampled = resample(ts, resampling_ratio)

rational_resampled = resample(data, rationalize(resampling_ratio))
rational_ts_resampled = resample(ts, rationalize(resampling_ratio))

# individual axes
fig = let
    fig = Figure()
    colors = Makie.wong_colors()
    ax_kwargs = (; ylabel="Data", limits=(nothing, nothing, -1, 1))

    ax1 = Axis(fig[1, 1]; ax_kwargs...)
    l1 = lines!(ax1, middle_third(ts), middle_third(plt_filters(data; fs)); color=colors[1])

    ax2 = Axis(fig[2, 1]; ax_kwargs...)
    l2 = lines!(ax2, middle_third(ts_resampled), middle_third(plt_filters(resampled; fs));
                color=colors[2])

    ax3 = Axis(fig[3, 1]; xlabel="Time (s)", ax_kwargs...)
    l3 = lines!(ax3, middle_third(rational_ts_resampled),
                middle_third(plt_filters(rational_resampled; fs)); color=colors[3])

    Legend(fig[4, 1], [l1, l2, l3], ["original", "resampled", "rational resampled"];
           orientation=:horizontal)
    fig
end

save("mwe.png", fig)

# combined
fig = let
    fig = Figure()
    colors = Makie.wong_colors()
    ax_kwargs = (; ylabel="Data", limits=(nothing, nothing, -1, 1))
    ax = Axis(fig[1, 1]; xlabel="Time (s)", ax_kwargs...)

    lines!(ax, middle_third(ts_resampled), middle_third(plt_filters(resampled; fs));
           color=colors[2], label="resampled")
    lines!(ax, middle_third(rational_ts_resampled),
           middle_third(plt_filters(rational_resampled; fs)); color=colors[3],
           label="rational resampled")
    lines!(ax, middle_third(ts), middle_third(plt_filters(data; fs)); color=colors[1],
           label="original")

    axislegend(ax)
    fig
end
save("mwe-combined.png", fig)
fig

Image
Image

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions