Speech Signal Processing Toolkit (SPTK) est une bibliothèque de langage C qui peut effectuer une analyse vocale, une synthèse vocale, une quantification vectorielle, un traitement de données, etc. Je pensais qu'il pouvait être utilisé pour le traitement du signal tel que les vibrations, alors j'ai décidé de l'essayer.
Cette fois, les contenus que nous voulons réaliser en utilisant SPTK
sont les suivants.
En tant que module python, il existe un outil de traitement du signal haute performance appelé librosa
et un wrapper pour SPTK
publié par des volontaires appelé pysptk
, mais je veux utiliser SPTK
. Il ne semblait pas prendre en charge la commande, alors j'ai dû y travailler.
De plus, je n'ai aucune connaissance du traitement du signal (la programmation est également suspecte), il peut donc y avoir des erreurs de termes. Veuillez comprendre que ce n'est pas mal.
J'ai fait référence aux HP suivants.
Construire avec VisualStudio2019 x64 Native Tools
. Il a été plus facile à installer que prévu, mais dans mon environnement, j'ai eu un problème avec la construction de "pitch.exe".
Donc, je l'ai évité en supprimant de force toutes les descriptions liées à "pitch.exe" dans le fichier bin / Makefile.mak avant la construction.
J'ai fait référence aux HP suivants.
Il peut être installé avec ʻapt, mais
SPTK qui peut être installé avec ʻapt
semble avoir des fonctions optionnelles limitées avec certaines commandes (cela peut être un problème dans mon environnement). Je pense qu'il est préférable de construire docilement à partir du fichier source car il est possible que vous soyez accro à des choses inutiles lors de l'utilisation de commandes.
$ tar xvzf SPTK-3.11.tar.gz
$ cd SPTK-3.11
$ ./configure
$ make
$ sudo make install
Tout d'abord, j'ai appris à utiliser SPTK
. Il existe un merveilleux HP qui peut être utile. Ce fut une expérience d'apprentissage formidable pour moi d'expliquer en détail. Merci beaucoup.
SPTK
est fondamentalement comme un outil qui fonctionne à l'aide de commandes via la console. Ici, créez des données sin wave avec la commande sin
de SPTK
et enregistrez-les avec le nom de fichier sin.data
.
Ouvrez la console et entrez la commande suivante. Une séquence d'ondes sinusoïdales de période 16 et de longueur 48 (pour 3 cycles) est enregistrée sous le nom de fichier «sin.data».
$ sin -l 48 -p 16 > sin.data
Pour vérifier le contenu du fichier, entrez la commande SPTK
comme suit:
$ x2x +f < sin.data | dmp +f
Le résultat est affiché comme indiqué ci-dessous et vous pouvez vérifier le contenu du fichier. Le numéro de gauche est le numéro d'index. Gardez à l'esprit que les numéros d'index sont automatiquement ajoutés pour l'affichage et que le fichier de données réel contient uniquement les numéros (à droite).
0 0
1 0.382683
2 0.707107
3 0.92388
4 1
5 0.92388
…
De plus, il semble que les données textuelles puissent également être lues. Dans ce cas, préparez un fichier de données texte (sin.txt
dans l'exemple ci-dessous) dans lequel les valeurs numériques sont séparées par des espaces (valeur séparée par un espace?), Et lisez-le avec la commande suivante.
$ x2x +af < sin.txt | dmp +f
Lors de la lecture de données texte, l'option doit correspondre à ʻASCII, tel que
+ af`. (Parce que je ne comprenais pas ces spécifications de base, je n'ai pas pu obtenir les résultats d'analyse attendus et j'ai perdu environ une demi-journée ...)
Maintenant, lisons les données de chaîne d'octets sin.data
enregistrées précédemment avec python.
import numpy as np
with open('sin.data', mode='rb') as f:
data = np.frombuffer(f.read(), dtype='float32')
print(data)
résultat
[ 0.0000000e+00 3.8268343e-01 7.0710677e-01 9.2387950e-01
1.0000000e+00 9.2387950e-01 7.0710677e-01 3.8268343e-01
1.2246469e-16 -3.8268343e-01 -7.0710677e-01 -9.2387950e-01
-1.0000000e+00 -9.2387950e-01 -7.0710677e-01 -3.8268343e-01
-2.4492937e-16 3.8268343e-01 7.0710677e-01 9.2387950e-01
1.0000000e+00 9.2387950e-01 7.0710677e-01 3.8268343e-01
3.6739403e-16 -3.8268343e-01 -7.0710677e-01 -9.2387950e-01
-1.0000000e+00 -9.2387950e-01 -7.0710677e-01 -3.8268343e-01
-4.8985874e-16 3.8268343e-01 7.0710677e-01 9.2387950e-01
1.0000000e+00 9.2387950e-01 7.0710677e-01 3.8268343e-01
6.1232340e-16 -3.8268343e-01 -7.0710677e-01 -9.2387950e-01
-1.0000000e+00 -9.2387950e-01 -7.0710677e-01 -3.8268343e-01]
Ensuite, créons des données de chaîne d'octets à passer à SPTK
avec python. Il est assez important de spécifier le type. (J'étais accro ici aussi)
arr = np.array(range(0,5)) #Faites une séquence de nombres appropriée
with open('test.data', mode='wb') as f:
arr = arr.astype(np.float32) #Faire le type float32
barr = bytearray(arr.tobytes()) #au bytarray
f.write(barr)
Lisez le fichier avec SPTK
et vérifiez-le.
$ x2x +f < test.data | dmp +f
0 0
1 1
2 2
3 3
4 4
Si vous enregistrez le numpy.ndarray créé par python de cette manière dans un fichier sous forme de chaîne d'octets et passez le fichier via une commande, il semble que vous puissiez traiter les données avec SPTK
.
Essayons d'utiliser sin.data
pendant un moment.
import subprocess
#Commande pour lire les données et appliquer la fonction de fenêtre
cmd = 'x2x +f < sin.data | window -l 16'
p = subprocess.check_output(cmd, shell = True)
out = np.frombuffer(p, dtype='float32')
print(out)
[-0.0000000e+00 3.0001572e-03 2.5496081e-02 8.6776853e-02
1.8433140e-01 2.7229854e-01 2.8093100e-01 1.7583697e-01
5.6270582e-17 -1.5203877e-01 -2.0840828e-01 -1.7030001e-01
-9.3926586e-02 -3.3312235e-02 -5.5435672e-03 2.4845590e-18
1.5901955e-33 3.0001572e-03 2.5496081e-02 8.6776853e-02
1.8433140e-01 2.7229854e-01 2.8093100e-01 1.7583697e-01
1.6881173e-16 -1.5203877e-01 -2.0840828e-01 -1.7030001e-01
-9.3926586e-02 -3.3312235e-02 -5.5435672e-03 2.4845590e-18
3.1803911e-33 3.0001572e-03 2.5496081e-02 8.6776853e-02
1.8433140e-01 2.7229854e-01 2.8093100e-01 1.7583697e-01
2.8135290e-16 -1.5203877e-01 -2.0840828e-01 -1.7030001e-01
-9.3926586e-02 -3.3312235e-02 -5.5435672e-03 2.4845590e-18]
Je déplorais combien il était inutile de créer un fichier juste pour passer des données à SPTK
, mais il y a quelque chose d'utile appelé ʻio.BytesIO`.
En fin de compte, j'ai préparé quelque chose comme ça.
import io
import shlex, subprocess
from typing import List
import numpy
def sptk_wrap(in_array : numpy.ndarray, sptk_cmd : str) -> numpy.ndarray:
'''
contribution
in_array :Données de forme d'onde
sptk_cmd :commandes sptk (par exemple'window -l 16')
production
Données après analyse
'''
# numpy.Convertir ndarray en bytearray
arr = in_array.astype(np.float32)
barr = bytearray(arr.tobytes())
bio = io.BytesIO(barr)
#commande sptk
cmd = shlex.split(sptk_cmd)
proc = subprocess.Popen(cmd, stdin=subprocess.PIPE, stdout=subprocess.PIPE)
out, err = proc.communicate(input=bio.read())
return np.frombuffer(out, dtype='float32')
def sptk_wrap_pipe(in_array : numpy.ndarray, sptk_cmd_pipe : List[str]) -> numpy.ndarray:
'''
contribution
in_array :Données de forme d'onde
sptk_cmd_pipe :Commandes Sptk stockées dans une liste dans l'ordre dans lequel vous souhaitez diriger
(Exemple)
cmd_list = [
'window -l 512 -L 512 -w 2',
'spec -l 512 -o 0',
]
production
Données après analyse
'''
out_array = numpy.copy(in_array)
for l in sptk_cmd_pipe:
out_array = sptk_wrap(out_array, l)
return out_array
#Exemple d'analyse de spectre
def ndarr2sp_ndarr(in_array : numpy.ndarray, length : int, wo : int = 2, oo : int = 0) -> numpy.ndarray:
'''
contribution:Données de forme d'onde
production:Spectre de puissance log
option:
wo :Options de fonction de la fenêtre (0:blackman 1:hammin 2:hanning 3:barlett)
oo :Forme du spectre de sortie (0: 20 × log |Xk| )
exemple de commande sptk
window -l 512 -L 512 -w 2 | spec -l 512 -o 0
'''
cmd_list = [
"window -l {0} -L {0} -w {1} ".format(length, wo),
"spec -l {0} -o {1}".format(length, oo),
]
return sptk_wrap_pipe(in_array, cmd_list)
Créez des données de forme d'onde appropriées et analysez-les réellement. Ici, 10 ensembles d'échantillons avec une longueur de données de 512 ont été créés tout en modifiant la fréquence des données à créer.
import numpy as np
import matplotlib.pyplot as plt
N = 2**9 #Nombre d'échantillons de forme d'onde à analyser 512
dt = 0.01 #Intervalle d'échantillonnage
t = np.arange(0, N*dt, dt) #Axe du temps
freq = np.linspace(0, 1.0/dt, N) #Axe de fréquence
samples = []
for f in range(1,11):
#Réglez la fréquence de la forme d'onde à créer sur 1~Créez 10 ensembles d'échantillons de forme d'onde en passant à 10.
wave = np.sin(2*np.pi*f*t)
samples.append(wave)
samples = np.asarray(samples)
print(samples.shape)
Sortie: (10, 512)
Lorsque vous tracez les données créées, cela ressemble à ceci.
1ère donnée (fréquence 1Hz)
plt.plot(t, samples[0])
10ème données (fréquence 10Hz)
plt.plot(t, samples[9])
Maintenant, analysons le spectre des 10èmes données en utilisant SPTK
.
ps = ndarr2sp_ndarr(samples[9], N)
plt.plot(freq[:N//2+1], ps)
plt.xlabel("frequency [Hz]")
plt.ylabel("Logarithmic Power Spectrum [dB]")
Vous pouvez également analyser plusieurs données à la fois. Cependant, le résultat est sorti dans un état connecté de manière plate, un remodelage est donc nécessaire.
Commencez par vérifier la «forme» du jeu de données.
samples_shape = samples.shape
print(samples_shape)
Sortie: (10, 512)
Analysez 10 pièces avec «SPTK».
ps_s = ndarr2sp_ndarr(samples, N)
print(ps_s.shape)
Sortie: (2570,)
Remodeler.
ps_s = ps_s.reshape((samples_shape[0],-1))
print(ps_s.shape)
Sortie: (10, 257)
10ème données (fréquence 10Hz)
print(np.max(ps_s[9]))
plt.plot(freq[:N//2+1], ps_s[9])
plt.xlabel("frequency [Hz]")
plt.ylabel("Logarithmic Power Spectrum [dB]")
Sortie: 19.078928
Je l'ai comparé au résultat de ma propre analyse. J'ai essayé de normaliser avec le nombre de données et de multiplier par la valeur de correction de la fonction de fenêtre, mais la valeur en décibels est légèrement différente du résultat analysé par SPTK
.
Je ne connais pas la raison ... Il est probable que vous fassiez quelque chose de stupide. (S'il vous plaît dites-moi qui le connaît)
wavedata = samples[9]
#Mettez une fenêtre de miel
hanningWindow = np.hanning(len(wavedata))
wavedata = wavedata * hanningWindow
#Calculer le coefficient de correction
acf = 1/(sum(hanningWindow)/len(wavedata))
#Conversion de Fourier (convertie en signal de fréquence)
F = np.fft.fft(wavedata)
#Normalisation+Doublez le composant AC
F = 2*(F/N)
F[0] = F[0]/2
#Spectre d'oscillation
Adft = np.abs(F)
#Multipliez le coefficient de correction lors de la multiplication de la fonction de fenêtre
Adft = acf * Adft
#Spectre de puissance
Pdft = Adft ** 2
#Spectre de puissance logistique
PdftLog = 10 * np.log10(Pdft)
# PdftLog = 10 * np.log(Pdft)
print(np.max(PdftLog))
start=0
stop=int(N/2)
plt.plot(freq[start:stop], PdftLog[start:stop])
plt.xlabel("frequency [Hz]")
plt.ylabel("Logarithmic Power Spectrum [dB]")
plt.show()
Sortie: -0,2237693
Recommended Posts