Resample a numpy array
Solution 1
As scipy.signal.resample
can be very slow, I searched for other algorithms adapted for audio.
It seems that Erik de Castro Lopo's SRC (a.k.a. Secret Rabbit Code a.k.a. libsamplerate) is one of the best resampling algorithms available.
It is used by scikit's
scikit.samplerate
, but this library seems to be complicated to install (I gave up on Windows).-
Fortunately, there is an easy-to-use and easy-to-install Python wrapper for
libsamplerate
, made by Tino Wagner: https://pypi.org/project/samplerate/. Installation withpip install samplerate
. Usage:import samplerate from scipy.io import wavfile sr, x = wavfile.read('input.wav') # 48 khz file y = samplerate.resample(x, 44100 * 1.0 / 48000, 'sinc_best')
Interesting reading / comparison of many resampling solutions: http://signalsprocessed.blogspot.com/2016/08/audio-resampling-in-python.html
Addendum: comparison of spectrograms of a resampled frequency sweep (20hz to 20khz):
1) Original
2) Resampled with libsamplerate / samplerate
module
3) Resampled with numpy.interp
("One-dimensional linear interpolation"):
Solution 2
NumPy has numpy.interp
which does linear interpolation:
In [1]: numpy.interp(np.arange(0, len(a), 1.5), np.arange(0, len(a)), a)
Out[1]: array([ 1. , 2.5, 4. , 5.5, 7. , 8.5, 10. ])
SciPy has scipy.interpolate.interp1d
which can do linear and nearest interpolation (though which point is nearest might not be obvious):
In [2]: from scipy.interpolate import interp1d
In [3]: xp = np.arange(0, len(a), 1.5)
In [4]: lin = interp1d(np.arange(len(a)), a)
In [5]: lin(xp)
Out[5]: array([ 1. , 2.5, 4. , 5.5, 7. , 8.5, 10. ])
In [6]: nearest = interp1d(np.arange(len(a)), a, kind='nearest')
In [7]: nearest(xp)
Out[7]: array([ 1., 2., 4., 5., 7., 8., 10.])
Solution 3
Since you mention this being data from an audio .WAV file, you might look at scipy.signal.resample
.
Resample
x
tonum
samples using Fourier method along the given axis.The resampled signal starts at the same value as
x
but is sampled with a spacing oflen(x) / num * (spacing of x)
. Because a Fourier method is used, the signal is assumed to be periodic.
Your linear array a
is not a good one to test this on, since it isn't periodic in appearance. But consider sin
data:
x=np.arange(10)
y=np.sin(x)
y1, x1 =signal.resample(y,15,x) # 10 pts resampled at 15
compare these with either
y1-np.sin(x1) # or
plot(x, y, x1, y1)
Solution 4
And if you want the integer sampling
a = numpy.array([1,2,3,4,5,6,7,8,9,10])
factor = 1.5
x = map(int,numpy.round(numpy.arange(0,len(a),factor)))
sampled = a[x]
Solution 5
In signal processing, you can think of resampling as basically rescaling the array and interpolating the missing values or values with non-integer index using nearest, linear, cubic, etc methods.
Using scipy.interpolate.interp1d
, you can achieve one dimensional resampling using the following function
def resample(x, factor, kind='linear'):
n = np.ceil(x.size / factor)
f = interp1d(np.linspace(0, 1, x.size), x, kind)
return f(np.linspace(0, 1, n))
e.g.:
a = np.array([1,2,3,4,5,6,7,8,9,10])
resample(a, factor=1.5, kind='linear')
yields
array([ 1. , 2.5, 4. , 5.5, 7. , 8.5, 10. ])
and
a = np.array([1,2,3,4,5,6,7,8,9,10])
resample(a, factor=1.5, kind='nearest')
yields
array([ 1., 2., 4., 5., 7., 8., 10.])
Related videos on Youtube
Basj
I work on R&D involving Python, maths, machine learning, deep learning, data science, product design, and MacGyver solutions to complex problems. I love prototyping, building proofs-of-concept. For consulting/freelancing inquiries : [email protected]
Updated on July 16, 2022Comments
-
Basj almost 2 years
It's easy to resample an array like
a = numpy.array([1,2,3,4,5,6,7,8,9,10])
with an integer resampling factor. For instance, with a factor 2 :
b = a[::2] # [1 3 5 7 9]
But with a non-integer resampling factor, it doesn't work so easily :
c = a[::1.5] # [1 2 3 4 5 6 7 8 9 10] => not what is needed...
It should be (with linear interpolation):
[1 2.5 4 5.5 7 8.5 10]
or (by taking the nearest neighbour in the array)
[1 3 4 6 7 9 10]
How to resample a numpy array with a non-integer resampling factor?
Example of application: audio signal resampling / repitching
-
wflynny about 9 yearsWhat is the desired behavior? Linear interpolation or nearest neighbor in the array?
-
Basj about 9 years@wflynny Both would work... If nearest neighboor, probably it's even not necessary to duplicate the array in memory, just a new "view" of the array might be possible, right? (At the end I'll probably use linear interp for better quality)
-
reptilicus about 9 yearsprobably have to use
scipy.interpolate.interp1d
or one of the other interpolation routines in scipy -
hpaulj about 9 years'resampling' is an unusual way of describing the
::2
way of indexing.numpy
arrays (and Python lists) are not primarily seen as samples (though their values may represent samples of something else). -
Basj about 9 years@hpaulj I used the word resampling, because I use a
numpy
array for audio data contained in a .WAV files. Doing this on this array is called "resampling" in audio / or "repitching", it depends on how we use it. -
Alejandro about 9 yearsThe example you are using, in particular using indexing and resampling as the same thing is very confusing. I suggest you to modify your question by removing the indexing part. I guess your problem is to interpolate a function that map (0,1,2,3,.... N) to (0,1,2,3,....,N), and you are trying to find the value at intermediate points. To do so, use scipy.interpolation tools, such us interp1d
-
hpaulj about 9 yearsIsn't audio downsampling more involved than simply throwing away half of the data? The literature talks about sinc interpolation and filtering.
-
-
Basj about 9 yearsNice as well! Do you think it is more efficient that the other solution, in terms of speed?
-
EngineeredE about 9 yearsprobably not faster than scipy / numpy solution. just giving you options.
-
Basj over 5 yearsWorking @hpaulj but
scipy.signal.resample
can be very slow! -
Noprogexprnce mathmtcn about 5 yearsHello and thanks for your answer and upvoted (not my question)!. But what if the signal isn't periodic? Is there a way to resample then? I asked a related queston here- stats.stackexchange.com/questions/398752/…
-
fabda01 about 5 years@Noprogexprncemathmtcn If the signal is not periodic you might want to use some kind of interpolation. Check this answer stackoverflow.com/a/55747293/6327658