def PSD(sig, fs=None, window='hann', window_length=8192, weighting=False, inputspec=True): """ Calculate Spectral Density Spectrum [W] Inputs: sig = time or spectrum - Default is spectrum fs = [Hz] sample frequency - only valid when time signal (inputspec=False) Outputs: F = [Hz] frequency bins PSD = [W?] Power spectral density - power per hertz Options: window = [string] name of windowtype - Only valid when inputspec is time (False) window_length = [-] length of window in number of samples - Only valid when inputspec is time (False) weighting = True/False Boolean for setting if a weighting is applied on spectrum - only valid when inputspec is time(False) inputspec = True/False Boolean for setting input as spectrum(True) or as time Signal(False) AS creates a single sided spectrum of Frequency and phase. There two possible input signals. a time signal and a spectral signal (complex or Real and Imaginair). When time signal is applied some extra parameters can be set. window and weighting. For window it is possible to set the window type and length of samples. default for this is hanning window and length of 8192 samples. after this the single sided power spectrum is created and returned. When input is a spectrum. it is checked for complex vallued signal and for symmetry. after this the single sided power spectrum is created and returned. """ if inputspec is True: from scripts.checks import istuple, even, odd, oddphase, phasecheck if istuple(sig): sig1phase = phasecheck(sig[1]) if sig1phase is True: sig0even = even(sig[0]) sig1odd = oddphase(sig[1]) if (sig0even is True) and (sig1odd is True): N = len(sig) F = np.arange(1, N / 2) PS = (sig[0][1:len(sig[0]) / 2] ** 2) / F # power per Hertz PH = sig[1][1:len(sig[1])/2] else: N = len(sig) F = np.arange(1, N / 2) PS = (sig[0] ** 2) / F # power per hertz PH = sig[1] else: sig0even = even(sig[0]) sig1odd = odd(sig[1]) if (sig0even is True) and (sig1odd is True): N = len(sig) F = np.arange(1, N/2) PS = (np.sqrt(sig[0][1:len(sig[0]) / 2] ** 2 + sig[1][1:len(sig[1]) / 2] ** 2) ** 2) / F PH = np.arctan2(sig[0][1:len(sig[0]) / 2], sig[1][1:len(sig[1]) / 2]) else: N = len(sig) F = np.arange(1, N / 2) PS = (np.sqrt(sig[0] ** 2 + sig[1] ** 2) ** 2) / F # power per hertz PH = np.arctan2(sig[0], sig[1]) elif np.iscomplex(sig): print('from complex spectum is becomming a magnitude pahse spectrum... \nshow olny N/2 frequency bins') N = len(sig) F = np.arange(1, N / 2) PSD = (abs(sig[1:N / 2]) ** 2) / F # power per hertz PH = np.arctan2(sig.real, sig.imag) elif inputspec is False: F, PSD, PH = AS(sig, fs, window, window_length, weighting, inputspec) PSD = (PSD ** 2) / F # Power per hertz - AS to PSD else: raise ValueError('inputspec should be True or False') return(F, PSD, PH)
def AS(sig, fs=None, window='hann', window_length=8192, weighting=False, inputspec=True): """ Calculate Amplitude Spectrum [v // g // ...] Inputs: sig = time or spectrum - Default is spectrum (Magnitude, Phase) fs = [Hz] sample frequency - only valid when time signal (inputspec=False) Outputs: F = [Hz] Frequency Array of given frequencies - only availeble in time input AS = [V, g,...] amplitude spectrum depends on input PH = [deg] phase output -180 - 180 degrees phase Options: window = [string] name of windowtype - Only valid when inputspec is time (False) window_length = [-] length of window in number of samples - Only valid when inputspec is time (False) weighting = True/False Boolean for setting if a weighting is applied on spectrum - only valid when inputspec is time(False) inputspec = True/False Boolean for setting input as spectrum(True) or as time Signal(False) AS creates a single sided spectrum of Frequency and phase. There two possible input signals. a time signal and a spectral signal (complex or Real and Imaginair). When time signal is applied some extra parameters can be set. window and weighting. For window it is possible to set the window type and length of samples. default for this is hanning window and length of 8192 samples. When window_length is set to None; no window will be applied after this the single sided amplitude spectrum is created and returned. When input is a spectrum. it is checked for complex vallued signal and for symmetry. after this the single sided amplitude spectrum is created and returned. """ if inputspec is True: from scripts.checks import istuple, even, odd, oddphase, phasecheck if istuple(sig): sig1phase = phasecheck(sig[1]) if sig1phase is True: sig0even = even(sig[0]) sig1odd = oddphase(sig[1]) if (sig0even is True) and (sig1odd is True): N = len(sig) F = np.arange(1, N / 2) AS = sig[0][1:len(sig[0])/2] PH = sig[1][1:len(sig[1])/2] else: N = len(sig) F = np.arange(1, N / 2) AS = sig[0] PH = sig[1] else: sig0even = even(sig[0]) sig1odd = odd(sig[1]) if (sig0even is True) and (sig1odd is True): N = len(sig) F = np.arange(1, N / 2) AS = np.sqrt(sig[0][1:len(sig[0]) / 2] ** 2 + sig[1][1:len(sig[1]) / 2] ** 2) PH = np.arctan2(sig[0][1:len(sig[0]) / 2], sig[1][1:len(sig[1]) / 2]) else: N = len(sig) F = np.arange(1, N / 2) AS = np.sqrt(sig[0] ** 2 + sig[1] ** 2) PH = np.arctan2(sig[0], sig[1]) elif np.iscomplex(sig): print('from complex spectum is becomming a magnitude pahse spectrum... \nshow olny N/2 frequency bins') N = len(sig) AS = abs(sig[1:N / 2]) PH = np.arctan2(sig.real, sig.imag) F = np.arange(1, N / 2) elif inputspec is False: if fs is not None: pass else: raise ValueError('value fs is \'None\' this should be changed') if (window_length is None) and (weighting is False): F, AS, PH = FFT(sig, fs, spectrum='AmPh0') elif (window_length is None) and (weighting is not False): F, AS, PH = FFT(sig, fs, spectrum='AmPh') elif isinstance(window_length, int) and (weighting is False): F, AS, PH = FFT(sig, fs, window, window_length, spectrum='AmPh0') elif isinstance(window_length, int) and (weighting is not False): F, AS, PH = FFT(sig, fs, window, window_length, spectrum='AmPh') if weighting is False: pass elif weighting is True: from scripts.weighting import AWeighting AS = AWeighting.A_Weighting(F, AS) elif weighting == 'A': from scripts.weighting import AWeighting AS = AWeighting.A_Weighting(F, AS) elif weighting == 'B': from scripts.weighting import BWeighting AS = BWeighting.B_Weighting(F, AS) elif weighting == 'C': from scripts.weighting import CWeighting AS = CWeighting.C_Weighting(F, AS) elif weighting == 'D': from scripts.weighting import DWeighting AS = DWeighting.D_Weighting(F, AS) else: raise ValueError('weighing should be True, False, or the letters A to D') else: raise ValueError('inputspec should be True or False') return(F, AS, PH)
def Transfer(x_in, x_out, fs): # possible some input paremeters addded later """ Inputs: x_in = input signal or recorded signal x_out = output signal or calculated signal fs = [Hz] sample frequency Output: H_0 = derived signal X_in / x_out Before makeing the transfer the input data is checked if it exist out the right information. This means the data have to be frequency specific data. This data exist out of amplitude and phase info from the form \' Real\' and \'Imaginair\' or complex data. transfer function is in case of in = microphone and out is ref signal: in signal in1 in2 blackbox out H = ---------- --> --- or --- is ------------ out signal out out blackbox in 2 Do: - Check complex values - check equal sized - if complex than no FFT """ # Tuple = FFT or wrong input # Compex valued signals = FFT # Nummeric is real valued and neeed FFT!! # else is wrong valued type and give error from scripts.checks import even, odd, oddphase, phasecheck if isinstance(x_in, tuple): if phasecheck(x_in[1]) == True: x_in0even = even(x_in[0]) # even symmetry x_in1phodd = oddphase(x_in[1]) # odd symmetry else: x_in0even = even(x_in[0]) # even symmetry x_in1odd = odd(x_in[1]) # odd symmetry print(x_in0even, x_in1odd) # make complex array if (x_in0even & x_in1odd): x_in = x_in[0] + 1j*x_in[1] elif (x_in0even & x_in1phodd): x_in = x_in[0]*np.sin(x_in[1]) + 1j * x_in[0]*np.cos(x_in[1]) if isinstance(x_out, tuple): x_out0even = even(x_out[0]) x_out1odd = odd(x_out[1]) # make complex array if (x_out0even & x_out1odd): x_out = x_out[0] + 1j*x_out[0] H_0 = x_in / x_out elif np.iscomplexobj(x_out): H_0 = x_in / x_out elif np.isrealobj(x_out): (X_OUT, F, _) = FFT(x_out, fs) H_0 = x_in / X_OUT else: raise TypeError("Wrong input type") elif np.iscomplexobj(x_in): if isinstance(x_out, tuple): x_in0even = even(x_in[0]) # even symmetry x_in1odd = odd(x_in[1]) # odd symmetry # make complex array if (x_out0even & x_out1odd): x_out = x_out[0] + 1j*x_out[0] H_0 = x_in / x_out elif np.iscomplexobj(x_out): H_0 = x_in / x_out elif np.isrealobj(x_out): (F, X_OUT, _) = FFT(x_out, fs) H_0 = x_in / X_OUT else: raise TypeError("Wrong input type") elif np.isrealobj(x_in): (F, X_IN, _) = FFT(x_in, fs) if isinstance(x_out, tuple): x_in0even = even(x_in[0]) # even symmetry x_in1odd = odd(x_in[1]) # odd symmetry # make complex array if (x_out0even & x_out1odd): x_out = x_out[0] + 1j*x_out[0] H_0 = X_IN / x_out elif np.iscomplexobj(x_out): H_0 = X_IN / x_out elif np.isrealobj(x_out): (F, X_OUT, _) = FFT(x_out, fs) H_0 = X_IN / X_OUT else: raise TypeError("Wrong input type") else: raise TypeError("Wrong input type") return(H_0)