Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Weird effect at end of resampled signal #62

Closed
bolau opened this issue Jun 3, 2018 · 4 comments · Fixed by #63
Closed

Weird effect at end of resampled signal #62

bolau opened this issue Jun 3, 2018 · 4 comments · Fixed by #63
Assignees
Milestone

Comments

@bolau
Copy link

bolau commented Jun 3, 2018

Hi,

when resampling a signal I get a weird effect at the end. It consists of a reduced amplitude plus a nasty noise. Is this normal, a bug or am I doing something wrong? Here are plots for a linear and a sine signal:

Linear Signal

Sine Signal

I'm using the current resampy master from GitHub (3e76335), all other packages are installed from conda / virtualenv.

Here's the code that produces the plots:

import matplotlib.pyplot as plt
import numpy as np

import resampy

factor = .5

a = np.arange(0, 50, .1, dtype=float)
b = resampy.resample(a, 1, factor, axis=0)
c = resampy.resample(b, 1, 1/factor, axis=0)

plt.figure()
plt.plot(a, label='Original')
plt.plot(b, label='Resampled %.2f' % factor)
plt.plot(c, label='Resampeld %.2f -> %.2f' % (factor, 1/factor))
plt.legend()

plt.show()

# Same with sin
plt.figure()
a = np.sin(np.arange(0, 50, .1, dtype=float))
b = resampy.resample(a, 1, factor, axis=0)
c = resampy.resample(b, 1, 1/factor, axis=0)

plt.figure()
plt.plot(a, label='Original')
plt.plot(b + 1.5, label='Resampled %.2f' % factor)
plt.plot(c + 3.0, label='Resampeld %.2f -> %.2f' % (factor, 1/factor))
plt.legend()

plt.show()

And here my environment (virtualenv freeze):

cycler==0.10.0
kiwisolver==1.0.1
llvmlite==0.23.2
matplotlib==2.2.2
numba==0.38.1
numpy==1.14.3
pyparsing==2.2.0
python-dateutil==2.7.3
pytz==2018.4
scipy==1.1.0
six==1.11.0

It would be great if you could have a look into this problem. Please let me know if I can do something to help you reproduce it.

Best, Boris

@bmcfee bmcfee added the question label Jun 4, 2018
@bmcfee
Copy link
Owner

bmcfee commented Jun 4, 2018

I think this is probably expected behavior given how short your input signals are, but I will look into it. (Your code example does reproduce the reported behavior on my environment.)

To get high quality reconstruction, the default filter (kaiser_best) uses a very long window to approximate a sinc filter. When you get to the end of the signal, the filter gets adaptively shortened to avoid running off the end of the input buffer, which results in the attenuation behavior that you reported above. You can see this by switching from kaiser_best to kaiser_fast, in which case the results look like:
image
image
(note that the edge effects occupy a much smaller portion of the signal). If you want even more control over this, you can call resampy(... filter='sinc_window', num_zeros=16); the num_zeros parameter controls the effective precision of the resampling filter, with larger values producing longer filters and better fidelity.

For typical audio signals, these edge effects should be negligible. ~100 samples at 22050 Hz would not be audible. Still, it's a bit strange that the beginning of the resampled signal does not exhibit these artifacts, since the filter is time-symmetric, so I'll look into it.

@bmcfee bmcfee added the bug label Jun 4, 2018
@bmcfee bmcfee self-assigned this Jun 4, 2018
@bmcfee bmcfee added this to the 0.2.1 milestone Jun 4, 2018
@bmcfee
Copy link
Owner

bmcfee commented Jun 4, 2018

Update: this does indeed seem to be a bug, due to this line subtracting off the left-hand array bound when calculating the right-hand array bound. Removing that subtraction brings the boundary effects down to where I would expect them:

image

image

At this point though, I'm wondering if it makes more sense to calculate a symmetric array bound for time t so that each output sample always has an equal contributions from the left- and right- wings of the filter. I'll experiment with this and report back. Otherwise, I've flagged this issue for fixing in 0.2.1, which I hope to push in the next few days.

Thanks @bolau for reporting this!

@bmcfee
Copy link
Owner

bmcfee commented Jun 4, 2018

Fix is merged, I'll push the bugfix release later today and it should appear on conda-forge shortly thereafter.

The fix as implemented is, I think, the correct thing to do if we assume the input signal is zero outside of the observations. More generally, I could imagine it being useful to support other edge modes, which might be useful depending on the assumptions you're willing to make about your signals. I've created a new issue #64 for that. I probably won't have time to implement that in the immediate future, but I'm happy to help any newcomers that want to work on it.

@bolau
Copy link
Author

bolau commented Jun 8, 2018

Thanks a lot, this looks much better :)

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

Successfully merging a pull request may close this issue.

2 participants