web-dev-qa-db-fra.com

Rééchantillonner un tableau numpy

Il est facile de rééchantillonner un tableau comme

 a = numpy.array([1,2,3,4,5,6,7,8,9,10])

avec un entier facteur de rééchantillonnage . Par exemple, avec un facteur 2:

b = a[::2]    # [1 3 5 7 9]

Mais avec un facteur de rééchantillonnage non entier, cela ne fonctionne pas aussi facilement:

c = a[::1.5]    # [1 2 3 4 5 6 7 8 9 10]  => not what is needed...

Il doit être (avec interpolation linéaire):

[1 2.5 4 5.5 7 8.5 10]

ou (en prenant le plus proche voisin dans le tableau)

[1 3 4 6 7 9 10]

Comment rééchantillonner un tableau numpy avec un facteur de rééchantillonnage non entier?

Exemple d'application: rééchantillonnage/repitching du signal audio

13
Basj

Comme scipy.signal.resample peut être très lent , j'ai cherché d'autres algorithmes adaptés à l'audio.

Il semble que Erik de Castro Lopo SRC (a.k.a. Secret Rabbit Code a.k.a. libsamplerate) est l'un des meilleurs algorithmes de rééchantillonnage disponibles.

  • Il est utilisé par scikit.samplerate, mais cette bibliothèque semble compliquée à installer (j'ai abandonné sous Windows).

  • Heureusement, il existe une enveloppe facile à utiliser et à installer Python pour libsamplerate, faite par Tino Wagner: https: // pypi. org/project/samplerate / . Installation avec pip 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')  
    

Lecture/comparaison intéressante de nombreuses solutions de rééchantillonnage: http://signalsprocessed.blogspot.com/2016/08/audio-resampling-in-python.html


Addendum: comparaison des spectrogrammes d'un balayage de fréquence rééchantillonné (20hz à 20khz):

1) Original

2) Rééchantillonné avec le module libsamplerate/samplerate

3) Rééchantillonné avec numpy.interp ("Interpolation linéaire unidimensionnelle"):

7
Basj

NumPy a numpy.interp qui fait une interpolation linéaire:

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 a scipy.interpolate.interp1d qui peut effectuer une interpolation linéaire et la plus proche (bien que le point le plus proche ne soit pas évident):

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.])
20
xnx

Puisque vous mentionnez qu'il s'agit de données d'un fichier audio .WAV, vous pouvez regarder scipy.signal.resample.

Rééchantillonner les échantillons x en num en utilisant la méthode de Fourier le long de l'axe donné.

Le signal rééchantillonné commence à la même valeur que x mais est échantillonné avec un espacement de len(x) / num * (spacing of x). Parce qu'une méthode de Fourier est utilisée, le signal est supposé être périodique.

Votre tableau linéaire a n'est pas bon pour le tester, car il n'est pas périodique en apparence. Mais considérons les données sin:

x=np.arange(10)
y=np.sin(x)
y1, x1 =signal.resample(y,15,x)  # 10 pts resampled at 15

comparer ceux-ci avec

y1-np.sin(x1) # or
plot(x, y, x1, y1)
10
hpaulj

Et si vous voulez l'échantillonnage entier

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]
4
EngineeredE

Dans le traitement du signal, vous pouvez considérer le rééchantillonnage comme un redimensionnement du tableau et une interpolation des valeurs manquantes ou des valeurs avec un indice non entier en utilisant les méthodes les plus proches, linéaires, cubiques, etc.

En utilisant scipy.interpolate.interp1d , vous pouvez réaliser un rééchantillonnage unidimensionnel en utilisant la fonction suivante

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))

par exemple.:

a = np.array([1,2,3,4,5,6,7,8,9,10])
resample(a, factor=1.5, kind='linear')

les rendements

array([ 1. ,  2.5,  4. ,  5.5,  7. ,  8.5, 10. ])

et

a = np.array([1,2,3,4,5,6,7,8,9,10])
resample(a, factor=1.5, kind='nearest')

les rendements

array([ 1.,  2.,  4.,  5.,  7.,  8., 10.])
1
yellow01