Bedienen Sie das Speech Signal Processing Toolkit über Python

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.

1. Einführung von SPTK

Für Windows

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.

Für Ubuntu

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

1. Verwendung von SPTK

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

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

Daten mit Python lesen

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]

Daten in Python erstellen

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

Kooperation zwischen Python und SPTK

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]

Effizientere Datenübertragung

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)

2. Anwendungsbeispiel

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.

  1. Daten (Frequenz 1Hz)
plt.plot(t, samples[0])

index1.png

  1. Daten (Frequenz 10Hz)
plt.plot(t, samples[9])

index2.png

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

index3.png

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)

  1. Daten (Frequenz 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]")

Ausgabe: 19.078928 index4.png

3. 3. Ergänzung

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

index5.png

Recommended Posts

Bedienen Sie das Speech Signal Processing Toolkit über Python
python3 Messen Sie die Verarbeitungsgeschwindigkeit.
Akustische Signalverarbeitung mit Python (2)
Überlassen Sie die mühsame Verarbeitung Python
Signalverarbeitung in Python (1): Fourier-Transformation
[Python] Betreiben Sie den Browser automatisch mit Selenium
Die Geschichte der Verarbeitung A von Blackjack (Python)
Holen Sie sich das Wetter in Osaka über Web-API (Python)
Der einfachste Weg, um Stimme mit Python zu synthetisieren
Zeigen Sie das Ergebnis der Geometrieverarbeitung in Python an
Bildverarbeitung? Die Geschichte, Python für zu starten
Installieren Sie MongoDB unter Ubuntu 16.04 und arbeiten Sie über Python
Python-Dateiverarbeitung
[Python] Misst und zeigt die für die Verarbeitung erforderliche Zeit an
[Wiedereinführung in Python] Importieren über das übergeordnete Verzeichnis
Verwenden Sie CASA Toolkit in Ihrer eigenen Python-Umgebung
Senden Sie Daten von Python über die Socket-Kommunikation an Processing
Senden und empfangen Sie Google Mail über die Google Mail-API mit Python
Untersuchen Sie die genaue Verarbeitung des Python-Datasets (SQLAlchemy-Wrapper).