def SCF_block(x,fs,a): ts=1.0/float(fs) l=len(x) n=num.array(range(l)) u=num.exp(-1j*num.pi*a*n*ts)*x v=num.exp(1j*num.pi*a*n*ts)*x scf,f=csd(u,v) uu,f=csd(u,u) vv,f=csd(v,v) Saf=abs(scf)/(abs(uu)*abs(vv))**.5 return max(Saf)
def SCF(z,fs,a=0): # this implementation is based on cross spectrum between u and v N=len(z) m=range(-N/2,N/2) u=num.array([z[k]*num.exp(-1j*num.pi*a*m[k]/fs) for k in range(N)]) v=num.array([z[k]*num.exp(1j*num.pi*a*m[k]/fs) for k in range(N)]) scfuv,freq=csd(v,u) scfu,freq=csd(u,u) scfv,freq=csd(v,v) scf=abs(scfuv)/((abs(scfu))*(abs(scfv)))**.5 return scf,freq
def test_csd_padding(self): """Test zero padding of csd().""" if self.NFFT_density is None: # for derived classes return sargs = dict(x=self.y, y=self.y+1, Fs=self.Fs, window=mlab.window_none, sides=self.sides) spec0, _ = mlab.csd(NFFT=self.NFFT_density, **sargs) spec1, _ = mlab.csd(NFFT=self.NFFT_density*2, **sargs) assert_almost_equal(np.sum(np.conjugate(spec0)*spec0).real, np.sum(np.conjugate(spec1/2)*spec1/2).real)
def tfe(y, x, source=None, *args, **kwargs): """estimate transfer function from x to y, see csd for calling convention""" if source is None: sxy, fxy = csd(y, x, *args, **kwargs) sxx, fxx = psd(x, *args, **kwargs) return sxy / sxx, fxx else: ssx, fsx = csd(x, source, *args, **kwargs) # sss, _ = psd(s, *args, **kwargs) ssy, fsy = csd(y, source, *args, **kwargs) return ssy / ssx, fsx
def preprocess(self, data): n_channels, _ = np.shape(data) _, _, filtered = analytic_signal(data, self.fb, self.fs) super().prepare_pairs(n_channels) # Store all the pair-wise auto/cross spectra. # 2nd axis, 1st dimension is the autospectra of the 1st channel (within a pair) # 2nd axis, 2nd dimension is the autospectra of the 2nd channel (within a pair) # 2nd axis, 3rd dimension is the crosspectra between the two channels (within a pair) samples = (self.csd_nfft / 2.0) + 1 csds = np.zeros((n_channels, n_channels, 3, samples)) for pair in self.pairs: filt1, filt2 = filtered[pair, ] csdxx, _ = mlab.csd( filt1, filt1, NFFT=self.csd_nfft, Fs=self.fs, noverlap=self.csd_noverlap, scale_by_freq=True, sides="onesided", ) csdyy, _ = mlab.csd( filt2, filt2, NFFT=self.csd_nfft, Fs=self.fs, noverlap=self.csd_noverlap, scale_by_freq=True, sides="onesided", ) csdxy, _ = mlab.csd( filt1, filt2, NFFT=self.csd_nfft, Fs=self.fs, noverlap=self.csd_noverlap, scale_by_freq=True, sides="onesided", ) r1, r2 = pair csds[r1, r2, 0] = csdxx csds[r1, r2, 1] = csdyy csds[r1, r2, 2] = csdxy return csds
def getTF(exc, resp, tmeas, Fs, Nfft, padto=None): """ compute transfer function along with coherence and SNR. uses PSD/CSD method with 50% overlapping windows returns f, TF, Coherence, SNR exc = excitation signal resp = system response tmeas = duration of mesurement in seconds Fs = sample rate (Hz) Nfft = number of data points to be used in each block for fft padto = pad to this many points """ N = 1.89 * tmeas / (Nfft / Fs) Sx, f = psd(exc, NFFT=Nfft, Fs=Fs, noverlap=int(Nfft / 2), pad_to=padto) Sy = psd(resp, NFFT=Nfft, Fs=Fs, noverlap=int(Nfft / 2), pad_to=padto)[0] Sxy = csd(exc, resp, NFFT=Nfft, Fs=Fs, noverlap=int(Nfft / 2), pad_to=padto)[0] Cxy = (Sxy * np.conj(Sxy)) / (Sx * Sy) snr = np.sqrt(Cxy * 2 * N / (1 - Cxy)) return f, Sxy / Sx, Cxy, snr
def get_cross_spectra(self, x, y): ''' Compute cross-spectra between x and y using the method implemented in matplotlib.mlab.csd Arguments --------- *x*, *y* : np.ndarray signals, shape (n_x/n_y, T), n_x/n_y is number of signals, T the number of samples Returns ------- *C_xy* : np.ndarray complex array if shape (n_x, n_y, NFFT) containing the cross-spectra ''' n_x = x.shape[0] n_y = y.shape[0] #try: # assert(n_x >= n_y) #except AssertionError as ae: # raise ae, 'n_x = {} < n_y = {}'.format(n_x, n_y) #compute cross-spectra C_xy = np.empty((n_x, n_y, self.NFFT), dtype=complex) for i in range(n_x): for j in range(n_y): G, f = csd(x[i, ], y[j, ], NFFT=self.NFFT, Fs=self.Fs, noverlap=self.noverlap, sides='twosided') C_xy[i, j, ] = G return C_xy
def cp(tr1, tr2, lenfft, lenol, delta): # Cross-power function sr = 1./float(delta) cpval,fre = csd(tr1.data, tr2.data, NFFT=lenfft, Fs=sr, noverlap=int(lenol*lenfft), scale_by_freq=True) fre = fre[1:] cpval = cpval[1:] return cpval, fre
def csd(self, plot=True, nbandavg=1, **kwargs): """ Cross spectral density nbandavg = Number of fft bins to average """ if self.isequal == False and self.VERBOSE: print( 'Warning - time series is unequally spaced consider using lomb-scargle fft' ) NFFT = int(2**(np.floor(np.log2( self.ny / nbandavg)))) # Nearest power of 2 to length of data Pyy, frq = mlab.csd(self.TSobs.y - self.TSobs.y.mean(), Fs=2 * np.pi / self.dt, NFFT=NFFT, window=mlab.window_hanning, scale_by_freq=True) if plot: plt.loglog(frq, Pyy, **kwargs) plt.xlabel('Freq. [$cycles s^{-1}$]') plt.ylabel('PSD') plt.grid(b=1) return Pyy, frq
def cohere_transfere_MI (convolved_train, wNoise, nFFT, FS): """ Function computes coherence, mutual information from coherence, transfer function and cross-power-spectra density and power spectra density. Function computes the same for whole signal and only for the steady state portion (_short) :param metas: meta data :param convolved_train: convolved spike train :param wNoise: white noise :param nFFT: FFT :param FS: sample rate :return coh: computed coherence :return coh_short: :return freq: :return MI: :return MI_short: :return P_csd: :return P_csd_short: :return P_psd: :return P_csd_short: """ # conversions w. clipping first 2 seconds wNoiseShort = wNoise[2*FS:] conv_train_short = convolved_train[2*FS:] # compute coherence coh, freq = mlab.cohere(wNoise-np.mean(wNoise), convolved_train-np.mean(convolved_train), NFFT=nFFT, Fs=FS) coh_short, _ = mlab.cohere(wNoiseShort-np.mean(wNoiseShort), conv_train_short-np.mean(conv_train_short), NFFT=nFFT, Fs=FS) # calculate the mutual information MI = (-np.log(1-coh))/np.log(2) MI_short = (-np.log(1-coh_short))/np.log(2) # compute csd P_csd, _ = mlab.csd(wNoise, convolved_train, NFFT=nFFT, Fs=FS) P_csd_short, _ = mlab.csd(wNoiseShort, conv_train_short, NFFT=nFFT, Fs=FS) if np.any(np.absolute(P_csd_short) < 0): print("negative CSD") # compute psd P_psd,_ = mlab.psd(wNoise,NFFT=nFFT, Fs=FS) P_psd_short,_ = mlab.psd(wNoiseShort,NFFT=nFFT, Fs=FS) # compute the transfer function H = np.absolute(P_csd)/P_psd H_short = np.absolute(P_csd_short)/P_psd_short return freq, coh, coh_short, H, H_short, MI, MI_short, P_csd, P_csd_short, P_psd, P_psd_short
def preprocess(self, data): n_channels, n_samples = np.shape(data) filtered, _, _ = analytic_signal(data, self.fb, self.fs) if self.pairs is None: self.pairs = [(r1, r2) for r1 in range(n_channels) for r2 in range(n_channels)] # Store all the pair-wise auto/cross spectra. # 2nd axis, 1st dimension is the autospectra of the 1st channel (within a pair) # 2nd axis, 2nd dimension is the autospectra of the 2nd channel (within a pair) # 2nd axis, 3rd dimension is the crosspectra between the two channels (within a pair) samples = (self.csd_nfft / 2.0) + 1 csds = np.zeros((n_channels, n_channels, 3, samples)) for pair in self.pairs: filt1, filt2 = filtered[pair, ] csdxx, _ = mlab.csd(filt1, filt1, NFFT=self.csd_nfft, Fs=self.fs, noverlap=self.csd_noverlap, scale_by_freq=True, sides='onesided') csdyy, _ = mlab.csd(filt2, filt2, NFFT=self.csd_nfft, Fs=self.fs, noverlap=self.csd_noverlap, scale_by_freq=True, sides='onesided') csdxy, _ = mlab.csd(filt1, filt2, NFFT=self.csd_nfft, Fs=self.fs, noverlap=self.csd_noverlap, scale_by_freq=True, sides='onesided') r1, r2 = pair csds[r1, r2, 0, ] = csdxx csds[r1, r2, 1, ] = csdyy csds[r1, r2, 2, ] = csdxy return csds
def binned_pair2cxy(binned0, binned1, Fs=1000., NFFT=256, noverlap=None, windw=mlab.window_hanning, detrend=mlab.detrend_mean, freq_high=100, average_over_trials=True): """Given 2d array of binned times, return Cxy Helper function to ensure faking goes smoothly binned: 2d array, trials on rows, timepoints on cols Keep trials lined up! rest : psd_kwargs. noverlap defaults to NFFT/2 Trial averaging, if any, is done between calculating the spectra and normalizing them. Will Cxy each trial with psd_kwargs, then mean over trials, then slice out frequencies below freq_high and return. """ # Set up psd_kwargs if noverlap is None: noverlap = NFFT / 2 psd_kwargs = { 'Fs': Fs, 'NFFT': NFFT, 'noverlap': noverlap, 'detrend': detrend, 'window': windw } # Cxy each trial ppxx_l, ppyy_l, ppxy_l = [], [], [] for row0, row1 in zip(binned0, binned1): ppxx, freqs = mlab.psd(row0, **psd_kwargs) ppyy, freqs = mlab.psd(row1, **psd_kwargs) ppxy, freqs = mlab.csd(row0, row1, **psd_kwargs) ppxx_l.append(ppxx) ppyy_l.append(ppyy) ppxy_l.append(ppxy) # Optionally mean over trials, then normalize S12 = np.real_if_close(np.array(ppxy_l)) S1 = np.array(ppxx_l) S2 = np.array(ppyy_l) if average_over_trials: S12 = S12.mean(0) S1 = S1.mean(0) S2 = S2.mean(0) Cxy = S12 / np.sqrt(S1 * S2) # Truncate unnecessary frequencies if freq_high: topbin = np.where(freqs > freq_high)[0][0] freqs = freqs.T[1:topbin].T Cxy = Cxy.T[1:topbin].T return Cxy, freqs
def cp(tr1, tr2): cpval, fre = csd(tr1.data, tr2.data, NFFT=length, Fs=tr1.stats.sampling_rate, noverlap=overlap, scale_by_freq=True) return cpval[1:], fre[1:]
def DifResMlabCsd(data1, data2, fs): P1, f1 = mlab.csd(data1, data2, len(data1), Fs=fs, window=mlab.window_hanning) P2, f2 = mlab.csd(data1, data2, len(data1) / 10, Fs=fs, window=mlab.window_hanning) P3, f3 = mlab.csd(data1, data2, len(data1) / 100, Fs=fs, window=mlab.window_hanning) return f1, P1, f2, P2, f3, P3
def espec2(x,y,nfft,fs): """ # ================================================================================== # # # Calcula o espectro cruzado entre duas series reais # # Dados de entrada: x = serie real 1 (potencia de 2) # y = serie real 2 (potencia de 2) # nfft - Numero de pontos utilizado para o calculo da FFT # fs - frequencia de amostragem # # Dados de saida: [aa2] - col 0: vetor de frequencia # col 1: amplitude do espectro cruzado # col 2: co-espectro # col 3: quad-espectro # col 4: espectro de fase # col 5: espectro de coerencia # col 6: intervalo de confianca inferior do espectro cruzado # col 7: intervalo de confianca superior do espectro cruzado # col 8: intervalo de confianca da coerencia # # Infos: detrend - mean # window - hanning # noverlap - 50% # # ================================================================================== # """ #cross-spectral density - welch method (complex valued) sp = mlab.csd(x,y,NFFT=nfft,Fs=fs,detrend=mlab.detrend_mean,window=mlab.window_hanning,noverlap=nfft/2) f = sp[1][1:] sp2 = sp[0][1:] #co e quad espectro (real e imag) - verificar com parente co = np.real(sp2) qd = np.imag(sp2) #phase (angle function) ph = np.angle(sp2,deg=True) #ecoherence between x and y (0-1) coer = mlab.cohere(x,y,NFFT=nfft,Fs=fs,detrend=mlab.detrend_mean,window=mlab.window_hanning,noverlap=nfft/2) coer = coer[0][1:] #intervalo de confianca para a amplitude do espectro cruzado - 95% ici = sp2 * 14 /26.12 ics = sp2 * 14 /5.63 #intervalo de confianca para coerencia icc = np.zeros(len(sp2)) icc[:] = 1 - (0.05 ** (1 / (14 / 2.0 - 1))) aa2 = np.array([f,sp2,co,qd,ph,coer,ici,ics,icc]).T return aa2
def auto_auto_cross(a, b, sample_rate, NFFT=None, detrend=mlab.detrend_none, window=mlab.window_none, noverlap=None, binned=True, bins_per_decade=30, **kwds): """ Return estimates of the auto-spectral density of both real time series a and b, of their cross-spectral density, and the frequencies corresponding to these estimates. Parameters ---------- a : ndarray(real) A real time series. b : ndarray(real) A real time series. sample_rate : float The sample rate of both time series. NFFT : int The number of samples to use for each FFT chunk; should be a power of two for speed; if None, a reasonable default is used. window : callable A function that takes a complex time series as argument and returns a windowed time series. noverlap : int The number of samples to overlap in each chunk; if None, a value equal to half the NFFT value is used. detrend : callable A function that takes a complex time series as argument and returns a detrended time series. binned : bool If True, the result is binned using bin sizes that increase with frequency, and the bins at zero frequency and the Nyquist frequency are dropped. bins_per_decade : int The number of bins per decade; used only if binned is True. kwds : dict Additional keywords to pass to mlab.psd and mlab.csd. Returns ------- f : ndarray(float) The frequencies corresponding to the data. S_aa : ndarray(float) The spectral density of a. S_bb : ndarray(float) The spectral density of b. S_ab : ndarray(complex) The cross-spectral density of a and b. """ if NFFT is None: NFFT = int(2 ** (np.floor(np.log2(a.size)) - 3)) if noverlap is None: noverlap = NFFT // 2 S_aa, f = mlab.psd(a, Fs=sample_rate, NFFT=NFFT, detrend=detrend, window=window, noverlap=noverlap, **kwds) S_bb, f = mlab.psd(b, Fs=sample_rate, NFFT=NFFT, detrend=detrend, window=window, noverlap=noverlap, **kwds) S_ab, f = mlab.csd(a, b, Fs=sample_rate, NFFT=NFFT, window=window, detrend=detrend, noverlap=noverlap, **kwds) if binned: f = f[1:-1] S_aa = S_aa[1:-1] S_bb = S_bb[1:-1] S_ab = S_ab[1:-1] edges, counts, f, (S_aa, S_bb, S_ab) = binning.log_bin(f, bins_per_decade, S_aa, S_bb, S_ab) return AutoAutoCross(f, S_aa, S_bb, S_ab)
def crossCalib(monitor_trace, response_trace, **kwargs): m_trace=monitor_trace.copy() r_trace=response_trace.copy() if 'demean' in kwargs and kwargs['demean']: m_trace.detrend('demean') r_trace.detrend('demean') if 'taper' in kwargs and kwargs['taper']: m_trace.taper(0.05) r_trace.taper(0.05) #Paramètres des PSD if 'nfft' in kwargs: n_fft=kwargs['nfft'] else: n_fft=1024 if 'npad' in kwargs: n_pad=kwargs['npad'] else: n_pad=n_fft*4 if 'noverlap' in kwargs: n_overlap=kwargs['noverlap'] else: n_overlap=int(n_fft*0.90) #paz par défaut: chaine générique if 'paz' in kwargs: paz=kwargs['paz'] else: paz=dict() paz['zeros']=np.array([]) paz['poles']=np.array([]) paz['gain']=1 paz['seismometer_gain']=1 paz['datalogger_gain']=1 paz['sensitivity']=paz['seismometer_gain']*paz['datalogger_gain']*paz['gain'] fs=m_trace.stats.sampling_rate (P00,f)=mlab.psd(m_trace.data,Fs=fs,NFFT=n_fft,noverlap=n_overlap,pad_to=n_pad,detrend=mlab.detrend_mean,window=mlab.window_hanning) (P01,f)=mlab.csd(m_trace.data,r_trace.data,Fs=fs,NFFT=n_fft,noverlap=n_overlap,pad_to=n_pad,detrend=mlab.detrend_mean,window=mlab.window_hanning) (C,f)=mlab.cohere(m_trace.data,r_trace.data,Fs=fs,NFFT=n_fft,noverlap=n_overlap,pad_to=n_pad,detrend=mlab.detrend_mean,window=mlab.window_hanning) (b,a)=sp.zpk2tf(paz['zeros'],paz['poles'],paz['sensitivity']) (_w,H0)=sp.freqs(b,a,f*2*np.pi) H1=P01*H0/P00 H1=H1[1:] C=C[1:] f=f[1:] return (H1,C,f)
def test_csd(self): freqs = self.freqs_density spec, fsp = mlab.csd(x=self.y, y=self.y+1, NFFT=self.NFFT_density, Fs=self.Fs, noverlap=self.nover_density, pad_to=self.pad_to_density, sides=self.sides) assert_allclose(fsp, freqs, atol=1e-06) assert spec.shape == freqs.shape
def cp(tr1, tr2, lenfft, lenol, delta): sr = 1 / delta cpval, fre = csd(tr1.data, tr2.data, NFFT=lenfft, Fs=sr, noverlap=lenol, scale_by_freq=True) fre = fre[1:] cpval = cpval[1:] return cpval, fre
def espec2(x, y, nfft, fs): """ Calcula o espectro cruzado entre duas series reais Dados de entrada: x = serie real 1 (potencia de 2) y = serie real 2 (potencia de 2) nfft - Numero de pontos utilizado para o calculo da FFT fs - frequencia de amostragem Dados de saida: [aa2] - col 0: vetor de frequencia col 1: amplitude do espectro cruzado col 2: co-espectro col 3: quad-espectro col 4: espectro de fase col 5: espectro de coerencia col 6: intervalo de confianca inferior do espectro cruzado col 7: intervalo de confianca superior do espectro cruzado col 8: intervalo de confianca da coerencia Infos: detrend - mean window - hanning noverlap - 50% """ #cross-spectral density - welch method (complex valued) s, f = mlab.csd(x, y, NFFT=nfft, Fs=fs, detrend=mlab.detrend_mean, window=mlab.window_hanning, noverlap=nfft/2) # graus de liberdade dof = len(x) / nfft * 2 #co e quad espectro (real e imag) - verificar com parente co = np.real(s) qd = np.imag(s) #phase (angle function) ph = np.angle(s, deg=True) #ecoherence between x and y (0-1) coer = mlab.cohere(x, y, NFFT=nfft, Fs=fs, detrend=mlab.detrend_mean, window=mlab.window_hanning, noverlap=nfft/2)[0] # coer = coer[0][1:] #intervalo de confianca para a amplitude do espectro cruzado - 95% ici = s * dof /26.12 ics = s * dof /5.63 #intervalo de confianca para coerencia icc = np.zeros(len(s)) icc[:] = 1 - (0.05 ** (1 / (14 / 2.0 - 1))) # matriz de saida aa = np.array([f, s ,co, qd, ph, coer, ici, ics, icc]).T return aa
def test_full_spectral_helper(): x = np.random.randn(2 ** 20) y = np.random.randn(2 ** 20) mlabPxx, fr = mlab.psd(x, NFFT=2 ** 16, Fs=512e6 / 2 ** 14) mlabPyy, fr = mlab.psd(y, NFFT=2 ** 16, Fs=512e6 / 2 ** 14) mlabPxy, fr = mlab.csd(x, y, NFFT=2 ** 16, Fs=512e6 / 2 ** 14) with warnings.catch_warnings(): warnings.simplefilter('ignore', np.ComplexWarning) fullPxx, fullPyy, fullPxy, freqs, t = full_spectral_helper(x, y, NFFT=2 ** 16, Fs=512e6 / 2 ** 14) assert (np.allclose(mlabPxx, fullPxx.mean(1))) assert (np.allclose(mlabPyy, fullPyy.mean(1))) assert (np.allclose(mlabPxy, fullPxy.mean(1)))
def calc_spectra(x, y, sr, nfft = None): # expects two 1d arrays as signals and a number for the sampling rate # (optional) parameters for FFT # returns PSD(x,x), PSD(y,y), PSD(x,y), PSD(y,x) and frequency if nfft is None: nfft = 2 ** 11 params = {'NFFT': nfft, 'noverlap': nfft / 2} if not isinstance(params, dict): print('ERROR: params in calc_spectra() is not a dictionary.') x = x - mean(x) y = y - mean(y) Pxx, _ = ml.psd(x, Fs=sr, **params) Pyy, _ = ml.psd(y, Fs=sr, **params) Pxy, _ = ml.csd(x, y, Fs=sr, **params) Pyx, _ = ml.csd(y, x, Fs=sr, **params) ml_coherence, f = ml.cohere(x, y, Fs=sr, **params) return Pxx, Pyy, Pxy, Pyx, ml_coherence, f
def est_s(s, r, nfft=2**12): ''' Q_rs = numpy.correlate(r_est, s,'full') Q_rr = numpy.correlate(r_est, r_est,'full') Qf_rs = numpy.fft.fftpack.rfft(Q_rs,nfft) Qf_rr = numpy.fft.fftpack.rfft(Q_rr,nfft) ''' Qf_rs = mlab.csd(r, s, nfft) Qf_rr = mlab.csd(r, r, nfft) Txy = Qf_rs[0] / Qf_rr[0] T = numpy.array(Txy.tolist() + Txy[::-1].conj()[1:-1].tolist()) k = numpy.fft.fftshift(numpy.fft.ifft(T).real) ''' s_est = fftfilt(k,r) s_est = s_est[nfft/2:] ''' s_est = numpy.convolve(r, k, 'full') s_est = s_est[nfft / 2:-nfft / 2 + 1] return s_est, Txy, T, k
def getspectra(string): try: #if True: debug = True lenfft = 20000 resppath = '/APPS/metadata/RESPS/' stringTEMP = string.split('_') net = stringTEMP[0] sta = stringTEMP[1] loc = stringTEMP[2] chan = stringTEMP[3] year = stringTEMP[4] jday = stringTEMP[5] if debug: print 'Working on: ' + net + ' ' + sta + ' ' + loc + ' ' + chan stime = UTCDateTime(year + '-' + jday + "T00:00:00") st = client.timeseries(net, sta, loc, chan, stime, stime + 24*60*60) if debug: print(st) if len(st) == 1: power,freq = csd(st[0].data,st[0].data, NFFT = lenfft, noverlap = int(lenfft*.5), Fs = 1/st[0].stats.delta, scale_by_freq = True) power = power[1:].real freq = freq[1:] resp = evalresp(t_samp = st[0].stats.delta, nfft = lenfft, filename= resppath + 'RESP.' + net + '.' + \ sta + '.' + loc + '.' + chan, date = st[0].stats.starttime, station = sta, channel = chan, network = net, locid = loc, units = 'ACC') resp = resp[1:] power = 10.*np.log10(power/np.absolute(resp*np.conjugate(resp))) else: power =[] freq=[] if len(power) > 1: if debug: print 'Writing data for: ' + string if not os.path.exists('/TEST_ARCHIVE/PSDS/' + sta): os.makedirs('/TEST_ARCHIVE/PSDS/' + sta) if not os.path.exists('/TEST_ARCHIVE/PSDS/' + sta + '/' + year): os.makedirs('/TEST_ARCHIVE/PSDS/' + sta + '/' + year) fpsd = open('/TEST_ARCHIVE/PSDS/' + sta + '/' + year + '/PSD_' + string,'w') for p,f in zip(power,freq): fpsd.write(str(p) + ', ' + str(f) + '\n') fpsd.close() except: print 'Unable to process: ' + string return
def estimate_pair(self, ts1, ts2): csdxx, _ = mlab.csd(x=ts1, y=ts1, Fs=self.fs, scale_by_freq=True, sides="onesided", **self.csdargs) csdyy, _ = mlab.csd(x=ts2, y=ts2, Fs=self.fs, scale_by_freq=True, sides="onesided", **self.csdargs) csdxy, _ = mlab.csd(x=ts1, y=ts2, Fs=self.fs, scale_by_freq=True, sides="onesided", **self.csdargs) cohv = np.abs(csdxy * np.conj(csdxy)) / (csdxx * csdyy) return np.sum(cohv) / len(cohv)
def test_psd_csd_equal(self): Pxx, freqsxx = mlab.psd(x=self.y, NFFT=self.NFFT_density, Fs=self.Fs, noverlap=self.nover_density, pad_to=self.pad_to_density, sides=self.sides) Pxy, freqsxy = mlab.csd(x=self.y, y=self.y, NFFT=self.NFFT_density, Fs=self.Fs, noverlap=self.nover_density, pad_to=self.pad_to_density, sides=self.sides) assert_array_almost_equal_nulp(Pxx, Pxy) assert_array_equal(freqsxx, freqsxy)
def _spectral_density(x, y, Fs, Nf, Nens, Npts_per_real, Npts_overlap, Npts_per_ens, detrend, window, print_status=False, status_label=''): 'Get spectral density of provided signals.' same_data = x is y # Initialize spectral density array if not same_data: # Cross-spectral density is intrinsically complex-valued, so # we must initialize the spectral density as a complex-valued # array to avoid loss of information Gxy = np.zeros([Nf, Nens], dtype=np.complex128) else: # Autospectral density is intrinsically real-valued # (assuming `x` is real-valued), so we don't need the # overhead of a complex-valued array Gxy = np.zeros([Nf, Nens]) if print_status: print '' # Loop over successive ensembles for ens in np.arange(Nens): # Create a slice corresponding to current ensemble ens_start = ens * Npts_per_ens ens_stop = (ens + 1) * Npts_per_ens sl = slice(ens_start, ens_stop) if same_data: Gxy[:, ens] = mlab.psd( x[sl], Fs=Fs, NFFT=Npts_per_real, noverlap=Npts_overlap, detrend=detrend, window=window)[0] else: Gxy[:, ens] = mlab.csd( x[sl], y[sl], Fs=Fs, NFFT=Npts_per_real, noverlap=Npts_overlap, detrend=detrend, window=window)[0] if print_status: print ('%s percent complete: %.1f \r' % (status_label, (100 * np.float(ens + 1) / Nens))), if print_status: print '' return Gxy
def get_coherence_phase(s1, s2, sampling=5000): """ Gets the phase angle of the coherence between two signals Input: s1,s2: two time series sampling: the sampling of the signal [def: 5000] Output: Psi: phase in radians f: frequencies """ from matplotlib.mlab import csd from numpy import angle Pxy, freqs = csd(s1, s2, NFFT=256, Fs=sampling) return angle(Pxy), freqs
def test_full_spectral_helper(): x = np.random.randn(2**20) y = np.random.randn(2**20) mlabPxx, fr = mlab.psd(x, NFFT=2**16, Fs=512e6 / 2**14) mlabPyy, fr = mlab.psd(y, NFFT=2**16, Fs=512e6 / 2**14) mlabPxy, fr = mlab.csd(x, y, NFFT=2**16, Fs=512e6 / 2**14) with warnings.catch_warnings(): warnings.simplefilter('ignore', np.ComplexWarning) fullPxx, fullPyy, fullPxy, freqs, t = full_spectral_helper(x, y, NFFT=2**16, Fs=512e6 / 2**14) assert (np.allclose(mlabPxx, fullPxx.mean(1))) assert (np.allclose(mlabPyy, fullPyy.mean(1))) assert (np.allclose(mlabPxy, fullPxy.mean(1)))
def get_coherence_phase(s1,s2,sampling=5000): """ Gets the phase angle of the coherence between two signals Input: s1,s2: two time series sampling: the sampling of the signal [def: 5000] Output: Psi: phase in radians f: frequencies """ from matplotlib.mlab import csd from numpy import angle Pxy, freqs = csd( s1,s2, NFFT = 256, Fs = sampling ) return angle( Pxy ), freqs
def xps(s1,s2, Fs,minfreq=None): """ like nps, but for cross spectra: returns two vectors, frequencies and PSD PSD is in units^s/Hz """ if minfreq != None: nfft=np.min([len(s1),np.int(2.*Fs/minfreq)]) nfft=2**(np.int(np.log2(nfft))) elif minfreq == None: nfft=len(s1) nfft=2**(np.int(np.log2(nfft))) Pxx, freqs = mlab.csd(s1,s2, NFFT=nfft, Fs = Fs) #we hate zero frequency freqs=freqs[1:] Pxx=Pxx[1:] return freqs, Pxx
def xps(s1, s2, Fs, minfreq=None): """ like nps, but for cross spectra: returns two vectors, frequencies and PSD PSD is in units^s/Hz """ if minfreq != None: nfft = np.min([len(s1), np.int(2. * Fs / minfreq)]) nfft = 2**(np.int(np.log2(nfft))) elif minfreq == None: nfft = len(s1) nfft = 2**(np.int(np.log2(nfft))) Pxx, freqs = mlab.csd(s1, s2, NFFT=nfft, Fs=Fs) #we hate zero frequency freqs = freqs[1:] Pxx = Pxx[1:] return freqs, Pxx
def binned_pair2cxy(binned0, binned1, Fs=1000., NFFT=256, noverlap=None, windw=mlab.window_hanning, detrend=mlab.detrend_mean, freq_high=100, average_over_trials=True): """Given 2d array of binned times, return Cxy Helper function to ensure faking goes smoothly binned: 2d array, trials on rows, timepoints on cols Keep trials lined up! rest : psd_kwargs. noverlap defaults to NFFT/2 Trial averaging, if any, is done between calculating the spectra and normalizing them. Will Cxy each trial with psd_kwargs, then mean over trials, then slice out frequencies below freq_high and return. """ # Set up psd_kwargs if noverlap is None: noverlap = NFFT / 2 psd_kwargs = {'Fs': Fs, 'NFFT': NFFT, 'noverlap': noverlap, 'detrend': detrend, 'window': windw} # Cxy each trial ppxx_l, ppyy_l, ppxy_l = [], [], [] for row0, row1 in zip(binned0, binned1): ppxx, freqs = mlab.psd(row0, **psd_kwargs) ppyy, freqs = mlab.psd(row1, **psd_kwargs) ppxy, freqs = mlab.csd(row0, row1, **psd_kwargs) ppxx_l.append(ppxx); ppyy_l.append(ppyy); ppxy_l.append(ppxy) # Optionally mean over trials, then normalize S12 = np.real_if_close(np.array(ppxy_l)) S1 = np.array(ppxx_l) S2 = np.array(ppyy_l) if average_over_trials: S12 = S12.mean(0) S1 = S1.mean(0) S2 = S2.mean(0) Cxy = S12 / np.sqrt(S1 * S2) # Truncate unnecessary frequencies if freq_high: topbin = np.where(freqs > freq_high)[0][0] freqs = freqs.T[1:topbin].T Cxy = Cxy.T[1:topbin].T return Cxy, freqs
def estimate_decoder(time, s, r, dt, nfft=2**12): ''' Estimates the decoding kernel K and reconstructs the original stimuls Inputs: time: time vector s: stimulus r: response dt: sampling period nfft: number of datapoints to be used for spectral estimation (window length) Outputs: k: the decoding kernel (length of the nfft) k_time: the time vector of the decoding kernel (length of the nfft) s_est: the estimated stimulus (length of s and r minus a window length) s_est_time: time vector for s_est NOTE: we discard data points 0:nfft/2 and -nnft2:end due to boundary effects ''' Fs = 1 / dt # sampling frequency # compute the cross spectrum between response and stimulus Qf_rs, freqs = mlab.csd(r, s, nfft, Fs=Fs) Qf_rs *= dt # computes the response power spectrum Qf_rr, freqs = mlab.psd(r, nfft, Fs=Fs) Qf_rr *= dt # take the ratio Kf = Qf_rs / Qf_rr # we need to add negative frequency with (conjugate values) to comply to the input # requirements of the ifft function Kf = np.hstack([Kf, Kf[::-1].conj()[1:-1]]) k = np.fft.fftshift(np.fft.ifft(Kf).real) / dt k_time = (np.arange(nfft) - int(nfft / 2)) * dt # compute estimated stimulus s_est = np.convolve(r, k, 'same') * dt # crop s_est and time vector appropriately s_est = s_est[int(nfft / 2):int(-nfft / 2)] s_est_time = time[int(nfft / 2):int(-nfft / 2)] - dt return k, k_time, s_est, s_est_time
def pca_noise_with_errors(d, NFFT, Fs, window=mlab.window_hanning, detrend=mlab.detrend_mean, use_log_bins=True): # Assume the rotation is small so that the variance can be approximated using the values in the pre-PCA spectra. # Take the variance to be the square of the power in each bin, divided by the number of averaged spectra. n_averaged = d.size / NFFT pii, pf = mlab.psd(d.real, NFFT=NFFT, Fs=Fs, window=window, detrend=detrend) pqq, pf = mlab.psd(d.imag, NFFT=NFFT, Fs=Fs, window=window, detrend=detrend) piq, pf = mlab.csd(d.real, d.imag, NFFT=NFFT, Fs=Fs, window=window, detrend=detrend) if use_log_bins: bf, bc_ii, (bp_ii, bvar_ii) = binning.log_bin_with_variance(pf, pii, pii ** 2 / n_averaged) bf, bc_qq, (bp_qq, bvar_qq) = binning.log_bin_with_variance(pf, pqq, pqq ** 2 / n_averaged) bf, bc_iq, (bp_iq, bvar_iq) = binning.log_bin_with_variance(pf, piq, np.abs(piq) ** 2 / n_averaged) # probably not right S, evals, evects, angles = calculate_pca_noise(bp_ii, bp_qq, bp_iq) return bf, S, evals, evects, angles, (bp_ii, bp_qq, bp_iq), bc_ii, np.vstack((bvar_qq, bvar_ii)) else: S, evals, evects, angles = calculate_pca_noise(pii, pqq, piq) return (pf, S, evals, evects, angles, (pii, piq, piq), np.ones_like(pf), np.vstack((pqq**2 / n_averaged, pii**2 / n_averaged)))
def compute_mean_psd_csd(x, y, n_epochs, nfft, sfreq): '''Computes mean of PSD and CSD for signals.''' x2 = np.array_split(x, n_epochs) y2 = np.array_split(y, n_epochs) Rxy = np.zeros((n_epochs, n_freqs), dtype=np.complex) Rxx = np.zeros((n_epochs, n_freqs), dtype=np.complex) Ryy = np.zeros((n_epochs, n_freqs), dtype=np.complex) for i in range(n_epochs): Rxy[i], freqs = mlab.csd(x2[i], y2[i], NFFT=nfft, Fs=sfreq) Rxx[i], _ = mlab.psd(x2[i], NFFT=nfft, Fs=sfreq) Ryy[i], _ = mlab.psd(y2[i], NFFT=nfft, Fs=sfreq) Rxy_mean = np.mean(Rxy, axis=0) Rxx_mean = np.mean(Rxx, axis=0) Ryy_mean = np.mean(Ryy, axis=0) return freqs, Rxy, Rxy_mean, np.real(Rxx_mean), np.real(Ryy_mean)
def calculate(self, NFFT=2**16, thresh=0.95): self.pxx1, self.freq = mlab.psd(self.corrected_timeseries1.real, NFFT=NFFT, Fs=self.timeseries_sample_rate) self.pii1, self.freq = mlab.psd(self.corrected_timeseries1.imag, NFFT=NFFT, Fs=self.timeseries_sample_rate) self.pxx2, self.freq = mlab.psd(self.corrected_timeseries2.real, NFFT=NFFT, Fs=self.timeseries_sample_rate) self.pii2, self.freq = mlab.psd(self.corrected_timeseries2.imag, NFFT=NFFT, Fs=self.timeseries_sample_rate) self.coherence, self.coh_freq = mlab.cohere( self.corrected_timeseries1.real, self.corrected_timeseries2.real, NFFT=NFFT, Fs=self.timeseries_sample_rate) #print self.coherence.mean() self.effective_dof = self.coherence.mean() * len( self.corrected_timeseries1) / (NFFT / 2.) self.effective_dof = 0.25 * (len(self.corrected_timeseries1) / (NFFT / 2.)) self.gamma95 = 1 - (1 - thresh)**(1. / (self.effective_dof - 1.)) self.mask95 = self.coherence > self.gamma95 self.csd, self.csd_freq = mlab.csd(self.corrected_timeseries1.real, self.corrected_timeseries2.real, NFFT=NFFT, Fs=self.timeseries_sample_rate) self.angle = np.angle(self.csd) self.lpts1 = filters.low_pass_fir( self.corrected_timeseries1.real, cutoff=100.0, nyquist_freq=self.timeseries_sample_rate) self.lpts2 = filters.low_pass_fir( self.corrected_timeseries2.real, cutoff=100.0, nyquist_freq=self.timeseries_sample_rate)
def pca_noise(d, NFFT=None, Fs=256e6 / 2.**11, window=mlab.window_hanning, detrend=mlab.detrend_mean, use_log_bins=True, use_full_spectral_helper=True): if NFFT is None: NFFT = int(2**(np.floor(np.log2(d.shape[0])) - 3)) #print "using NFFT: 2**", np.log2(NFFT) if use_full_spectral_helper: pii, pqq, piq, fr_orig, t = full_spectral_helper(d.real, d.imag, NFFT=NFFT, Fs=Fs, window=window, detrend=detrend) pii = pii.mean(1) pqq = pqq.mean(1) piq = piq.mean(1) else: pii, fr_orig = mlab.psd(d.real, NFFT=NFFT, Fs=Fs, window=window, detrend=detrend) pqq, fr = mlab.psd(d.imag, NFFT=NFFT, Fs=Fs, window=window, detrend=detrend) piq, fr = mlab.csd(d.real, d.imag, NFFT=NFFT, Fs=Fs, window=window, detrend=detrend) if use_log_bins: fr, (pii, pqq, piq) = binning.log_bin_old(fr_orig, [pii, pqq, piq]) else: fr = fr_orig S, evals, evects, angles = calculate_pca_noise(pii, pqq, piq) return fr, S, evals, evects, angles, piq
def tf_estimate(x, y, *args, **kwargs): """ Estimate transfer function from x to y, see csd (from matplotlib.mlab package) for calling convention. Link: https://stackoverflow.com/questions/28462144/python-version-of -matlab-signal-toolboxs-tfestimate The vectors *x* and *y* are divided into *NFFT* length segments. Each segment is detrended by function *detrend* and windowed by function *window*. *noverlap* gives the length of the overlap between segments. Parameters ---------- x : 1-D arrays or sequences Arrays or sequences containing the data y : 1-D arrays or sequences Arrays or sequences containing the data args : Default keyword values: None kwargs : NFFT, Fs, detrend, window, noverlap, pad_to, sides, scale_by_freq Returns ------- frequency : float array Frequency array H : complex array Transfer function estimate Attributes ---------- p_xy: float array Cross spectral density p_xx: float array Power spectral density frequencies_csd: array Frequency array for cross spectral density frequencies_psd: array Frequency array for power spectral density """ p_xy, frequencies_csd = csd(y, x, *args, **kwargs) p_xx, frequencies_psd = psd(x, *args, **kwargs) return frequencies_csd, (p_xy / p_xx).conjugate()
def pca_noise_with_errors(d, NFFT, Fs, window=mlab.window_hanning, detrend=mlab.detrend_mean, use_log_bins=True): # Assume the rotation is small so that the variance can be approximated using the values in the pre-PCA spectra. # Take the variance to be the square of the power in each bin, divided by the number of averaged spectra. n_averaged = d.size / NFFT pii, pf = mlab.psd(d.real, NFFT=NFFT, Fs=Fs, window=window, detrend=detrend) pqq, pf = mlab.psd(d.imag, NFFT=NFFT, Fs=Fs, window=window, detrend=detrend) piq, pf = mlab.csd(d.real, d.imag, NFFT=NFFT, Fs=Fs, window=window, detrend=detrend) if use_log_bins: bf, bc_ii, (bp_ii, bvar_ii) = binning.log_bin_with_variance( pf, pii, pii**2 / n_averaged) bf, bc_qq, (bp_qq, bvar_qq) = binning.log_bin_with_variance( pf, pqq, pqq**2 / n_averaged) bf, bc_iq, (bp_iq, bvar_iq) = binning.log_bin_with_variance( pf, piq, np.abs(piq)**2 / n_averaged) # probably not right S, evals, evects, angles = calculate_pca_noise(bp_ii, bp_qq, bp_iq) return bf, S, evals, evects, angles, (bp_ii, bp_qq, bp_iq), bc_ii, np.vstack( (bvar_qq, bvar_ii)) else: S, evals, evects, angles = calculate_pca_noise(pii, pqq, piq) return (pf, S, evals, evects, angles, (pii, piq, piq), np.ones_like(pf), np.vstack((pqq**2 / n_averaged, pii**2 / n_averaged)))
def pca_noise(d, NFFT=None, Fs=256e6/2.**11, window=mlab.window_hanning, detrend=mlab.detrend_mean, use_log_bins=True, use_full_spectral_helper=True): if NFFT is None: NFFT = int(2 ** (np.floor(np.log2(d.shape[0])) - 3)) #print "using NFFT: 2**", np.log2(NFFT) if use_full_spectral_helper: pii, pqq, piq, fr_orig, t = full_spectral_helper(d.real, d.imag, NFFT=NFFT, Fs=Fs, window=window, detrend=detrend) pii = pii.mean(1) pqq = pqq.mean(1) piq = piq.mean(1) else: pii, fr_orig = mlab.psd(d.real, NFFT=NFFT, Fs=Fs, window=window, detrend=detrend) pqq, fr = mlab.psd(d.imag, NFFT=NFFT, Fs=Fs, window=window, detrend=detrend) piq, fr = mlab.csd(d.real, d.imag, NFFT=NFFT, Fs=Fs, window=window, detrend=detrend) if use_log_bins: fr, (pii, pqq, piq) = binning.log_bin_old(fr_orig, [pii, pqq, piq]) else: fr = fr_orig S, evals, evects, angles = calculate_pca_noise(pii, pqq, piq) return fr, S, evals, evects, angles, piq
def csd(self, plot=True,nbandavg=1,**kwargs): """ Cross spectral density nbandavg = Number of fft bins to average """ if self.isequal==False and self.VERBOSE: print 'Warning - time series is unequally spaced consider using lomb-scargle fft' NFFT = int(2**(np.floor(np.log2(self.ny/nbandavg)))) # Nearest power of 2 to length of data Pyy,frq = mlab.csd(self.TSobs.y-self.TSobs.y.mean(),Fs=2*np.pi/self.dt,NFFT=NFFT,window=mlab.window_hanning,scale_by_freq=True) if plot: plt.loglog(frq,Pyy,**kwargs) plt.xlabel('Freq. [$cycles s^{-1}$]') plt.ylabel('PSD') plt.grid(b=1) return Pyy, frq
def calculate(self,NFFT=2**16,thresh=0.95): self.pxx1,self.freq = mlab.psd(self.corrected_timeseries1.real,NFFT=NFFT,Fs=self.timeseries_sample_rate) self.pii1,self.freq = mlab.psd(self.corrected_timeseries1.imag,NFFT=NFFT,Fs=self.timeseries_sample_rate) self.pxx2,self.freq = mlab.psd(self.corrected_timeseries2.real,NFFT=NFFT,Fs=self.timeseries_sample_rate) self.pii2,self.freq = mlab.psd(self.corrected_timeseries2.imag,NFFT=NFFT,Fs=self.timeseries_sample_rate) self.coherence,self.coh_freq = mlab.cohere(self.corrected_timeseries1.real,self.corrected_timeseries2.real, NFFT=NFFT,Fs=self.timeseries_sample_rate) #print self.coherence.mean() self.effective_dof = self.coherence.mean()*len(self.corrected_timeseries1)/(NFFT/2.) self.effective_dof = 0.25*(len(self.corrected_timeseries1)/(NFFT/2.)) self.gamma95 = 1-(1-thresh)**(1./(self.effective_dof-1.)) self.mask95 = self.coherence > self.gamma95 self.csd,self.csd_freq = mlab.csd(self.corrected_timeseries1.real,self.corrected_timeseries2.real, NFFT=NFFT,Fs=self.timeseries_sample_rate) self.angle = np.angle(self.csd) self.lpts1 = filters.low_pass_fir(self.corrected_timeseries1.real,cutoff=100.0,nyquist_freq=self.timeseries_sample_rate) self.lpts2 = filters.low_pass_fir(self.corrected_timeseries2.real,cutoff=100.0, nyquist_freq=self.timeseries_sample_rate)
def gen_edges_wpli(x, fs=256, weighted=True): """ Generate weighted(optional) edges based on weighted phase lax index :param x: (T, C) :param weighted: True or False :return: edge_index: (2, num_edges) edge_weight:(num_edges, 1) """ x = x.T channels, samples = x.shape wpli = np.zeros((channels, channels)) pairs = [(i, j) for i in range(channels) for j in range(channels)] for pair in pairs: ch1, ch2 = x[pair,] csdxy, _ = mlab.csd(ch1, ch2, Fs=fs, scale_by_freq=True, sides='onesided') i_xy = np.imag(csdxy) num = np.nansum(np.abs(i_xy) * np.sign(i_xy)) denom = np.nansum(np.abs(i_xy)) wpli[pair] = np.abs(num / denom) adj = wpli adj[range(adj.shape[0]), range(adj.shape[0])] = 0 avg = np.sum(adj) / (adj.shape[0] * adj.shape[0] - adj.shape[0]) zeros_index = np.argwhere(adj <= avg) adj[zeros_index[:, 0], zeros_index[:, 1]] = 0 edge_index = np.argwhere(adj != 0).T if weighted: edge_weight = adj[edge_index[0, :], edge_index[1, :]].reshape(-1, 1) return edge_index, edge_weight else: return edge_index
def power_spectral_density( degrees, fourier_transform_size, stream_file,delta ): cross_spectral_density = np.zeros((degrees, degrees, int((fourier_transform_size / 2)+1)),dtype=complex) # Store the data 01 by means of a three-dimensional matrix 5 * 5 * 1025 frequency = np.zeros((degrees, degrees, int((fourier_transform_size / 2)+1)),dtype=complex) # build the matrix... n = stream_file.shape # dimensions of stream file lines x columns stream_file = stream_file[1:] if n[0] > n[1]: acceleration = stream_file #acceleration receives the data from the read file else: acceleration = np.transpose(stream_file)#acceleration receives the data from the reading file in a transposed way for i in range(0, degrees): # for j in range(0, degrees): # cross_spectral_density[:][i, j],frequency[:][i, j]= mlab.csd( # applying welch in matrix padding: cross spectral density and frequency acceleration[:, i], acceleration[:, j], NFFT=fourier_transform_size, Fs=delta, detrend=mlab.detrend_none, window=np.hanning(fourier_transform_size), noverlap =( int(fourier_transform_size / 2)), pad_to=None, sides='default', scale_by_freq=True ) return cross_spectral_density, frequency
# Ps - frequencia de amostragem # detrend - tirar a tendencia (entra com uma funcao) # window - janela aplicada (default=hanning) # noverlap - comprimento de overlap (0=sem overlap) aa1 = mlab.psd(eta1,NFFT=256,Fs=1.28,detrend=mlab.detrend_mean,window=mlab.window_hanning,noverlap=128) aa1 = np.array(aa1).T f = aa1[:,1] sp = aa1[:,0] ## =================================================== ## # Espectro cruzado #espectro cruzado (amplitude do espec cruzado?) aa2 = mlab.csd(eta1,dspx1,NFFT=256,Fs=1.28,detrend=mlab.detrend_mean,window=mlab.window_hanning,noverlap=128) aa2 = np.array(aa2).T #calcula o modulo do espectro aa2[:,0] = abs(aa2[:,0]) #espectro de coerencia aa3 = mlab.cohere(eta1,dspx1,NFFT=256,Fs=1.28,detrend=mlab.detrend_mean,window=mlab.window_hanning,noverlap=128) aa3 = np.array(aa3).T ## Figuras #autoespectro pl.figure() pl.plot(aa[:,0],aa[:,1])
def sleeman(stream): """ Sleeman method calculating the noise of each trace of input stream. :type stream: Stream object from module obspy.core.stream :param stream: Stream containing 3 traces with the same signal recorded. """ #Copy original stream m = stream.copy() #Verify stream if m[0].stats.sampling_rate != m[1].stats.sampling_rate \ or m[0].stats.sampling_rate != m[2].stats.sampling_rate \ or m[1].stats.sampling_rate != m[2].stats.sampling_rate: print("[pyColocSensors.sleeman]: Sampling rates are not identical \ between traces") if m[0].stats.npts != m[1].stats.npts \ or m[0].stats.npts != m[2].stats.npts \ or m[1].stats.npts != m[2].stats.npts: print("[pyColocSensors.sleeman]: Traces does not have the same length") if m[0].stats.starttime-m[1].stats.starttime >= m[0].stats.sampling_rate/2\ or m[1].stats.starttime-m[2].stats.starttime >= m[1].stats.sampling_rate/2\ or m[0].stats.starttime-m[2].stats.starttime >= m[0].stats.sampling_rate/2:\ print("[pyColocSensors.sleeman]: Traces does not have the same start time") #Set psd and csd parameters. Set as McNamara recommands in his paper, \ #except for windows length, staticaly fixed to 1024, to improve resolution #(doi: 10.1785/012003001) n_fft = 1024 n_overlap = int(n_fft*0.75) fs = m[0].stats.sampling_rate #Calculate psd and csd (P00,f) = mlab.psd(m[0].data,Fs=fs,NFFT=n_fft,noverlap=n_overlap,\ detrend=detrend_func,window=cosine_taper(n_fft,p=0.2),scale_by_freq=True) (P11,f) = mlab.psd(m[1].data,Fs=fs,NFFT=n_fft,noverlap=n_overlap,\ detrend=detrend_func,window=cosine_taper(n_fft,p=0.2),scale_by_freq=True) (P22,f) = mlab.psd(m[2].data,Fs =fs,NFFT=n_fft,noverlap=n_overlap,\ detrend=detrend_func,window=cosine_taper(n_fft,p=0.2),scale_by_freq=True) (P01,f) = mlab.csd(m[0].data,m[1].data, Fs=fs,NFFT=n_fft,noverlap=n_overlap,\ detrend=detrend_func,window=cosine_taper(n_fft,p=0.2),scale_by_freq=True) (P02,f) = mlab.csd(m[0].data,m[2].data, Fs=fs,NFFT=n_fft,noverlap=n_overlap,\ detrend=detrend_func,window=cosine_taper(n_fft,p=0.2),scale_by_freq=True) P10 = np.conj(P01) (P12,f) = mlab.csd(m[1].data,m[2].data, Fs=fs,NFFT=n_fft,noverlap=n_overlap,\ detrend=detrend_func,window=cosine_taper(n_fft,p=0.2),scale_by_freq=True) P20 = np.conj(P02) P21 = np.conj(P12) #Apply corrections as McNamara recommends for spectra in [P00,P11,P22,P01,P02,P10,P12,P20,P21]: spectra = spectra*1.142857 #Calculate electronic noises acoording to Sleeman's method N0 = P00-P10*P02/P12 N1 = P11-P21*P10/P20 N2 = P22-P02*P21/P01 #Remove first samples (3%) in order to avoid poor resolution problems. #Samples remaining should be enough to cover one decade in frequency. N0 = N0[int(n_fft*0.03):] N1 = N1[int(n_fft*0.03):] N2 = N2[int(n_fft*0.03):] f = f[int(n_fft*0.03):] return (N0,N1,N2,f)
def residual_spectrum(xres, fu, dt): """RESIDUAL_SPECTRUM: Computes statistics from an input spectrum over a number of bands, returning the band limits and the estimates for power spectra for real and imaginary parts and the cross-spectrum. Mean values of the noise spectrum are computed for the following 8 frequency bands defined by their center frequency and band width: M0 +.1 cpd; M1 +-.2 cpd; M2 +-.2 cpd; M3 +-.2 cpd; M4 +-.2 cpd; M5 +-.2 cpd; M6 +-.21 cpd; M7 (.26-.29 cpd); and M8 (.30-.50 cpd). S. Lentz 10/28/99 R. Pawlowicz 11/1/00 Version 1.0 Define frequency bands for spectral averaging. """ fband = np.array([[0.0001, 0.00417], [0.03192, 0.04859], [0.07218, 0.08884], [0.11243, 0.1291], [0.15269, 0.16936], [0.19295, 0.20961], [0.2332, 0.251], [0.26, 0.29], [0.3, 0.5]]) # If we have a sampling interval> 1 hour, we might have to get # rid of some bins. # fband(fband(:,1)>1/(2*dt),:)=[]; nfband = fband.shape[0] nx = max(xres.shape) # Spectral estimate (takes real time series only). fx, Pxr = sps.welch(np.real(xres), window=np.hanning(nx), noverlap=np.ceil(nx / 2), nfft=nx, fs=1/dt, nperseg=nx) Pxr = Pxr / 2 / dt fx, Pxi = sps.welch(np.imag(xres), window=np.hanning(nx), noverlap=np.ceil(nx / 2), nfft=nx, fs=1/dt, nperseg=nx) Pxi = Pxi / 2 / dt Pxc, fx = mplm.csd(np.real(xres), np.imag(xres), nx, 1/dt) # matlab cpsd returns only reals when given a real xres have to # test for complex and maybe change to ifstatement Pxc = np.real(Pxc) Pxc = Pxc / 2 / dt df = fx[2] - fx[1] # Sets Px=NaN in bins close to analyzed frequencies # to prevent leakage problems?). Pxr[np.around(fu / df).astype(int)] = np.nan Pxi[np.around(fu / df).astype(int)] = np.nan Pxc[np.around(fu / df).astype(int)] = np.nan Pxrave = np.zeros(shape=(nfband, 1), dtype='float64') Pxiave = np.zeros(shape=(nfband, 1), dtype='float64') Pxcave = np.zeros(shape=(nfband, 1), dtype='float64') # Loop downwards in frequency through bands (cures short time series # problem with no data in lowest band). # Divide by nx to get power per frequency bin, and multiply by 2 # to account for positive and negative frequencies. for k in range(nfband-1, -1, - 1): jband = np.flatnonzero(np.all(np.vstack([fx >= fband[(k), 0], fx <= fband[(k), 1], np.isfinite(Pxr)]).T, axis=1)) if any(jband): Pxrave[k] = np.dot(np.mean(Pxr[(jband)]), 2) / nx Pxiave[k] = np.dot(np.mean(Pxi[(jband)]), 2) / nx Pxcave[k] = np.dot(np.mean(Pxc[(jband)]), 2) / nx else: if k < nfband: Pxrave[k] = Pxrave[(k + 1)] # Low frequency bin might not have any points... Pxiave[k] = Pxiave[(k + 1)] Pxcave[k] = Pxcave[(k + 1)] return fband, Pxrave, Pxiave, Pxcave
def get_spectra(time_series, method=None): r""" Compute the spectra of an n-tuple of time series and all of the pairwise cross-spectra. Parameters ---------- time_series: float array The time-series, where time is the last dimension method: dict, optional contains: this_method:'welch' indicates that :func:`mlab.psd` will be used in order to calculate the psd/csd, in which case, additional optional inputs (and default values) are: NFFT=64 Fs=2pi detrend=mlab.detrend_none window=mlab.window_hanning n_overlap=0 this_method:'periodogram_csd' indicates that :func:`periodogram` will be used in order to calculate the psd/csd, in which case, additional optional inputs (and default values) are: Skx=None Sky=None N=None sides='onesided' normalize=True Fs=2pi this_method:'multi_taper_csd' indicates that :func:`multi_taper_psd` used in order to calculate psd/csd, in which case additional optional inputs (and default values) are: BW=0.01 Fs=2pi sides = 'onesided' Returns ------- f: float array The central frequencies for the frequency bands for which the spectra are estimated fxy: float array A semi-filled matrix with the cross-spectra of the signals. The csd of signal i and signal j is in f[j][i], but not in f[i][j] (which will be filled with zeros). For i=j fxy[i][j] is the psd of signal i. """ if method is None: method = {'this_method': 'welch'} # The default # If no choice of method was explicitely set, but other parameters were # passed, assume that the method is mlab: this_method = method.get('this_method', 'welch') if this_method == 'welch': NFFT = method.get('NFFT', 64) Fs = method.get('Fs', 2 * np.pi) detrend = method.get('detrend', mlab.detrend_none) window = method.get('window', mlab.window_hanning) n_overlap = method.get('n_overlap', int(np.ceil(NFFT / 2.0))) # The length of the spectrum depends on how many sides are taken, which # depends on whether or not this is a complex object: if np.iscomplexobj(time_series): fxy_len = NFFT else: fxy_len = NFFT / 2.0 + 1 # If there is only 1 channel in the time-series: if len(time_series.shape) == 1 or time_series.shape[0] == 1: temp, f = mlab.csd(time_series, time_series, NFFT, Fs, detrend, window, n_overlap, scale_by_freq=True) fxy = temp.squeeze() # the output of mlab.csd has a weird # shape else: fxy = np.zeros((time_series.shape[0], time_series.shape[0], fxy_len), dtype=complex) # Make sure it's complex for i in xrange(time_series.shape[0]): for j in xrange(i, time_series.shape[0]): #Notice funny indexing, in order to conform to the #conventions of the other methods: temp, f = mlab.csd(time_series[j], time_series[i], NFFT, Fs, detrend, window, n_overlap, scale_by_freq=True) fxy[i][j] = temp.squeeze() # the output of mlab.csd has a # wierd shape elif this_method in ('multi_taper_csd', 'periodogram_csd'): # these methods should work with similar signatures mdict = method.copy() func = eval(mdict.pop('this_method')) freqs, fxy = func(time_series, **mdict) f = utils.circle_to_hz(freqs, mdict.get('Fs', 2 * np.pi)) else: raise ValueError("Unknown method provided") return f, fxy.squeeze()
from numpy import loadtxt, savetxt from optparse import OptionParser parser = OptionParser() parser.add_option("-f", "--file", dest="filename") parser.add_option("-p", "--power", type="int", dest="power", default=int(14)) parser.add_option("-e", "--overlap", type="int", dest="overlap", default=int(10)) parser.add_option("-o", "--output", type="string", dest="output", default="output.dat") (options, args) = parser.parse_args() print "options.power = ", options.power print "options.overlap = ", options.overlap x = loadtxt(options.filename) print "x.shape = ", x.shape print "x.ndim = ", x.ndim if x.ndim==1: psx, fr = psd(x, NFFT=2**options.power, detrend=detrend_mean, noverlap=options.overlap) elif x.ndim==2: psx, fr = csd(x[:, 0], x[:, 1], NFFT=2**options.power, detrend=detrend_mean, noverlap=options.overlap) else: raise(DimensionError) fr = fr.reshape(-1, 1) psx = psx.reshape(-1, 1) print "psx.shape = ", psx.shape print "fr.shape = ", fr.shape savetxt(options.output, hstack((fr, abs(psx))))
def residual_spectrum(xres, fu, dt): """RESIDUAL_SPECTRUM: Computes statistics from an input spectrum over a number of bands, returning the band limits and the estimates for power spectra for real and imaginary parts and the cross-spectrum. Mean values of the noise spectrum are computed for the following 8 frequency bands defined by their center frequency and band width: M0 +.1 cpd; M1 +-.2 cpd; M2 +-.2 cpd; M3 +-.2 cpd; M4 +-.2 cpd; M5 +-.2 cpd; M6 +-.21 cpd; M7 (.26-.29 cpd); and M8 (.30-.50 cpd). S. Lentz 10/28/99 R. Pawlowicz 11/1/00 Version 1.0 Define frequency bands for spectral averaging. """ fband = np.array([0.0001, 0.00417, 0.03192, 0.04859, 0.07218, 0.08884, 0.11243, 0.1291, 0.15269, 0.16936, 0.19295, 0.20961, 0.2332, 0.251, 0.26, 0.29, 0.3, 0.5]).reshape(9,2) # If we have a sampling interval> 1 hour, we might have to get # rid of some bins. #fband(fband(:,1)>1/(2*dt),:)=[]; nfband = fband.shape[0] nx = max(xres.shape) # Spectral estimate (takes real time series only). # Matlab has changed their spectral estimator functions # To match the old code, I have to divide by 2*dt. This is because # # PSD*dt is two-sided spectrum in units of power per hertz. # # PWELCH is the one-sided spectrum in power per hertz # # So PWELCH/2 = PSD*dt #[Pxr,fx]=psd(real(xres),nx,1/dt); # Call to SIGNAL PROCESSING TOOLBOX - see note in t_readme. If you have an error here you are probably missing this toolbox #[Pxi,fx]=psd(imag(xres),nx,1/dt); # Call to SIGNAL PROCESSING TOOLBOX - see note in t_readme. #[Pxc,fx]=csd(real(xres),imag(xres),nx,1/dt); # Call to SIGNAL PROCESSING TOOLBOX - see note in t_readme. Pxr, fx = sps.welch(np.real(xres), window=np.hanning(nx), noverlap=np.ceil(nx / 2),nfft=nx,fs=1/dt) # nargout=2 # Call to SIGNAL PROCESSING TOOLBOX - see note in t_readme. If you have an error here you are probably missing this toolbox Pxr = Pxr / 2 / dt Pxi, fx = sps.welch(np.imag(xres), window=np.hanning(nx), noverlap=np.ceil(nx / 2),nfft=nx,fs=1/dt) # nargout=2 # Call to SIGNAL PROCESSING TOOLBOX - see note in t_readme. Pxi = Pxi / 2 / dt Pxc, fx = mplm.csd(np.real(xres), np.imag(xres),nx,1 / dt) # nargout=2 # Call to SIGNAL PROCESSING TOOLBOX - see note in t_readme. Pxc = Pxc / 2 / dt df = fx[2] - fx[1] Pxr[np.around(fu / df).astype(int) ] = np.nan # Sets Px=NaN in bins close to analyzed frequencies Pxi[np.around(fu / df).astype(int)] = np.nan # (to prevent leakage problems?). Pxc[np.around(fu / df).astype(int)] = np.nan Pxrave = np.zeros(shape=(nfband, 1), dtype='float64') Pxiave = np.zeros(shape=(nfband, 1), dtype='float64') Pxcave = np.zeros(shape=(nfband, 1), dtype='float64') # Loop downwards in frequency through bands (cures short time series # problem with no data in lowest band). # # Divide by nx to get power per frequency bin, and multiply by 2 # to account for positive and negative frequencies. # for k in range(nfband-1, -1, - 1): jband = np.flatnonzero(np.all(np.vstack([fx >= fband[(k), 0],fx <= fband[(k), 1] , np.isfinite(Pxr)]).T,axis=1)) if any(jband): Pxrave[k] = np.dot(np.mean(Pxr[(jband)]), 2) / nx Pxiave[k] = np.dot(np.mean(Pxi[(jband)]), 2) / nx Pxcave[k] = np.dot(np.mean(Pxc[(jband)]), 2) / nx else: if k < nfband: Pxrave[k] = Pxrave[(k + 1)] # Low frequency bin might not have any points... Pxiave[k] = Pxiave[(k + 1)] Pxcave[k] = Pxcave[(k + 1)] return fband, Pxrave, Pxiave, Pxcave
def ut_pdgm(t,e,cfrq,equi,frqosmp): #import pdb; pdb.set_trace() P = {} nt = len(e) # matches MatLab hann # want to switch to this in future #hn = np.hanning(nt) # Matches matlab hanning hn = np.hanning(nt+2) hn = hn[1:-1] if equi: # matlab pwelch # pwelch(x,window,noverlap,nfft) #[Puu1s,allfrq] = pwelch(real(e),hn,0,nt); # Puu1s, allfrq = scipy.signal.welch(np.real(e), window='hanning', # noverlap=0, nfft=nt, fs=2*np.pi) # allfrq, Puu1s = scipy.signal.welch(np.real(e), window='hanning', # noverlap=0, nfft=nt, fs=2*np.pi, # detrend='constant', # scaling='density') # allfrq, Puu1s = scipy.signal.periodogram(np.real(e), window='hanning', # nfft=nt, fs=2*np.pi, # detrend='constant', # scaling='density') allfrq, Puu1s = scipy.signal.welch(np.real(e), window=hn, noverlap=0, nfft=nt, fs=2*np.pi) #hn = mlab.window_hanning(t) #Puu1s, allfrq = mlab.psd(np.real(e), window=hn, noverlap=0, NFFT=nt, Fs=2*np.pi) else: # ut_lmbscga # Here I think scipy.signal.lombscargle(x,y,freqs) should work. Look # into it. pass #import pdb; pdb.set_trace() fac = (nt-1)/(2*np.pi*(t[-1]-t[0])*24) # conv fac: rad/sample to cph allfrq = allfrq*fac # to [cycle/hour] from [rad/samp] Puu1s = Puu1s / fac # to [e units^2/cph] from [e units^2/(rad/samp)] #import pdb; pdb.set_trace() P['Puu'], P['fbnd'] = ut_fbndavg(Puu1s, allfrq, cfrq) if not np.isreal(e).all(): if equi: #Pvv1s, _ = pwelch(np.imag(e),hn,0,nt) temp, Pvv1s = scipy.signal.welch(np.imag(e),window=hn, noverlap=0, nfft=nt, fs=2*np.pi) #temp, Pvv1s = scipy.signal.welch(np.imag(e),window=hn, noverlap=0, nfft=nt, fs=2*np.pi) # should be able to use mlab.csd #Puv1s, _ = cpsd(np.real(e),np.imag(e),hn,0,nt) #Pvv1s, temp = mlab.psd(np.imag(e), window=hn, noverlap=0, NFFT=nt, Fs=2*np.pi, sides='default') Puv1s, temp = mlab.csd(np.real(e),np.imag(e), noverlap=0, NFFT=nt, window=hn, Fs=2*np.pi) else: #Pvv1s, _ = ut_lmbscga(imag(e),t,hn,frqosmp); #Puv1s, _ = ut_lmbscgc(real(e),imag(e),t,hn,frqosmp); pass Pvv1s = Pvv1s/fac P['Pvv'], _ = ut_fbndavg(Pvv1s,allfrq,cfrq) Puv1s = np.real(Puv1s)/fac P['Puv'], _ = ut_fbndavg(Puv1s,allfrq,cfrq) P['Puv'] = np.abs(P['Puv']) #import pdb; pdb.set_trace() return P
def DifResMlabCsd(data1, data2, fs): P1, f1 = mlab.csd(data1, data2, len(data1), Fs=fs, window=mlab.window_hanning) P2, f2 = mlab.csd(data1, data2, len(data1)/10, Fs=fs, window=mlab.window_hanning) P3, f3 = mlab.csd(data1, data2, len(data1)/100, Fs=fs, window=mlab.window_hanning) return f1, P1, f2, P2, f3, P3
def tfe(y, x, *args, **kwargs): """estimate transfer function from x to y, see csd for calling convention""" sxy, fxy = csd(y, x, *args, **kwargs) sxx, fxx = psd(x, *args, **kwargs) return sxy / sxx, fxx
def cp(tr1,tr2,lenfft,lenol,delta): sr = 1/delta cpval,fre = csd(tr1.data,tr2.data,NFFT=lenfft,Fs=sr,noverlap=lenol,scale_by_freq=True) fre = fre[1:] cpval = cpval[1:] return cpval, fre
def csd(plot, *args, **kwargs): """PlotFactory Wrapper of matplotlib.csd : Compute the csd(cross-spectral) of *data1* vs *data2* contrarly to matplolib.psd, return a new xyplot factory instance ready to plot result of the csd. Different Parameters than matplotlib: data1 : fisrt data set data2 : second data set They can be liases to "x" and "y" for instance direction ("y"/"x") : in wich axis the spectrum is ploted, default is "y" Machined Parameters (if direction=="y"): x : alias('freqs') y : 10*log10(psd) freqs : frequences csd : psd result in linear space data : the input data xlabel, ylabel : are set if not already set ymin, ymax : set to 0, alias('spec') (for vlines plot) min, max, lines : set to 0, alias('spec'), alias('freq') if direction == "x" swap above x's and y's the matplotlib doc is copied below Remember that this return a xyplot instance the output of spectrograph are in "csd", "freqs" -> csd, freqs =getargs("csd", "freqs") ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ """ plot.update(kwargs.pop(KWS,{}), **kwargs) (data1, data2, NFFT, Fs, Fc, detrend, window, noverlap, pad_to, sides, scale_by_freq) = plot.parseargs(args, "data1", "data2", "NFFT", "Fs", "Fc", "detrend", "window", "noverlap", "pad_to", "sides", "scale_by_freq", NFFT=None, Fs=None, Fc=None, detrend=None, window=None, noverlap=None, pad_to=None, sides=None, scale_by_freq=None ) if Fc is None: Fc = 0 pxy, freqs = mlab.csd(x=data1, y=data2, NFFT=NFFT, Fs=Fs, detrend=detrend, window=window, noverlap=noverlap, pad_to=pad_to, sides=sides, scale_by_freq=scale_by_freq) pxy.shape = len(freqs), # pxy is complex freqs += Fc di, dd = plot._get_direction() plot.update( {di:alias('freqs'), dd:10 * np.log10(pxy), dd+"min":0, dd+"max":alias(dd)}, min=0, max=alias(dd), lines=alias('freqs'), csd=pxy, freqs=freqs, data1=data1,data2=data2, Fc=Fc) plot.locals.setdefault(di+"label", 'Frequency') plot.locals.setdefault(dd+"label", 'Cross Spectrum Magnitude (dB)') plot.axes.update(grid=True) plot.goifgo()