Speech Signal Processing Toolkit (SPTK) ist eine C-Sprachbibliothek, die Sprachanalyse, Sprachsynthese, Vektorquantisierung, Datenverarbeitung usw. durchführen kann. Ich dachte, es könnte für die Signalverarbeitung wie Vibration verwendet werden, also beschloss ich, es auszuprobieren.
Dieses Mal sind die Inhalte, die wir mit "SPTK" realisieren möchten, wie folgt.
Als Python-Modul gibt es ein leistungsstarkes Signalverarbeitungswerkzeug namens "librosa" und einen Wrapper für "SPTK", der von Freiwilligen namens "pysptk" veröffentlicht wurde, aber ich möchte "SPTK" verwenden. Es schien den Befehl nicht zu unterstützen, also musste ich daran arbeiten.
Außerdem habe ich keine Kenntnisse über die Signalverarbeitung (die Programmierung ist ebenfalls verdächtig), sodass möglicherweise Fehler auftreten. Bitte haben Sie Verständnis dafür, dass es nicht schlecht ist.
Ich bezog mich auf die folgenden HP.
Erstellen Sie mit "VisualStudio2019 x64 Native Tools". Es war einfacher zu installieren als ich erwartet hatte, aber in meiner Umgebung hatte ich ein Problem beim Erstellen von "Pitch.exe". Also habe ich es vermieden, indem ich vor dem Erstellen alle Beschreibungen zu "Pitch.exe" in der Datei bin / Makefile.mak zwangsweise gelöscht habe.
Ich bezog mich auf die folgenden HP.
Es kann mit apt
installiert werden, aber SPTK
, das mit apt
installiert werden kann, scheint mit einigen Befehlen eingeschränkte optionale Funktionen zu haben (dies kann in meiner Umgebung ein Problem sein). Ich denke, es ist besser, gehorsam aus der Quelldatei zu erstellen, da die Möglichkeit besteht, dass Sie bei der Verwendung von Befehlen von unnötigen Dingen abhängig werden.
$ tar xvzf SPTK-3.11.tar.gz
$ cd SPTK-3.11
$ ./configure
$ make
$ sudo make install
Zuerst habe ich gelernt, wie man SPTK benutzt. Es gibt eine wunderbare HP, die hilfreich sein kann. Es war eine großartige Lernerfahrung für mich, sie ausführlich zu erklären. Vielen Dank.
SPTK
ist im Grunde wie ein Tool, das mit Befehlen über die Konsole arbeitet. Erstellen Sie hier Sin-Wave-Daten mit dem Befehl "sin" von "SPTK" und speichern Sie sie unter dem Dateinamen "sin.data".
Öffnen Sie die Konsole und geben Sie den folgenden Befehl ein. Eine Folge von Sinuswellen mit Periode 16 und Länge 48 (für 3 Zyklen) wird unter dem Dateinamen "sin.data" gespeichert.
$ sin -l 48 -p 16 > sin.data
Geben Sie den Befehl SPTK
wie folgt ein, um den Inhalt der Datei zu überprüfen:
$ x2x +f < sin.data | dmp +f
Das Ergebnis wird wie unten gezeigt ausgegeben und Sie können den Inhalt der Datei überprüfen. Die Nummer links ist die Indexnummer. Beachten Sie, dass die Indexnummern automatisch zur Anzeige hinzugefügt werden und die eigentliche Datendatei nur die Nummern enthält (rechts).
0 0
1 0.382683
2 0.707107
3 0.92388
4 1
5 0.92388
…
Darüber hinaus scheinen auch Textdaten gelesen werden zu können. Bereiten Sie in diesem Fall eine Textdatendatei (sin.txt
im folgenden Beispiel) vor, in der die numerischen Werte durch Leerzeichen getrennt sind (Leerzeichen getrennter Wert?), Und lesen Sie sie mit dem folgenden Befehl.
$ x2x +af < sin.txt | dmp +f
Beim Lesen von Textdaten muss die Option "ASCII" unterstützen, z. B. "+ af". (Weil ich solche grundlegenden Spezifikationen nicht verstanden habe, konnte ich nicht die erwarteten Analyseergebnisse erhalten und habe ungefähr einen halben Tag verschwendet ...)
Lesen wir nun die Byte-String-Daten sin.data
, die zuvor mit Python gespeichert wurden.
import numpy as np
with open('sin.data', mode='rb') as f:
data = np.frombuffer(f.read(), dtype='float32')
print(data)
Ergebnis
[ 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]
Als nächstes erstellen wir Byte-String-Daten, die mit Python an SPTK übergeben werden sollen. Es ist sehr wichtig, den Typ anzugeben. (Ich war auch hier süchtig)
arr = np.array(range(0,5)) #Machen Sie eine entsprechende Zahlenfolge
with open('test.data', mode='wb') as f:
arr = arr.astype(np.float32) #Machen Sie float32 Typ
barr = bytearray(arr.tobytes()) #zu bytarray
f.write(barr)
Lesen Sie die Datei mit SPTK
und überprüfen Sie sie.
$ x2x +f < test.data | dmp +f
0 0
1 1
2 2
3 3
4 4
Wenn Sie die von Python auf diese Weise erstellte numpy.ndarray als Byte-Zeichenfolge in einer Datei speichern und die Datei über einen Befehl übergeben, können Sie die Daten anscheinend mit SPTK
verarbeiten.
Lassen Sie uns für einen Moment versuchen, sin.data
zu verwenden.
import subprocess
#Befehl zum Lesen von Daten und Anwenden der Fensterfunktion
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]
Ich habe beklagt, wie verschwenderisch es war, eine Datei zu erstellen, nur um Daten an "SPTK" zu übergeben, aber es gibt etwas Nützliches namens "io.BytesIO".
Am Ende habe ich so etwas vorbereitet.
import io
import shlex, subprocess
from typing import List
import numpy
def sptk_wrap(in_array : numpy.ndarray, sptk_cmd : str) -> numpy.ndarray:
'''
Eingang
in_array :Wellenformdaten
sptk_cmd :sptk-Befehle (z'window -l 16')
Ausgabe
Daten nach der Analyse
'''
# numpy.Konvertieren Sie ndarray in bytearray
arr = in_array.astype(np.float32)
barr = bytearray(arr.tobytes())
bio = io.BytesIO(barr)
#sptk Befehl
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:
'''
Eingang
in_array :Wellenformdaten
sptk_cmd_pipe :Sptk-Befehle, die in einer Liste in der Reihenfolge gespeichert sind, in der Sie sie weiterleiten möchten
(Beispiel)
cmd_list = [
'window -l 512 -L 512 -w 2',
'spec -l 512 -o 0',
]
Ausgabe
Daten nach der Analyse
'''
out_array = numpy.copy(in_array)
for l in sptk_cmd_pipe:
out_array = sptk_wrap(out_array, l)
return out_array
#Beispiel für eine Spektrumanalyse
def ndarr2sp_ndarr(in_array : numpy.ndarray, length : int, wo : int = 2, oo : int = 0) -> numpy.ndarray:
'''
Eingang:Wellenformdaten
Ausgabe:Log Leistungsspektrum
Möglichkeit:
wo :Fensterfunktionsoptionen (0:blackman 1:hammin 2:hanning 3:barlett)
oo :Ausgangsspektrumform (0: 20 × log |Xk| )
Beispiel für einen sptk-Befehl
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)
Erstellen Sie geeignete Wellenformdaten und analysieren Sie sie tatsächlich. Hier wurden 10 Sätze von Stichproben mit einer Datenlänge von 512 erstellt, während die Häufigkeit der zu erstellenden Daten geändert wurde.
import numpy as np
import matplotlib.pyplot as plt
N = 2**9 #Anzahl der zu analysierenden Wellenformproben 512
dt = 0.01 #Abtastintervall
t = np.arange(0, N*dt, dt) #Zeitachse
freq = np.linspace(0, 1.0/dt, N) #Frequenzachse
samples = []
for f in range(1,11):
#Stellen Sie die Frequenz der zu erstellenden Wellenform auf 1 ein~Erstellen Sie 10 Sätze von Wellenform-Samples, während Sie zu 10 wechseln.
wave = np.sin(2*np.pi*f*t)
samples.append(wave)
samples = np.asarray(samples)
print(samples.shape)
Ausgabe: (10, 512)
Wenn Sie die erstellten Daten zeichnen, sieht es so aus.
plt.plot(t, samples[0])
plt.plot(t, samples[9])
Lassen Sie uns nun das Spektrum der 10. Daten mit SPTK
analysieren.
ps = ndarr2sp_ndarr(samples[9], N)
plt.plot(freq[:N//2+1], ps)
plt.xlabel("frequency [Hz]")
plt.ylabel("Logarithmic Power Spectrum [dB]")
Sie können auch mehrere Daten gleichzeitig analysieren. Das Ergebnis wird jedoch in einem flach verbundenen Zustand ausgegeben, sodass eine Umformung erforderlich ist.
Überprüfen Sie zunächst die Form des Datensatzes.
samples_shape = samples.shape
print(samples_shape)
Ausgabe: (10, 512)
Analysiere 10 Stücke zusammen mit SPTK
.
ps_s = ndarr2sp_ndarr(samples, N)
print(ps_s.shape)
Ausgabe: (2570,)
Umformen.
ps_s = ps_s.reshape((samples_shape[0],-1))
print(ps_s.shape)
Ausgabe: (10, 257)
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]")
Ausgabe: 19.078928
Ich habe es mit dem Ergebnis meiner eigenen Analyse verglichen. Ich habe versucht, mit der Anzahl der Daten zu normalisieren und mit dem Korrekturwert der Fensterfunktion zu multiplizieren, aber der Dezibelwert unterscheidet sich geringfügig von dem von "SPTK" analysierten Ergebnis.
Ich kenne den Grund nicht ... Es ist wahrscheinlich, dass Sie etwas Dummes tun. (Bitte sagen Sie mir, wer damit vertraut ist)
wavedata = samples[9]
#Stell ein Honigfenster auf
hanningWindow = np.hanning(len(wavedata))
wavedata = wavedata * hanningWindow
#Berechnen Sie den Korrekturkoeffizienten
acf = 1/(sum(hanningWindow)/len(wavedata))
#Fourier-Umwandlung (in Frequenzsignal umgewandelt)
F = np.fft.fft(wavedata)
#Normalisierung+Verdoppeln Sie die AC-Komponente
F = 2*(F/N)
F[0] = F[0]/2
#Schwingungsspektrum
Adft = np.abs(F)
#Multiplizieren Sie den Korrekturkoeffizienten, wenn Sie die Fensterfunktion multiplizieren
Adft = acf * Adft
#Leistungsspektrum
Pdft = Adft ** 2
#Logistisches Leistungsspektrum
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()
Ausgabe: -0,2237693
Recommended Posts