2016-10-16 1 views
0

Ich habe eine Funktion für die Sound-Verarbeitung/Sound-Verarbeitung. Und vorher war alles ein einziger Kanal. Aber weißt du, ich mache es mehr oder weniger mehrkanalig. An diesem Punkt habe ich das Gefühl, ich mache einen Teil der Scripts immer und immer wieder.Wiederholung von Tests in mehreren Funktionen python

In diesem Beispiel sind es zwei Funktionen (meine ursprüngliche Funktion ist länger), aber das gleiche passiert auch in einzelnen Skripten.

my Two functions 
import numpy as np 


# def FFT(x, fs, *args, **kwargs): 
def FFT(x, fs, output='complex'): 
    from scipy.fftpack import fft, fftfreq 
    N = len(x) 
    X = fft(x)/N 
    if output is 'complex': 
     F = np.linspace(0, N)/(N/fs) 
     return(F, X, []) 
    elif output is 'ReIm': 
     F = np.linspace(0, N)/(N/fs) 
     RE = np.real(X) 
     IM = np.imag(X) 
     return(F, RE, IM) 
    elif output is 'AmPh0': 
     F = np.linspace(0, (N-1)/2, N/2) 
     F = F/(N/fs) 
     # N should be int becouse of nfft 
     half_spec = np.int(N/2) 
     AMP = abs(X[0:half_spec]) 
     PHI = np.arctan(np.real(X[0:half_spec])/np.imag(X[0:half_spec])) 
     return(F, AMP, PHI) 
    elif output is 'AmPh': 
     half_spec = np.int(N/2) 
     F = np.linspace(1, (N-1)/2, N/2 - 1) 
     F = F/(N/fs) 
     AMP = abs(X[1:half_spec]) 
     PHI = np.arctan(np.real(X[1:half_spec])/np.imag(X[1:half_spec])) 
     return(F, AMP, PHI) 


def mFFT(x, fs, spectrum='complex'): 
    fft_shape = np.shape(x) 
    if len(fft_shape) == 1: 
     mF, mX1, mX2 = FFT(x, fs, spectrum) 
    elif len(fft_shape) == 2: 
     if fft_shape[0] < fft_shape[1]: 
      pass 
     elif fft_shape[0] > fft_shape[1]: 
      x = x.T 
      fft_shape = np.shape(x) 
     mF = mX1 = mX2 = [] 
     for channel in range(fft_shape[0]): 
      si_mF, si_mX1, si_mX2 = FFT(x[channel], fs, spectrum) 
      if channel == 0: 
       mF = np.append(mF, si_mF) 
       mX1 = np.append(mX1, si_mX1) 
       mX2 = np.append(mX2, si_mX2) 
      else: 
       mF = np.vstack((mF, si_mF)) 
       mX1 = np.vstack((mX1, si_mX1)) 
       if si_mX2 == []: 
        pass 
       else: 
        mX2 = np.vstack((mX2, si_mX2)) 
    elif len(fft_shape) > 2: 
     raise ValueError("Shape of input can't be greather than 2") 
    return(mF, mX1, mX2) 

Die zweite Funktion in diesem Fall hat das Problem.
Der Grund für diese Überprüfungen ist am besten mit einem Beispiel zu verstehen:

Ich habe eine Probe von 1 Sekunde Audiodaten mit 4 Mikrofonen aufgenommen. so habe ich ein ndim-Array von 4 x 44100 Proben. Die FFT funktioniert auf jedem geradzahligen Array. Das bedeutet, dass ich in beiden Situationen ein Ergebnis erhalte (4 x 44100 und 44100 x 4).
Für alle Funktionen nach dieser Funktion habe ich auch 2 Datentypen. oder ein komplexes Signal oder ein Tupel von zwei Signalen (Amplitude und Phase) ... was ist ein zusätzlicher Schalter/Check in das Skript.

  • Check-Typ (Tupel oder komplexe Daten)
  • Kontrollrichtung (ad es ändern)
  • überprüfen Größe/Form
  • Lauf-Funktion und fügen/stapeln diese

gibt es einige Methoden, um dies weniger repeat ich habe diese Situation in mindestens 10 Funktionen ...

Antwort

0

Bert,

Die Problematik, die ich verstehe, ist die Wiederholung der Anrufe, die Sie machen, um Schecks aller Art zu machen. Ich verstehe nicht alles, aber ich vermute, dass sie gemacht werden, um Ihre Daten so zu formatieren, dass Sie fft darauf ausführen können.

Eine der Philosophie über Computerprogrammierung in Python ist "Es ist einfacher, um Vergebung zu bitten, als um Erlaubnis zu bekommen." [1]. Dies bedeutet, dass Sie wahrscheinlich zuerst versuchen sollten und dann um Vergebung bitten (versuchen Sie, außer). Es ist viel schneller, es auf diese Weise zu tun und dann viele Überprüfungen des Wertes durchzuführen. Außerdem sollten diejenigen, die Ihr Programm verwenden werden, verstehen, wie es ziemlich einfach funktioniert; machen Sie es leicht, ohne diese Prüfung zu lesen, indem Sie das logische Geschäft von der technischen Logik trennen. Mach dir keine Sorgen, es ist nicht offensichtlich und die Tatsache, die Sie fragen, ist ein Indikator, dass Sie etwas fangen, ist nicht richtig :). Hier

ist, was ich für den Fall vorschlagen würde (und es ist nicht die perfekte Lösung!):

def mFFT(x, fs, spectrum='complex'): 
    #Assume we're correcty align when receiving the data 
    #:param: x assume that we're multi-channel in the format [channel X soundtrack ] 
    #also, don't do this: 
    #mF = mX1 = si_mX2 = [] 
    # see why : https://stackoverflow.com/questions/2402646/python-initializing-multiple-lists-line 
    mF = [] 
    mX1 = [] 
    mX2 = [] 
    try: 
     for channel in range(len(x)): 
      si_mF, si_mX1, si_mX2 = FFT(x[channel], fs, spectrum) 
      mF.append(si_mF) 
      mX1.append(si_mX1) 
      mX2.append(si_mX2) 
     return (mF, mX1, mX2) 
    except: 
     #this is where you would try to point out why it could have failed. One good you had was the check for the orientation of the data and try again; 
     if np.shape(x)[0] > np.shape(x)[1]: 
      result = mFFT(x.T,fs,spectrum) 
      return result 
     else : 
      if np.shape(x)[0] > 2: 
       raise(ValueError("Shape of input isn't supported for greather than 2")) 

ich ein Beispiel gegeben, weil ich glaube, dass Sie einen erwartet, aber ich gebe nicht die perfekte Antwort Weg ;). Die Problematik, die Sie haben, ist ein Designproblem und nein, es gibt keine einfache Lösung. Was ich Ihnen vorschlage, ist die Annahme, dass die Reihenfolge immer in diesem Format [n-te X-Abtastwertgröße] (d. H. [4-Kanal X 44100-Abtastwert]) ist. So probierst du es zuerst so aus (wie in try/except), dann vielleicht als umgekehrte Reihenfolge. Ein anderer Vorschlag (und es hängt wirklich von Ihrem Anwendungsfall ab) wäre, eine Datenstrukturklasse zu erstellen, die die FFT-Daten manipuliert, um den Komplex oder das ReIm oder das AmPh0 oder das AmPh als Getters zurückzugeben.(so behandeln Sie die Eingabedaten als immer Zeit und Sie geben nur, was die Benutzer wollen).

class FFT(object): 
     def __init__(self,x, fs): 
     from scipy.fftpack import fft, fftfreq 
     self.N = len(x) 
     self.fs = fs 
     self.X = fft(x)/N 

     def get_complex(self): 
     F = np.linspace(0, self.N)/(self.N/self.fs) 
     return(F, self.X, []) 

     def get_ReIm(self): 
     F = np.linspace(0, self.N)/(self.N/self.fs) 
     RE,IM = np.real(self.X), np.imag(self.X) 
     return(F, RE, IM) 

     def get_AmPh0(self): 
     F = np.linspace(0, (self.N-1)/2, self.N/2)/(self.N/self.fs) 
     # N should be int because of nfft 
     half_spec = np.int(self.N/2) 
     AMP = abs(self.X[:half_spec]) 
     PHI = np.arctan(np.real(self.X[:half_spec])/np.imag(self.X[:half_spec])) 
     return(F, AMP, PHI) 

Dies kann dann mit einem eval von einer anderen Klasse auf den gewünschten Ausgang in Abhängigkeit genannt werden verwendet werden, um den Wunsch Ausgabe zu erhalten (aber Sie benötigen die gleiche Konvention über Ihren Code zu verwenden;)). 2

+0

Ich füge ein Beispiel in meine Frage, warum ich denke, dass Sie Beispiel nicht arbeiten. Es war zu viel, um es in einem Kommentar zu erklären. –

+0

Hallo, ich habe meine Antwort geändert, um einen weiteren Vorschlag aufzunehmen, der vielleicht besser an das angepasst ist, was Sie wollen –

Verwandte Themen