在多个函数中重复测试 python

repeating tests in multiple functions python

我有一些声音处理功能/声音处理。之前都是单一渠道。但是我知道我会减少或增加多渠道。 此时我有一种感觉,我一遍又一遍地做着一部分的纸条。

在此示例中,它是两个函数(我的原始函数更长),但在单个脚本中也会发生同样的情况。

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)

本例中的第二个函数有问题。
这个检查的原因最好用一个例子来理解:

我用 4 个麦克风录制了 1 秒的音频数据样本。 所以我有一个 4 x 44100 个样本的 ndim 数组。 FFT 适用于每个偶数长度的数组。这意味着我在两种情况下都得到了结果(4 x 44100 和 44100 x 4)。
对于此函数之后的所有函数,我还有 2 种数据类型。或复杂信号或两个信号(振幅和相位)的元组...在脚本中创建额外开关/检查的内容。

是否有一些方法可以减少这种重复我至少有 10 个函数遇到过这种情况...

伯特,

我理解的问题是重复调用您进行各种检查。我不是很了解,但我猜它们是用来格式化您的数据的,您将能够对其执行 fft。

Python 中关于计算机编程的哲学之一是 "It's easier to ask forgiveness than it is to get permission."[1]。这意味着,您可能应该先尝试然后请求宽恕(尝试,除外)。这样做比对值进行大量检查要快得多。此外,那些打算使用你的程序的人应该很容易理解它是如何工作的;通过将逻辑业务与技术逻辑分开,无需这些检查即可轻松阅读。别担心,这并不明显,你问的事实表明你发现的东西不对 :)。

以下是我为您的案例提出的建议(这不是完美的解决方案!):

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

我举了一个例子,因为我相信你期待一个,但我不会给出完美的答案;)。您遇到的问题是设计问题,不,没有简单的解决方案。我向您建议的是首先假设顺序始终采用这种格式 [第 n 通道 X 样本大小](即 [4 通道 X 44100 样本])。这样,您首先像这样尝试(如 try/except),然后可能以相反的顺序进行尝试。

另一个建议(这实际上取决于您的用例)是创建一个数据结构 class 来将 FFT 数据操纵为 return 复数或 ReIm 或 AmPh0或 AmPh 作为吸气剂。 (因此您将输入数据视为始终是时间,而您只提供用户想要的)。

    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)

然后可以根据另一个 class 的所需输出来调用它,并使用 eval 来获得所需的输出(但您需要在代码中使用相同的约定 ;))。 2