def work(self, input_items, output_items): in0 = input_items[0] out = output_items[0] if self.avg == "True": avg = numpy.add(numpy.zeros(self.nData),numpy.zeros(self.nData)*1.j) for i in xrange(len(in0)): inp = in0[i] for a in numpy.arange(self.avgn): low = a*self.nData high = (a+1)*self.nData avg = numpy.add(avg,inp[low:high]) avg = avg/self.nData f, pw = sp.welch(avg,fs=self.fs, window='hann',nperseg=self.nf, noverlap=self.nf*self.noverlap, scaling=self.scale,detrend=False) out[i] = pw if self.avg == "False": for i in xrange(len(in0)): x = in0[i] # Uses the scipy.signal.welch method to average data f, pw = sp.welch(x,fs=self.fs,window='hann', nperseg = self.nf, noverlap=self.nf*self.noverlap, scaling=self.scale,detrend=False) out[i] = pw return len(output_items[0]) (output_items[0])
def estim_diff(percent=256): sound_counter=0 res=np.empty(len(input_file_names)) for i in range(res.shape[0]): input_rate,input_sig=wavfile.read(input_dir+'Segments/'+input_file_names[i]) output_rate,output_sig=wavfile.read(output_dir+'Segments/'+output_file_names[i]) input_sig=pcm2float(input_sig,'float32') output_sig=pcm2float(output_sig,'float32') min_size=np.min((input_sig[:,0].shape[0],output_sig[:,0].shape[0])) #print min_size,min_size*percent #S_inp=np.absolute(fft(input_sig[:min_size,0]-np.mean(input_sig[:min_size,0]))) #S_out=np.absolute(fft(output_sig[:min_size,0]-np.mean(output_sig[:min_size,0]))) t=time() nperseg=int(min_size*percent)-np.mod(int(min_size*percent),10) real_perc=float(float(nperseg)/int(min_size*percent)) S_inp=signal.welch(input_sig[:min_size,0],nperseg=nperseg)[1] S_out=signal.welch(output_sig[:min_size,0],nperseg=nperseg)[1] #S_inp=ndim_welch(input_sig[:min_size,0][None,...],nperseg=int(min_size*percent))[1] #S_out=ndim_welch(output_sig[:min_size,0][None,...],nperseg=int(min_size*percent))[1] #print time()-t #print S_inp_1,S_inp_2 res[sound_counter]=delta_estimator_3(S_out/S_inp,S_inp)-delta_estimator_3(S_inp/S_out,S_out) #out=float2pcm(output_sig,'int16') sound_counter+=1 return real_perc,int(min_size*percent),res
def calculate_spectra(ts, samp, olap=0, nseg=3, wtype='tukey', norm=True): """ ts = input time series samp = sampling rate in Hz olap = window overlap in %. 0 == Bartlett's method. nseg = number of segments to take for PSD estimation. wtype = window to use during calculation. see scipy.signal.get_window. norm = If true, normalizes spectra such that it's sum = 1. Calculates the spectra of an input time series using the specified window. Inspired by He, Biyu J in Neuron 2010 & J Neurosci 2011. """ if olap < 0 or olap >= 100: print('INVALID: olap = ' + str(olap) + ', should be a % (1-99)') # calculate the length of each window, accounting for nseg and olap ntrs = ts.shape[-1] nperseg = ntrs / nseg * (1 + olap/100.0) while np.remainder(nperseg, 1) != 0: nseg = nseg - 1 nperseg = ntrs / float(nseg) * (1 + olap/100.0) olap = olap * nperseg print('MSG: Calculating spectra using {} pts/window.'.format(nperseg)) if wtype == 'tukey': window = tukeywin(nperseg, alpha=0.5) spectra = signal.welch(ts, fs=samp, window=window, noverlap=olap, nperseg=nperseg, return_onesided=True, scaling='spectrum') else: try: spectra = signal.welch(ts, fs=samp, window=wtype, noverlap=olap, nperseg=nperseg, return_onesided=True, scaling='spectrum') except: print('Input window ' + str(wtype) + 'is invalid!') print('Using scipy default: hanning...') spectra = signal.welch(ts, fs=samp, noverlap=olap, nperseg=nperseg, return_onesided=True, scaling='spectrum') fs = spectra[0] pxx = spectra[1] # convert to %s (i.e., sum of pxx = 1) if norm == True: pxx = pxx / np.sum(pxx) return fs, pxx
def test_nd_axis_0(self): x = np.arange(20, dtype=np.float64)+0.04 x = x.reshape((10,2,1)) f, p = welch(x, nperseg=10, axis=0) assert_array_equal(p.shape, (6,2,1)) assert_array_almost_equal_nulp(p[:,0,0], p[:,1,0], 60) f0, p0 = welch(x[:,0,0], nperseg=10) assert_array_almost_equal_nulp(p0, p[:,1,0])
def test_nd_axis_0(self): x = np.arange(20, dtype=np.float64) + 0.04 x = x.reshape((10,2,1)) f, p = welch(x, nperseg=10, axis=0) assert_array_equal(p.shape, (6,2,1)) assert_allclose(p[:,0,0], p[:,1,0], atol=1e-13, rtol=1e-13) f0, p0 = welch(x[:,0,0], nperseg=10) assert_allclose(p0, p[:,1,0], atol=1e-13, rtol=1e-13)
def test_nd_axis_m1(self): x = np.arange(20, dtype=np.float64) + 0.04 x = x.reshape((2,1,10)) f, p = welch(x, nperseg=10) assert_array_equal(p.shape, (2, 1, 6)) assert_allclose(p[0,0,:], p[1,0,:], atol=1e-13, rtol=1e-13) f0, p0 = welch(x[0,0,:], nperseg=10) assert_allclose(p0[np.newaxis,:], p[1,:], atol=1e-13, rtol=1e-13)
def test_empty_input(self): f, p = welch([]) assert_array_equal(f.shape, (0,)) assert_array_equal(p.shape, (0,)) for shape in [(0,), (3,0), (0,5,2)]: f, p = welch(np.empty(shape)) assert_array_equal(f.shape, shape) assert_array_equal(p.shape, shape)
def test_window_external(self): x = np.zeros(16) x[0] = 1 x[8] = 1 f, p = welch(x, 10, 'hann', 8) win = signal.get_window('hann', 8) fe, pe = welch(x, 10, win, 8) assert_array_almost_equal_nulp(p, pe) assert_array_almost_equal_nulp(f, fe)
def test_short_data(self): x = np.zeros(8) x[0] = 1 with warnings.catch_warnings(): warnings.simplefilter('ignore', UserWarning) f, p = welch(x) f1, p1 = welch(x, nperseg=8) assert_allclose(f, f1) assert_allclose(p, p1)
def transferFunction(sigin, sigout, fs, nfft=int(2e13), filtering=None, limits=None): """ Return frequencies and modulus of \ transfer function T(iw) = sigout(iw)/sigin(iw). Parameters ---------- sigin, sigout : array_like Time series of measurement values for input and output fs : float Sampling frequency nfft : int, optional Length of the FFT used, if a zero padded FFT is desired. \ If None, the FFT length is nperseg. Defaults to None. filtering : float, optional If provided, apply a lowpass filter on sigin and sigout before \ computing fft (the default is None). Then filtering is the cutoff frequency \ as a fraction of the sampling rate (in (0, 0.5)). limits : (fmin, fmax), optional If provided, truncates the output between fmin and fmax \ (the default is None). Return ------ f : list frequency point in Hertz. TF : list Modulus of transfer function. """ if filtering is not None: sigin = lowpass(sigin, fc=filtering) sigout = lowpass(sigout, fc=filtering) import scipy.signal as sig f, Pxx_den1 = sig.welch(sigin, fs, nperseg=nfft, scaling='spectrum') f, Pxx_den2 = sig.welch(sigout, fs, nperseg=nfft, scaling='spectrum') TF = Pxx_den2/Pxx_den1 if limits is None: fmin, fmax = 20., 20e3 else: fmin, fmax = limits from numpy import nonzero nfmax = len(f) if fmax >= f[-1] else nonzero(f > fmax)[0][0] nfmin = nonzero(f > fmin)[0][0] f = f[nfmin:nfmax] TF = [el**0.5 for el in TF[nfmin:nfmax]] return f, TF
def test_filter_psd(): """Test highpass filter with power spectral density.""" a = np.sin(np.linspace(0, 4 * np.pi, 32)) b = rs.randn(32) / 2 y = a + b y_filt = glm.fsl_highpass_filter(y, 10) nt.assert_equal(y.shape, y_filt.shape) _, orig_d = signal.welch(y, nperseg=32) _, filt_d = signal.welch(y_filt, nperseg=32) nt.assert_greater(orig_d.sum(), filt_d.sum())
def welch_psd(Float, hpids, var, tz='z', hold='off'): """Compute power spectral density of some variable using Welch method. Variables are first interpolated onto a regular grid in either time or depth which can be specified using the tz optional argument. A time interval of 25 seconds is used and a depth interval of 4m.""" dz = 4. dt = 25./86400. if tz == 'z': df = dz ivar = 'z' m = 1. elif tz == 't': df = dt ivar = 'UTC' m = 86400. else: raise RuntimeWarning("tz should be 't' or 'z'.") profiles = Float.get_profiles(hpids) if np.iterable(profiles): for i, profile in enumerate(profiles): f = getattr(profile, ivar) nans = np.isnan(f) f = np.unique(f[~nans]) f = np.arange(f[0], f[-1], df) x = profile.interp(f, ivar, var) if hold == 'on': if i == 0: plt.figure() freq, Pxx = sig.welch(x, 1./(m*df)) plt.loglog(freq, Pxx) else: plt.figure() freq, Pxx = sig.welch(x, 1./(m*df)) plt.loglog(freq, Pxx) else: f = getattr(profiles, ivar) nans = np.isnan(f) f = np.unique(f[~nans]) f = np.arange(f[0], f[-1], df) x = profiles.interp(f, ivar, var) plt.figure() freq, Pxx = sig.welch(x, 1./(m*df)) plt.loglog(freq, Pxx)
def test_short_data(self): x = np.zeros(8) x[0] = 1 #for string-like window, input signal length < nperseg value gives #UserWarning, sets nperseg to x.shape[-1] with suppress_warnings() as sup: sup.filter(UserWarning, "nperseg = 256 is greater than input length = 8, using nperseg = 8") f, p = welch(x,window='hann') # default nperseg f1, p1 = welch(x,window='hann', nperseg=256) # user-specified nperseg f2, p2 = welch(x, nperseg=8) # valid nperseg, doesn't give warning assert_allclose(f, f2) assert_allclose(p, p2) assert_allclose(f1, f2) assert_allclose(p1, p2)
def test_short_data(self): x = np.zeros(8) x[0] = 1 #for string-like window, input signal length < nperseg value gives #UserWarning, sets nperseg to x.shape[-1] with warnings.catch_warnings(): warnings.simplefilter('ignore', UserWarning) f, p = welch(x,window='hann') # default nperseg f1, p1 = welch(x,window='hann', nperseg=256) # user-specified nperseg f2, p2 = welch(x, nperseg=8) # valid nperseg, doesn't give warning assert_allclose(f, f2) assert_allclose(p, p2) assert_allclose(f1, f2) assert_allclose(p1, p2)
def display(self, data): """Make graphicsitem for spectrum figure. Parameters ---------- data : ndarray 1D vector containing the data only This function can be called by self.display_window (which reads the data for the selected channel) or by the mouse-events functions in traces (which read chunks of data from the user-made selection). """ value = self.config.value self.scene = QGraphicsScene(value['x_min'], value['y_min'], value['x_max'] - value['x_min'], value['y_max'] - value['y_min']) self.idx_fig.setScene(self.scene) self.add_grid() self.resizeEvent(None) s_freq = self.parent.traces.data.s_freq f, Pxx = welch(data, fs=s_freq, nperseg=int(min((s_freq, len(data))))) # force int freq_limit = (value['x_min'] <= f) & (f <= value['x_max']) if self.config.value['log']: Pxx_to_plot = log(Pxx[freq_limit]) else: Pxx_to_plot = Pxx[freq_limit] self.scene.addPath(Path(f[freq_limit], Pxx_to_plot), QPen(QColor(LINE_COLOR), LINE_WIDTH))
def compute_NDSI(file, windowLength = 1024, anthrophony=[1000,2000], biophony=[2000,11000]): """ Compute Normalized Difference Sound Index from an audio signal. This function compute an estimate power spectral density using Welch's method. Reference: Kasten, Eric P., Stuart H. Gage, Jordan Fox, and Wooyeong Joo. 2012. The Remote Environ- mental Assessment Laboratory's Acoustic Library: An Archive for Studying Soundscape Ecology. Ecological Informatics 12: 50-67. windowLength: the length of the window for the Welch's method. anthrophony: list of two values containing the minimum and maximum frequencies (in Hertz) for antrophony. biophony: list of two values containing the minimum and maximum frequencies (in Hertz) for biophony. Inspired by the seewave R package, the soundecology R package and the original matlab code from the authors. """ #frequencies, pxx = signal.welch(file.sig_float, fs=file.sr, window='hamming', nperseg=windowLength, noverlap=windowLength/2, nfft=windowLength, detrend=False, return_onesided=True, scaling='density', axis=-1) # Estimate power spectral density using Welch's method # TODO change of detrend for apollo frequencies, pxx = signal.welch(file.sig_float, fs=file.sr, window='hamming', nperseg=windowLength, noverlap=windowLength/2, nfft=windowLength, detrend='constant', return_onesided=True, scaling='density', axis=-1) # Estimate power spectral density using Welch's method avgpow = pxx * frequencies[1] # use a rectangle approximation of the integral of the signal's power spectral density (PSD) #avgpow = avgpow / np.linalg.norm(avgpow, ord=2) # Normalization (doesn't change the NDSI values. Slightly differ from the matlab code). min_anthro_bin=np.argmin([abs(e - anthrophony[0]) for e in frequencies]) # min freq of anthrophony in samples (or bin) (closest bin) max_anthro_bin=np.argmin([abs(e - anthrophony[1]) for e in frequencies]) # max freq of anthrophony in samples (or bin) min_bio_bin=np.argmin([abs(e - biophony[0]) for e in frequencies]) # min freq of biophony in samples (or bin) max_bio_bin=np.argmin([abs(e - biophony[1]) for e in frequencies]) # max freq of biophony in samples (or bin) anthro = np.sum(avgpow[min_anthro_bin:max_anthro_bin]) bio = np.sum(avgpow[min_bio_bin:max_bio_bin]) ndsi = (bio - anthro) / (bio + anthro) return ndsi
def whelchMethod(data, Fs=200): f, pxx = signal.welch(data, fs=Fs, nperseg=1024) d = {'psd': pxx, 'freqs': f} df = pd.DataFrame(data=d) dfs = df.sort(['psd'], ascending=False) rows = dfs.iloc[:10] return rows['freqs'].mean()
def plot_psd_welch(data,fs,filename,flag): # Estimate PSD using Welchs method. Divides the data into overlapping segments, #computing a modified periodogram for each segment and overlapping the periodograms plt.figure(figsize=(10,10)) fig, (ax0,ax1) = plt.subplots(nrows=2) f, Pxx_den = signal.periodogram (data, fs) ax0.set_xlabel('frequency [Hz]') ax0.set_ylabel('periodogram') ax0.plot(f, Pxx_den) print "Periodogram" print "f is " , f print "Pxx_den is ", Pxx_den f2, Pxx_den2 = signal.welch(data, fs) ax1.set_ylabel('PSD [V**2/Hz]') print "Welch method " print "f2 is ", f2 print "Pxx_den2 is" , Pxx_den2 ax1.plot(f2, Pxx_den2) if flag==1: ax0.set_yscale('log') ax1.set_yscale('log') ax0.set_ylabel('periodogram (log scale)') ax1.set_ylabel('Welch\'s PSD [V**2/Hz] (log scale) ') plt.savefig(filename+'.pdf')
def plot_bin_riv(): paths = [#'/Users/user/Desktop/nagrania_eeg/binriv/Kuba_14_06_16/', '/Users/user/Desktop/nagrania_eeg/binriv/Karen_14_06_16/', '/Users/user/Desktop/nagrania_eeg/binriv/Ania_14_06_16/' ] for path in paths: recording = loading.Read_edf.Combine_EDF_XML(path,0,70) f, Pxx_den = signal.welch(recording['EEG P4'], fs = 498, nperseg=512) plt.figure() plt.plot(f, Pxx_den) epochs_before_info = {"response_changed": [ 498*5, 0] } epochs_before = prep.Epochs.Make_Epochs_for_Channels(recording, ['EEG P4'], epochs_before_info)['EEG P4'] epochs_after_info = {"response_changed": [0, 498*5] } epochs_after = prep.Epochs.Make_Epochs_for_Channels(recording, ['EEG P4'], epochs_after_info)['EEG P4'] epochs = {} epochs['P4'] = {'before_switch':epochs_before['response_changed'], 'after_switch': epochs_after['response_changed']} power_density= analysis.Explore.PlotPowerSpectrum(epochs['P4'], exact_sr =498, mode = 'welch', name = path, freq_min = 0, freq_max = 100)
def Power_Spectrum(ts, fs, dt): """Compute power spectral density (using psd welch)""" "ts: time series of measurement values" "fs: sampling frequency" "dt: detrend = None/'linear'/'constant'" "scal = 'density', normalized with units of V**2/hz" "scal = 'spectrum', units of V**2" ts[np.isnan(ts) == True] = nanmean(ts) # Gapfill the missing value nwindow = 9 # Number of windows to smooth data length = math.floor(len(ts) / nwindow) # Length calculated by deviding the window nwindow_fl = math.floor(log2(length)) # Number of windows with floor window length window = int(2 ** nwindow_fl) # segment_length ############################### nfft: Number of DFT points ############################### # The default nfft is the greater of 256 or the next power of 2 greater than the length of the segments. # The relation between segment length and the Number of DFT points: segment_length <= nfft # If nfft is greater than the segment length, the data is zero-padded. If nfft is less than the segment length, the segment is wrapped using datawrap to make the length equal to nfft ########################################################################################## ############################### welch's method for PSD ############################### # MATLAB function: pwelch(ts, segment_length, Number of overlapped window noverlap, Number of DFT points, fs,'onesided') # scipy method: pwelch(ts, fs, nperseg, noverlap, nfft, detrend, scaling) ########################################################################################## f, Pxx_den = signal.welch(ts, fs, nperseg=window, detrend=dt) return [f, Pxx_den]
def test_window_external(self): x = np.zeros(16) x[0] = 1 x[8] = 1 f, p = welch(x, 10, 'hann', nperseg=8) win = signal.get_window('hann', 8) fe, pe = welch(x, 10, win, nperseg=None) assert_array_almost_equal_nulp(p, pe) assert_array_almost_equal_nulp(f, fe) assert_array_equal(fe.shape, (5,)) # because win length used as nperseg assert_array_equal(pe.shape, (5,)) assert_raises(ValueError, welch, x, 10, win, nperseg=4) # because nperseg != win.shape[-1] win_err = signal.get_window('hann', 32) assert_raises(ValueError, welch, x, 10, win_err, nperseg=None) # win longer than signal
def test_axis_rolling(self): np.random.seed(1234) x_flat = np.random.randn(1024) _, p_flat = welch(x_flat) for a in range(3): newshape = [1,]*3 newshape[a] = -1 x = x_flat.reshape(newshape) _, p_plus = welch(x, axis=a) # Positive axis index _, p_minus = welch(x, axis=a-x.ndim) # Negative axis index assert_equal(p_flat, p_plus.squeeze(), err_msg=a) assert_equal(p_flat, p_minus.squeeze(), err_msg=a-x.ndim)
def test_nondefault_noverlap(self): x = np.zeros(64) x[::8] = 1 f, p = welch(x, nperseg=16, noverlap=4) q = np.array([0, 1./12., 1./3., 1./5., 1./3., 1./5., 1./3., 1./5., 1./6.]) assert_allclose(p, q, atol=1e-12)
def test_integer_onesided_even(self): x = np.zeros(16, dtype=np.int) x[0] = 1 x[8] = 1 f, p = welch(x, nperseg=8) assert_allclose(f, np.linspace(0, 0.5, 5)) assert_allclose(p, np.array([0.08333333, 0.15277778, 0.22222222, 0.22222222, 0.11111111]))
def test_detrend_external_nd_0(self): x = np.arange(20, dtype=np.float64) + 0.04 x = x.reshape((2,1,10)) x = np.rollaxis(x, 2, 0) f, p = welch(x, nperseg=10, axis=0, detrend=lambda seg: signal.detrend(seg, axis=0, type='l')) assert_allclose(p, np.zeros_like(p), atol=1e-15)
def dofft(sig,samplefrq,nperseg=512,detrend='constant'): """ Estimate power spectral density using Welch's method. For more informations on the Welch's method implemented in python, visit: http://docs.scipy.org/doc/scipy-dev/reference/generated/scipy.signal.welch.html Example: >>> frq,psd = dofft(sig=mySignal, samplefrq=mySampleFrq) Arguments: * sig: [numpy.array] signal * samplefrq: [int or float] sample frequency Returns: * frq: [numpy.array]frequencies * psd: [numpy.array]amplitudes """ # old crap... #siglength = sig.shape[0] #NFFT = nextpow2(siglength) ## NFFT = nextpow2(sig.shape(-1,)[0]) #amp = spfft.fft(sig.reshape(-1,),NFFT)/siglength #frq = samplefrq/2*np.linspace(0,1,NFFT/2+1) ## frq = spfft.fftfreq(siglength, (samplefrq)**-1) ## frq = frq[:NFFT/2+1] #amp = 2*abs(amp[:NFFT/2+1]) #return frq,amp frq, psd = spsig.welch(sig,fs=samplefrq, window='hanning', noverlap=None, nperseg=nperseg, return_onesided=True, scaling='density', axis=-1,detrend=detrend) return frq, psd
def test_integer_onesided_odd(self): x = np.zeros(16, dtype=np.int) x[0] = 1 x[8] = 1 f, p = welch(x, nperseg=9) assert_allclose(f, np.arange(5.0) / 9.0) assert_allclose(p, np.array([0.15958226, 0.24193954, 0.24145223, 0.24100919, 0.12188675]))
def process_samples(self): rs = self.scanner.sample_rate fc = self.center_frequency samples = self.raw.flatten() overlap_ratio = self.scanner.sampling_config.sweep_overlap_ratio win = get_window(self.scanner.sampling_config.window_type, NPERSEG) freqs, Pxx = welch(samples, fs=rs, window=win, nperseg=NPERSEG, scaling='density', return_onesided=False) iPxx = np.fft.irfft(Pxx) iPxx = self.translate_freq(iPxx, fc, rs) Pxx = np.abs(np.fft.rfft(iPxx.real)) freqs, Pxx = sort_psd(freqs, Pxx) f_ix = np.append(np.nonzero(freqs<-0.25e6), np.nonzero(freqs>0.25e6)) freqs = freqs[f_ix] Pxx = Pxx[f_ix] freqs += fc freqs /= 1e6 self.powers = Pxx if not np.array_equal(freqs, self.frequencies): print('freq not equal: %s, %s' % (self.frequencies.size, freqs.size)) self.frequencies = freqs self.collection.on_sample_set_processed(self) self.complete.set()
def PltUp(n): nonlocal DataPlot, SBInAmpF, FreqBand Block = True while True: try: Data = SoundQueue.get(block=Block) Data = Data * SBInAmpF # HWindow = signal.hanning(len(Data)//(Rate/1000)) F, PxxSp = signal.welch(Data, Rate, nperseg=64, noverlap=0, scaling='density') # Start = np.where(F > FreqBand[0])[0][0]-1 # End = np.where(F > FreqBand[1])[0][0]-1 BinSize = F[1] - F[0] RMS = sum(PxxSp * BinSize)**0.5 dB = 20*(math.log(RMS/MicSens_VPa, 10)) + 94 except Empty: break # Shift = len(Data) # DataPlot = np.roll(DataPlot, -Shift, axis=0) # DataPlot[-Shift:, 0] = Data Block = False for Col, Line in enumerate(Lines): print(dB, max(PxxSp)) Line.set_xdata(F) Line.set_ydata(PxxSp) return(Lines)
def _efficient_welch(data, sfreq): """Calls scipy.signal.welch with parameters optimized for greatest speed at the expense of precision. The window is set to ~10 seconds and windows are non-overlapping. Parameters ---------- data : array, shape (..., n_samples) The timeseries to estimate signal power for. The last dimension is assumed to be time. sfreq : float The sample rate of the timeseries. Returns ------- fs : array of float The frequencies for which the power spectra was calculated. ps : array, shape (..., frequencies) The power spectra for each timeseries. """ from scipy.signal import welch nperseg = min(data.shape[-1], 2 ** int(np.log2(10 * sfreq) + 1)) # next power of 2 return welch(data, sfreq, nperseg=nperseg, noverlap=0, axis=-1)
def PSD_using_scipy(ampl, fs): return signal.welch(ampl, fs, nperseg=1024, scaling= 'spectrum')
#Read chunks for i in range(1): y = x.read(round(RATE * SAMPLE_TIME)) w = 0 while w + 4 <= len(y): (l, r) = struct.unpack('<2h', y[w:w + 4]) # left & right samples lx.append(l) w += 4 x.stop_stream() # MIDI note off os.write(f, b'\x80' + struct.pack('B', nn) + b'\x7f') time.sleep(0.5) fr, pw = signal.welch(lx, RATE) b_1.append(pw) plt.figure() idx_0 = 0 for j in range(2): if j != idx_0: c = [] for k in range(len(b_1[0])): c.append(10. * numpy.log10(b_1[j][k] / b_1[idx_0][k])) plt.plot(fr, c, label='{0}'.format(j)) plt.xlim(0, 5000) # Frequency range to show plt.legend(loc='lower right')
def test_detrend_external(self): x = np.arange(10, dtype=np.float64) + 0.04 f, p = welch(x, nperseg=10, detrend=lambda seg: signal.detrend(seg, type='l')) assert_allclose(p, np.zeros_like(p), atol=1e-15)
def psd_calc_other_methods(df, prm: Mapping[str, Any]): ## scipy windows = signal.windows.dpss(180000, 2.5, Kmax=9, norm=2) signal.spectrogram ## Welch nperseg = 1024 * 8 freqs, psd_Ve = signal.welch(df.Ve, prm['fs'], nperseg=nperseg) freqs, psd_Vn = signal.welch(df.Vn, prm['fs'], nperseg=nperseg) ## use Spectrum module from spectrum import dpss def pmtm(x, eigenvalues, tapers, n_fft=None, method='adapt'): """Multitapering spectral estimation :param array x: the data :param eigenvalues: the window concentrations (eigenvalues) :param tapers: the matrix containing the tapering windows :param str method: set how the eigenvalues are used. Must be in ['unity', 'adapt', 'eigen'] :return: Sk (each complex), weights, eigenvalues Usually in spectral estimation the mean to reduce bias is to use tapering window. In order to reduce variance we need to average different spectrum. The problem is that we have only one set of data. Thus we need to decompose a set into several segments. Such method are well-known: simple daniell's periodogram, Welch's method and so on. The drawback of such methods is a loss of resolution since the segments used to compute the spectrum are smaller than the data set. The interest of multitapering method is to keep a good resolution while reducing bias and variance. How does it work? First we compute different simple periodogram with the whole data set (to keep good resolution) but each periodgram is computed with a differenttapering windows. Then, we average all these spectrum. To avoid redundancy and bias due to the tapers mtm use special tapers. from spectrum import data_cosine, dpss, pmtm data = data_cosine(N=2048, A=0.1, sampling=1024, freq=200) [tapers, eigen] = dpss(2048, 2.5, 4) res = pmtm(data, eigenvalues=eigen, tapers=tapers, show=False) .. versionchanged:: 0.6.2a The most of spectrum.pmtm original code is to calc PSD but it is not returns so here we return it + Removed redandand functionality (calling semilogy plot and that what included in spectrum.dpss) """ assert method in ['adapt', 'eigen', 'unity'] N = len(x) if eigenvalues is not None and tapers is not None: eig = eigenvalues[:] tapers = tapers[:] else: raise ValueError( "if eigenvalues provided, v must be provided as well and viceversa." ) nwin = len(eig) # length of the eigen values vector to be used later if n_fft is None: n_fft = max(256, 2**np.ceil(np.log2(N)).astype('int')) Sk_complex = np.fft.fft(tapers.transpose() * x, n_fft) # if nfft < N, cut otherwise add zero. Sk = (Sk_complex * Sk_complex.conj()).real # abs() ** 2 if method in ['eigen', 'unity']: if method == 'unity': weights = np.ones((nwin, 1)) elif method == 'eigen': # The S_k spectrum can be weighted by the eigenvalues, as in Park et al. weights = np.array( [_x / float(i + 1) for i, _x in enumerate(eig)]) weights = weights.reshape(nwin, 1) Sk = np.mean(Sk * weights, axis=0) elif method == 'adapt': # This version uses the equations from [2] (P&W pp 368-370). Sk = Sk.transpose() S = Sk[:, :2].mean() # Initial spectrum estimate # Set tolerance for acceptance of spectral estimate: sig2 = np.dot(x, x) / float(N) tol = 0.0005 * sig2 / float(n_fft) a = sig2 * (1 - eig) # Wrap the data modulo nfft if N > nfft S = S.reshape(n_fft, 1) for i in range( 100): # converges very quickly but for safety; set i<100 # calculate weights b1 = np.multiply(S, np.ones((1, nwin))) b2 = np.multiply(S, eig.transpose()) + np.ones( (n_fft, 1)) * a.transpose() b = b1 / b2 # calculate new spectral estimate weights = (b**2) * (np.ones((n_fft, 1)) * eig.transpose()) S1 = ((weights * Sk).sum(axis=1, keepdims=True) / weights.sum(axis=1, keepdims=True)) S, S1 = S1, S if np.abs(S - S1).sum() / n_fft < tol: break Sk = (weights * Sk).mean(axis=1) if np.isrealobj( x ): # Double to account for the energy in the negative frequencies if prm['n_fft'] % 2 == 0: Sk = 2 * Sk[:int(prm['n_fft'] / 2 + 1)] else: Sk = 2 * Sk[:int((prm['n_fft'] + 1) / 2)] return Sk_complex, Sk, weights prm['dpss_sp'], prm['eigvals_sp'] = dpss(prm['n_fft'], 3.5) sk_complex_Ve, sk_Ve_, weights_Ve = pmtm( df.Ve.values, prm['eigvals_sp'], prm['dpss_sp']) # n_fft=prm['n_fft'] sk_complex_Vn, sk_Vn_, weights_Vn = pmtm(df.Vn.values, prm['eigvals_sp'], prm['dpss_sp']) # Convert Power Spectrum to Power Spectral Density record_time_length = prm['length'] * prm['dt'] sk_Ve = sk_Ve_ / record_time_length sk_Vn = sk_Vn_ / record_time_length
if (Heart_rate[i] < Heart_rate_DOWN_Val): count += 1 Heart_rate_DOWN = count / Heart_rate.size * 100 ECG_features = [IBI_MEAN] ECG_features.append(IBI_STD) ECG_features.append(IBI_SKEW) ECG_features.append(IBI_KURTOSIS) ECG_features.append(IBI_UP) ECG_features.append(IBI_DOWN) ECG_features.append(Heart_rate_MEAN) ECG_features.append(Heart_rate_STD) ECG_features.append(Heart_rate_SKEW) ECG_features.append(Heart_rate_KURTOSIS) ECG_features.append(Heart_rate_UP) ECG_features.append(Heart_rate_DOWN) f_dash, Pxx_den = signal.welch(sig, fs=sampling_freq, nfft=100000) Pxx_den = list(Pxx_den) for i in range(5): ECG_features.append(Pxx_den[i]) for i in range(0, 255, 24): ECG_features.append(Pxx_den[i]) with open(fnamex, 'w', newline='') as file: writer = csv.writer(file) writer.writerow([ ECG_features[0], ECG_features[1], ECG_features[2], ECG_features[3], ECG_features[4], ECG_features[5], ECG_features[6], ECG_features[7], ECG_features[8], ECG_features[9], ECG_features[10], ECG_features[11], ECG_features[12], ECG_features[13], ECG_features[14], ECG_features[15], ECG_features[16], ECG_features[17], ECG_features[18], ECG_features[19], ECG_features[20], ECG_features[21], ECG_features[22], ECG_features[23], ECG_features[24], ECG_features[25], ECG_features[26], ECG_features[27],
def welch_psd(nni=None, rpeaks=None, fbands=None, nfft=2**12, detrend=True, window='hamming', show=True, show_param=True, legend=True, mode='normal'): """Computes a Power Spectral Density (PSD) estimation from the NNI series using the Welch’s method and computes all frequency domain parameters from this PSD according to the specified frequency bands. References: [Electrophysiology1996], [Umberto2017], [Welch2017] Docs: https://pyhrv.readthedocs.io/en/latest kwa/_pages/api/frequency.html#welch-s-method-welch-psd Parameters ---------- nni : array NN-Intervals in [ms] or [s] rpeaks : array R-peak locations in [ms] or [s] fbands : dict, optional Dictionary with frequency bands (2-element tuples or list) Value format: (lower_freq_band_boundary, upper_freq_band_boundary) Keys: 'ulf' Ultra low frequency (default: none) optional 'vlf' Very low frequency (default: (0.000Hz, 0.04Hz)) 'lf' Low frequency (default: (0.04Hz - 0.15Hz)) 'hf' High frequency (default: (0.15Hz - 0.4Hz)) nfft : int, optional Number of points computed for the FFT result (default: 2**12) detrend : bool optional If True, detrend NNI series by subtracting the mean NNI (default: True) window : scipy window function, optional Window function used for PSD estimation (default: 'hamming') show : bool, optional If true, show PSD plot (default: True) show_param : bool, optional If true, list all computed PSD parameters next to the plot (default: True) legend : bool, optional If true, add a legend with frequency bands to the plot (default: True) Returns ------- results : biosppy.utils.ReturnTuple object All results of the Welch's method's PSD estimation (see list and keys below) Returned Parameters & Keys -------------------------- .. Peak frequencies of all frequency bands in [Hz] (key: 'fft_peak') .. Absolute powers of all frequency bands in [ms^2][(key: 'fft_abs') .. Relative powers of all frequency bands [%] (key: 'fft_rel') .. Logarithmic powers of all frequency bands [-] (key: 'fft_log') .. Normalized powers of all frequency bands [-] (key: 'fft_norms') .. LF/HF ratio [-] (key: 'fft_ratio') .. Total power over all frequency bands in [ms^2] (key: 'fft_total') .. Interpolation method used for NNI interpolation (key: 'fft_interpolation') .. Resampling frequency used for NNI interpolation (key: 'fft_resampling_frequency') .. Spectral window used for PSD estimation of the Welch's method (key: 'fft_spectral_window)' Notes ----- .. The returned BioSPPy ReturnTuple object contains all frequency band parameters in parameter specific tuples of length 4 when using the ULF frequency band or of length 3 when NOT using the ULF frequency band. The structures of those tuples are shown in this example below (fft_results = ReturnTuple object returned by this function): Using ULF, VLF, LF and HF frequency bands: fft_results['fft_peak'] = (ulf_peak, vlf_peak, lf_peak, hf_peak) Using VLF, LF and HF frequency bands: fft_results['fft_peak'] = (vlf_peak, lf_peak, hf_peak) .. If 'show_param' is true, the parameters (incl. frequency band limits) will be listed next to the graph and no legend with frequency band limits will be added to the plot graph itself, i.e. the effect of 'show_param' will be used over the 'legend' effect. .. Only one type of input data is required. .. If both 'nni' and 'rpeaks' are provided, 'rpeaks' will be chosen over the 'nni' and the 'nni' data will be computed from the 'rpeaks'. .. NN and R-peak series provided in [s] format will be converted to [ms] format. s """ # Check input values nn = tools.check_input(nni, rpeaks) # Verify or set default frequency bands fbands = _check_freq_bands(fbands) # Resampling (with 4Hz) and interpolate # Because RRi are unevenly spaced we must interpolate it for accurate PSD estimation. fs = 4 t = np.cumsum(nn) t -= t[0] f_interpol = sp.interpolate.interp1d(t, nn, 'cubic') t_interpol = np.arange(t[0], t[-1], 1000. / fs) nn_interpol = f_interpol(t_interpol) # Subtract mean value from each sample for surpression of DC-offsets if detrend: nn_interpol = nn_interpol - np.mean(nn_interpol) # Adapt 'nperseg' according to the total duration of the NNI series (5min threshold = 300000ms) if t.max() < 300000: nperseg = nfft else: nperseg = 300 # Compute power spectral density estimation (where the magic happens) frequencies, powers = welch(x=nn_interpol, fs=fs, window=window, nperseg=nperseg, nfft=nfft, scaling='density') # Metadata args = (nfft, window, fs, 'cubic') names = ( 'fft_nfft', 'fft_window', 'fft_resampling_frequency', 'fft_interpolation', ) meta = utils.ReturnTuple(args, names) if mode not in ['normal', 'dev', 'devplot']: warnings.warn("Unknown mode '%s'. Will proceed with 'normal' mode." % mode, stacklevel=2) mode = 'normal' # Normal Mode: # Returns frequency parameters, PSD plot figure and no frequency & power series/arrays if mode == 'normal': # Compute frequency parameters params, freq_i = _compute_parameters('fft', frequencies, powers, fbands) # Plot PSD figure = _plot_psd('fft', frequencies, powers, freq_i, params, show, show_param, legend) figure = utils.ReturnTuple((figure, ), ('fft_plot', )) # Output return tools.join_tuples(params, figure, meta) # Dev Mode: # Returns frequency parameters and frequency & power series/array; does not create a plot figure nor plot the data elif mode == 'dev': # Compute frequency parameters params, _ = _compute_parameters('fft', frequencies, powers, fbands) # Output return tools.join_tuples(params, meta), frequencies, (powers / 10**6) # Devplot Mode: # Returns frequency parameters, PSD plot figure, and frequency & power series/arrays elif mode == 'devplot': # Compute frequency parameters params, freq_i = _compute_parameters('fft', frequencies, powers, fbands) # Plot PSD figure = _plot_psd('fft', frequencies, powers, freq_i, params, show, show_param, legend) figure = utils.ReturnTuple((figure, ), ('fft_plot', )) # Output return tools.join_tuples(params, figure, meta), frequencies, (powers / 10**6)
#Set montage (3d electrode location) raw = raw.set_montage('standard_1020') #Create events every w1 seconds sf = 250 w1 = 2 events_array = createEvenlySpaceEvents(rawArray.shape[1], w1, sf) #Create Epochs epochs = mne.Epochs(raw, events_array, tmin=-(w1 / 2 - 0.02 * w1), tmax=(w1 / 2 - 0.02 * w1)) #Get data as numpy array epochsArray = epochs.get_data(picks=['eeg']) numbOfEpochs = epochsArray.shape[0] win = int(1.8 * sf) # Window size is set to 4 seconds freqs, psd = welch(epochsArray, sf, nperseg=win, axis=-1) # Calculate the bandpower on 3-D PSD array bands = [(0.5, 4, 'Delta'), (4, 8, 'Theta'), (8, 12, 'Alpha'), (12, 16, 'Sigma'), (16, 30, 'Beta')] bandpower = yasa.bandpower_from_psd_ndarray(psd, freqs, bands) bandpower = bandpower.transpose([1,0,2]).reshape((numbOfEpochs,-1)) #Shape should be (#ofEpochs, #OfChannels*#ofbands) print(bandpower.shape) with open(dstPath / file.with_suffix(".pickle").name, 'wb') as outF: pickle.dump(bandpower,outF) x = 0
import audio_functions import numpy as np from scipy import signal import matplotlib.pyplot as plt duration = 5.0 fs = 44100 buffer_length = 1024 input('Press Enter when ready to record a sample') samples = audio_functions.record(duration, fs, buffer_length) print('Finished recording, now plotting recorded audio') # print(samples) f, psd = signal.welch(samples, fs, nperseg=1024)
def getSpectra(self, FIRST_SAMPLE, LAST_SAMPLE, *args): if 'mod' in args: print('\nplotting spectra for MODULATED units and stimulus') spikes = self.unitsXspikesLst_mod elif not 'mod' in args: print('\nplotting spectra for units and stimulus') spikes = self.unitsXspikesLst totalStimDurationSecs = LAST_SAMPLE - FIRST_SAMPLE ### in secs if totalStimDurationSecs > 10: ## stimulus duration must be longer than 10 secs to plot it plotSine = True else: plotSine = False FIRST_SAMPLE = 0 LAST_SAMPLE = np.max(np.max(spikes)) totalStimDurationSecs = LAST_SAMPLE - FIRST_SAMPLE ### in secs ### neuron's bin'd sample rate numBins, remainderSecs = np.divmod( totalStimDurationSecs, BIN_SIZE_SEC ) ### totalStimDuration is from 0 to the last spike time if no TTLs are present bins = np.linspace(FIRST_SAMPLE, FIRST_SAMPLE + round(float(numBins) * float(BIN_SIZE_SEC)), int(numBins), endpoint=True) binSampleRate = 1. / np.mean(np.diff(bins)) print('binSampleRate = {0}'.format(binSampleRate)) ### Welch PSD ### sine stimulus if plotSine == True: ### sine stim's bin'd sample rate try: sineStimSampleRate = self.sine_vals.shape[ 0] / totalStimDurationSecs except: sys.exit( '\n\nERROR: You probably need to uncomment data.reconstructSineFromTTLs(TTL_values, TTL_times) below to get the TTLs...\n\n' ) print('sineStimSampleRate = {0}'.format(sineStimSampleRate)) welchFreqs_sine, Pxx_den = welch( self.sine_vals, nperseg=sineStimSampleRate * 100, fs=sineStimSampleRate ) ######## TO DO: Fix the sample rate }{ time units ### set up figure assuming the sine is present NUM_ROWS = 3 NUM_COLUMNS = 1 ### gridspec.GridSpec(NUM_ROWS,NUM_COLUMNS) # state-based versions for subplot ### plt.subplot(611) ### doesn't require gridspec but is kinda clunky for dynamic changes FIG_SIZE = (NUM_ROWS, NUM_COLUMNS) fig = plt.figure(figsize=FIG_SIZE) rowPosition = 0 columnPosition = 0 ### sine stimulus ax1 = plt.subplot2grid((NUM_ROWS, NUM_COLUMNS), (rowPosition, columnPosition)) rowPosition += 1 ax1.set_title('sine stimulus Welch PSD') ax1.set_xlabel('frequency [Hz]') ax1.set_ylabel('PSD [V**2/Hz?]') ax1.semilogy(welchFreqs_sine, Pxx_den, '-o') ax1.set_xlim(0, MAX_FREQ_PLOTTED) elif plotSine == False: print( 'sine stimulus sample rate calculation failed (this is expected if there are no TTLs for this recording)' ) ### set up the figure if there's no sine stimulus NUM_ROWS = 2 NUM_COLUMNS = 1 FIG_SIZE = (NUM_ROWS, NUM_COLUMNS) fig = plt.figure(figsize=FIG_SIZE) rowPosition = 0 columnPosition = 0 ### neurons ax2 = plt.subplot2grid((NUM_ROWS, NUM_COLUMNS), (rowPosition, columnPosition)) rowPosition += 1 ax2.set_title('neurons\' Welch PSD (sci py ver)') ax2.set_xlabel('frequency [Hz]') ax2.set_ylabel('PSD [V**2/Hz?]') ax2.set_xlim(0, MAX_FREQ_PLOTTED) ax3 = plt.subplot2grid((NUM_ROWS, NUM_COLUMNS), (rowPosition, columnPosition)) rowPosition += 1 ax3.set_title('neurons\' PSD (matplotlib ver)') ax3.set_xlim(0, MAX_FREQ_PLOTTED) # ax4 = plt.subplot2grid((NUM_ROWS, NUM_COLUMNS), (rowPosition,columnPosition)) # rowPosition += 1 # ax4.set_title('neurons\' magnitude spectrum') # ax4.set_xlim(0, MAX_FREQ_PLOTTED) # ax5 = plt.subplot2grid((NUM_ROWS, NUM_COLUMNS), (rowPosition,columnPosition)) # rowPosition += 1 # ax5.set_title('neurons\' spectrogram') # ax5.set_ylabel('Freq in Hz') # ax5.set_xlabel('time in Secs') # ax5.set_ylim(0,100) if UNITS_PLOTTED == [0, 0]: firstUnit = 0 lastUnit = len(spikes) - 1 ### return to original after debugging else: firstUnit = UNITS_PLOTTED[0] lastUnit = UNITS_PLOTTED[-1] unitXfreqLst = [] for unit in range(firstUnit, lastUnit + 1): t = "unit: {0}".format(unit) print(t) # unit_hist, binEdges = np.histogram(spikes[unit], bins, (FIRST_SAMPLE, LAST_SAMPLE)) unit_hist, binEdges = np.histogram(spikes[unit], bins) ### Welch PSD welchFreqs_neuron, Pxx_den = welch( unit_hist, fs=binSampleRate, # sample rate window='hanning', # apply a Hanning window before taking the DFT nperseg=self.sampleRate / 10, # number of samples to include in the sliding window detrend='constant' ) ################################################################################## is detrending appropriate? unitXfreqLst.append([welchFreqs_neuron, Pxx_den]) ax2.semilogy(welchFreqs_neuron, Pxx_den, '-o', label=str(unit)) # ax2.plot(welchFreqs_neuron,Pxx_den, '-o') # ax2.legend(['unit: {0}'.format(unit)]) ### Welch PSD # ax3.psd(unit_hist, binSampleRate, pad_to=1024, detrend = 'mean') # ax3.psd(unit_hist, Fs= binSampleRate, NFFT= self.sampleRate, marker='o') ### <-- probably closer to working ### magnitude spectrum # ax4.magnitude_spectrum(unit_hist, Fs = binSampleRate, scale = 'dB', marker = 'o') # try: # ax4.magnitude_spectrum(unit_hist, Fs = binSampleRate, marker = 'o') # except: # print('magnitude spectrum threw an error for unit {0};\n error: noverlap must be less than n'.format(unit)) ### Spectrogram # Pxx, freqs, bins, im = ax5.specgram(spikes[unit], Fs=self.sampleRate, noverlap=100) # Pxx, freqs, bins, im = ax5.specgram(unit_hist, Fs=self.sampleRate, noverlap=100) # Pxx, freqs, bins, im = ax5.specgram(unit_hist, Fs= binSampleRate) ### TO DO: FIX RUNTIME WARNING: DIVIDE BY ZERO # fig.colorbar(im).set_label('Intensity [dB]') # fig.tight_layout() fig.subplots_adjust(hspace=1.0) fig.set_size_inches(w=15, h=8) fig_name = 'plot.png' fig.savefig(fig_name) if 'plot' in args: plt.show() ### TO DO: save plots to output dir if 'mod' in args: self.allPSDsLst_mod = unitXfreqLst else: self.unitXfreqLst = unitXfreqLst return unitXfreqLst
envelope_oi = envelope(outputi) # Noisy echoes N = 0.5 noise = np.random.normal(0, N, t.size) noisy_echoes = echoes + noise # Matched filter output both echoes with noise noisy_output = np.convolve(matched, noisy_echoes)*Ts noisy_output = noisy_output[:t.size] # Envelope of matched filter output with noise noisy_envelope_o = envelope(noisy_output) # Noise FFT Nfreq, Nabs = welch(noise, 1/Ts, nperseg=noise.size) # Plot of Signal # Plot of FFT plt.figure() plt.subplot(3, 1, 1) plt.plot(t[t<1.5*tau], signal[t<1.5*tau]) plt.plot(tpulse, phase, 'r--', lw=1) plt.plot(tpulse[tpulse<=tphase*l], phase[tpulse<=tphase*l], 'r', lw=1) plt.title("Binary Pulses") plt.xlabel("time [us]") plt.ylabel("amplitude") plt.legend(["signal", "baker code"], loc='upper right') plt.grid(True) plt.subplot(3, 1, 2) plt.plot(freq[freq<2*f], Sabs[freq<2*f])
def test_detrend_linear(self): x = np.arange(10, dtype=np.float64) + 0.04 f, p = welch(x, nperseg=10, detrend='linear') assert_allclose(p, np.zeros_like(p), atol=1e-15)
def frequency_features(ts, RR, sampling_rate=4.0): """Compute frequency-domain HRV features. Parameters ---------- ts : array Input time reference. RR : array Input RR signal. sampling_rate : int, float, optional Sampling frequency for resampled signal. Returns ------- its : array Interpolated RR time reference. iRR : array Interpolated instantaneous RR intervals. iHR : array Interpolated instantaneous heart rate. VLF : float Very low frequency band power [0.003, 0.04) Hz. LF : float Low frquency band power [0.04, 0.15) Hz. HF : float High frequency band power [0.15, 0.4) Hz. TF : float Total power in the VLF, LF, and HF bands. L2HF : float Ratio of LF to HF power. nuLF : float LF power in normalized units. nuHF : float HF power in normalized units. """ # resample its, iRR = rr_resample(ts, RR, sampling_rate=sampling_rate) iHR = 60. / iRR size = int(5 * sampling_rate) f, pwr = ss.welch(iRR, sampling_rate, window='hann', nperseg=size, noverlap=size/2, nfft=1024, scaling='density') # VLF idx = np.logical_and(0.003 <= f, f < 0.04) x = f[idx] y = pwr[idx] VLF = metrics.auc(x, y) # LF idx = np.logical_and(0.04 <= f, f < 0.15) x = f[idx] y = pwr[idx] LF = metrics.auc(x, y) # HF idx = np.logical_and(0.15 <= f, f < 0.4) x = f[idx] y = pwr[idx] HF = metrics.auc(x, y) TF = VLF + LF + HF L2HF = LF / HF nuLF = LF / (TF - VLF) nuHF = HF / (TF - VLF) return its, iRR, iHR, VLF, LF, HF, TF, L2HF, nuLF, nuHF, f, pwr
def elevation_spectrum(eta, sample_rate, nnft, window='hann', detrend=True, noverlap=None): """ Calculates the wave energy spectrum from wave elevation time-series Parameters ------------ eta: pandas DataFrame Wave surface elevation [m] indexed by time [datetime or s] sample_rate: float Data frequency [Hz] nnft: integer Number of bins in the Fast Fourier Transform window: string (optional) Signal window type. 'hann' is used by default given the broadband nature of waves. See scipy.signal.get_window for more options. detrend: bool (optional) Specifies if a linear trend is removed from the data before calculating the wave energy spectrum. Data is detrended by default. noverlap: int, optional Number of points to overlap between segments. If None, ``noverlap = nperseg / 2``. Defaults to None. Returns --------- S: pandas DataFrame Spectral density [m^2/Hz] indexed by frequency [Hz] """ # TODO: Add confidence intervals, equal energy frequency spacing, and NDBC # frequency spacing # TODO: may need an assert for the length of nnft- signal.welch breaks when nfft is too short # TODO: check for uniform sampling assert isinstance(eta, pd.DataFrame), 'eta must be of type pd.DataFrame' assert isinstance(sample_rate, (float, int)), 'sample_rate must be of type int or float' assert isinstance(nnft, int), 'nnft must be of type int' assert isinstance(window, str), 'window must be of type str' assert isinstance(detrend, bool), 'detrend must be of type bool' assert nnft > 0, 'nnft must be > 0' assert sample_rate > 0, 'sample_rate must be > 0' S = pd.DataFrame() for col in eta.columns: data = eta[col] if detrend: data = _signal.detrend(data.dropna(), axis=-1, type='linear', bp=0) [f, wave_spec_measured] = _signal.welch(data, fs=sample_rate, window=window, nperseg=nnft, nfft=nnft, noverlap=noverlap) S[col] = wave_spec_measured S.index = f S.columns = eta.columns return S
linestyle='--', color="#3498db") plt.xlim([0, 69]) plt.ylim([0, 1.01]) plt.show() plt.savefig('1usa-germany.svg') dates, infections_perday, deaths_perday = compute_ma() s1 = infections_perday[offset + 40:] s2 = deaths_perday[offset + 40:] f, p1 = welch(s1, nperseg=20, noverlap=19, detrend='linear', nfft=256, scaling='density') f, p2 = welch(s2, nperseg=20, noverlap=19, detrend='linear', nfft=256, scaling='density') plt.figure() plt.plot(1 / f, p1 / p1.max(), linewidth=2) plt.xlim([2, 20]) plt.plot(1 / f, p2 / p2.max(), linewidth=2) plt.xlim([2, 20]) dates, infections_perday, deaths_perday = compute_ma('germany')
def process( auscultation_signal, sr, start=0, # time end=0, # time original_spectrum=0, original_time_freq=0, bandpass_filter=1, bandpass_graph=0, bandpass_spectrum=0, bandpass_time_freq=0, export_bandpass=0, # .mat (1), .wav (2) wavelet=1, x_min=0, x_max=0, level=4, thershold='Minimax', # Universal, Minimax ponder='Multi nivel', # Comun, Primer nivel, Multi nivel hardness='Suave', # Duro, Suave see='Comparar', # Ver filtrada, Ver original, Comparar, Aprox y detalles, Multi nivel, Detalles filtrados, Multi nivel wavelet_graph=0, wavelet_spectrum=0, wavelet_time_freq=0, export_wavelet=0, # .mat (1), .wav (2) compare=0): if end == 0: end = len(auscultation_signal) if (x_max == 0): x_max = len(auscultation_signal) elif (x_max < x_min): x_min = 0 x_max = len(auscultation_signal) elif (x_max > len(auscultation_signal)): x_max = len(auscultation_signal) time = np.arange(0, len(auscultation_signal) / sr, 1 / sr) # Original Signal # Show spectrum of the signal if original_spectrum == 1: plt.figure() f, Pxx = signal.welch( auscultation_signal[(time >= start) & (time <= end)], sr, 'hanning', sr * 2, sr) plt.title('Original Signal Spectrum') plt.plot(f, Pxx) plt.xlabel('Frequency') plt.ylabel('Pxx') # Show time freq analysis if original_time_freq == 1: n_mels = 128 hop_length = 256 # 2^8 = 256 n_fft = 1024 # 2^10 = 1024 plt.figure() S = librosa.feature.melspectrogram( auscultation_signal[(time >= start) & (time <= end)], sr=sr, n_fft=n_fft, hop_length=hop_length, n_mels=n_mels) S_DB = librosa.power_to_db(S, ref=np.max) librosa.display.specshow(S_DB, sr=sr, hop_length=hop_length, x_axis='time', y_axis='mel') plt.colorbar(format='%+2.0f dB') plt.title('Original Signal Time-Frequency') # BandPass # Filter the signal with a bandpass with cutoff[100:1000] # (Fs, LowCutOff, HighcutOff, RevFilt, Signal, Graph response) if bandpass_filter == 1: if bandpass_graph != 1: bandpass_graph = 0 filter_generated = generate_filter(sr, 100, 1000, 0, auscultation_signal, graph=bandpass_graph) bandpass_signal = apply_filter(filter_generated, auscultation_signal) bandpass_signal = np.asfortranarray(bandpass_signal) # Show spectrum of the signal after BandPass if bandpass_spectrum == 1: plt.figure() f, Pxx = signal.welch(bandpass_signal[(time >= start) & (time <= end)], sr, 'hanning', sr * 2, sr) plt.title('After BandPass Signal Spectrum') plt.plot(f, Pxx) plt.xlabel('Frequency') plt.ylabel('Pxx') # Show time freq analysis after BandPass filter if bandpass_time_freq == 1: n_mels = 128 hop_length = 256 # 2^8 = 256 n_fft = 1024 # 2^10 = 1024 plt.figure() S = librosa.feature.melspectrogram(bandpass_signal[(time >= start) & (time <= end)], sr=sr, n_fft=n_fft, hop_length=hop_length, n_mels=n_mels) S_DB = librosa.power_to_db(S, ref=np.max) librosa.display.specshow(S_DB, sr=sr, hop_length=hop_length, x_axis='time', y_axis='mel') plt.colorbar(format='%+2.0f dB') plt.title('After BandPass Signal Time-Frequency') # Export Wavelet to: .mat (1) or .wav (2) if export_bandpass == 1: sio.savemat( 'filtered_by_bandpass.mat', {'filtered': bandpass_signal[(time >= start) & (time <= end)]}) elif export_bandpass == 2: sio.savemat('filtered_by_bandpass.mat', {'filtered': bandpass_signal}) # Wavelet # Apply Wavelet Filter if wavelet == 1: x_min = x_min x_max = x_max graph = wavelet_graph level = level thershold = thershold # Universal, Minimax ponder = ponder # Comun, Primer nivel, Multi nivel hardness = hardness # Duro, Suave see = see # Ver filtrada, Ver original, Comparar, Aprox y detalles, Multi nivel, Detalles filtrados, Multi nivel signal_after_wavelet = procesador.wavelet(bandpass_signal, x_min, x_max, graph, level, thershold, ponder, hardness, see) # 2nd BandPass filtered_signal = apply_filter(filter_generated, signal_after_wavelet) filtered_signal = np.asfortranarray(filtered_signal) # Show spectrum of the signal after wavelet filter if wavelet_spectrum == 1: plt.figure() f, Pxx = signal.welch(filtered_signal[(time >= start) & (time <= end)], sr, 'hanning', sr * 2, sr) plt.title('After Wavelet Spectrum') plt.plot(f, Pxx) plt.xlabel('Frequency') plt.ylabel('Pxx') # Show time freq analysis after wavelet filter if wavelet_time_freq == 1: n_mels = 128 hop_length = 256 # 2^9 n_fft = 1024 # 2^11 plt.figure() S = librosa.feature.melspectrogram(filtered_signal[(time >= start) & (time <= end)], sr=sr, n_fft=n_fft, hop_length=hop_length, n_mels=n_mels) S_DB = librosa.power_to_db(S, ref=np.max) librosa.display.specshow(S_DB, sr=sr, hop_length=hop_length, x_axis='time', y_axis='mel') plt.colorbar(format='%+2.0f dB') plt.title('After Wavelet Time-Frequency') # Export Wavelet to: .mat (1) or .wav (2) if export_wavelet == 1: sio.savemat( 'filtered_by_wavelet.mat', {'filtered': filtered_signal[(time >= start) & (time <= end)]}) elif export_wavelet == 2: librosa.output.write_wav( 'nivel_' + str(level) + '_' + str(thershold) + '_' + str(ponder) + '_' + str(hardness) + '.wav', 10 * filtered_signal[(time >= start) & (time <= end)], sr) # Compare Signals if compare == 1: plt.figure() plt.subplot(3, 1, 1) plt.title('Original') librosa.display.waveplot(auscultation_signal[(time >= start) & (time <= end)], sr=sr) plt.grid() plt.subplot(3, 1, 2) plt.title('BandPass') librosa.display.waveplot(bandpass_signal[(time >= start) & (time <= end)], sr=sr) plt.grid() plt.subplot(3, 1, 3) plt.title('BandPass + Wavelet + BandPass') librosa.display.waveplot(filtered_signal[(time >= start) & (time <= end)], sr=sr) plt.grid() plt.tight_layout() return time, filtered_signal[(time >= start) & (time <= end)]
import numpy as np ut = utility.Utility_Functions() import matplotlib.pyplot as plt # print("s" , ut.condLFP_data.shape) # print("s" , ut.LFP_data.shape) for i in range(1, 9): trials1 = ut.LFP_data[ut.condLFP_data[:, 0] == i] trials2 = ut.LFP_data[ut.condLFP_data[:, 0] == i + 8] # print(trials1.shape) # trials2 = ut.LFP_data[:, (ut.condLFP_data == i+8).squeeze()] print(trials1.shape) print(trials2.shape) trials = list(trials1) + list(trials2) trials = np.array(trials) freqs, psd = signal.welch(trials[0, 2700:3200]) # plt.figure(figsize=(5, 4) ) plt.subplot(2, 4, i) plt.semilogx(freqs, psd) plt.title('PSD: power spectral density for angel ' + str(i) + "\n in time [2700,3200]") plt.xlabel('Frequency') plt.ylabel('Power') plt.tight_layout() plt.subplots_adjust(left=0.02, wspace=0.5, bottom=0.06, hspace=0.5) plt.show() np.random.seed(0) time_step = .01
def power_spectral_density(data: np.ndarray, band: Tuple[float, float], sampling_rate: float = 100.0, window_length: float = 4.0, plot: bool = False, method: PSD_TYPE = PSD_TYPE.WELCH, relative=False): """Power spectral density: Many thanks to: https://raphaelvallat.github.io/bandpower.html Parameters ---------- data: Numpy Array. Time series data in the form of a numpy ndarray used to estimate the power spectral density. band: tuple. frequency band psd to export. Note this must be within the Nyquist frequency for your data. Approximated as sampling rate / 2. sampling_rate: float Sampling rate of the data in # of samples per second. window_length: float Length in seconds of data window. plot: boolean. Whether of not to plot the PSD estimated. Helpful for debugging and exploration. method: PSD_TYPE Type of PSD estimation method to use during calculation. relative: boolean Whether or not to express the power in a frequency band as a percentage of the total power of the signal. """ band = np.asarray(band) low, high = band # Compute the modified periodogram (Welch) if method == PSD_TYPE.WELCH: nperseg = window_length * sampling_rate freqs, psd = welch(data, sampling_rate, nperseg=nperseg) # Compute the modified periodogram (MultiTaper) elif method == PSD_TYPE.MULTITAPER: psd, freqs = psd_array_multitaper(data, sampling_rate, adaptive=True, normalization='full', verbose=False) # Find index of band in frequency vector idx_band = np.logical_and(freqs >= low, freqs <= high) # Frequency resolution freq_res = freqs[1] - freqs[0] # Integral approximation of the spectrum using parabola (Simpson's rule) bp = simps(psd[idx_band], dx=freq_res) # Plot the power spectrum if plot: sns.set(font_scale=1.2, style='white') plt.figure(figsize=(8, 4)) plt.plot(freqs, psd, color='k', lw=2) plt.xlabel('Frequency (Hz)') plt.ylabel('Power spectral density (V^2 / Hz)') plt.ylim([0, psd.max() * 1.1]) plt.title(f'{method.value}') plt.xlim([0, sampling_rate / 2]) sns.despine() plt.show() # Whether or not to return PSD as a percentage of total power if relative: bp /= simps(psd, dx=freq_res) return bp
def analyze_line_delay(filename, diagnostic_plots=False): ''' Analyze the file delay from a tagged file. :param filename: the name of the file containing the delay data. :param diagnostic_plots: saves two diagnostic plots in png. :return: the delay in seconds. ''' print_debug("Analyzing line delay info form file: \'%s\' ..." % (filename)) decimation = 2 zz = signal.decimate(openH5file(filename)[0], decimation, ftype="fir") info = get_rx_info(filename, ant=None) decimation *= info['decim'] freq, Pxx = signal.welch(zz.real, nperseg=len(zz), fs=int(info['rate'] / float(decimation)), detrend='linear', scaling='density') if diagnostic_plots: diag_fig = pl.figure() pl.plot(zz.real, label="real") pl.plot(zz.imag, label="imag") pl.plot(np.abs(zz), label="abs") pl.title("Delay acquisition diagnostic.\n total decimation: %d" % decimation) pl.xlabel("Samples") pl.ylabel("ADCu") pl.legend() pl.grid() pl.savefig("Delay_diagnostic.png") pl.close(diag_fig) diag_fig = pl.figure() pl.plot(np.angle(zz), label="angle") pl.title("Delay acquisition diagnostic.\n total decimation: %d" % decimation) pl.xlabel("Samples") pl.ylabel("ADCu") pl.legend() pl.grid() pl.savefig("Delay_diagnostic_phase.png") pl.close(diag_fig) diag_fig = pl.figure() pl.title("Delay acquisition diagnostic.") Pxx = 20 * np.log10(Pxx) pl.xlabel("Frequency [Hz]") pl.ylabel("ADC dB") pl.semilogx(freq, Pxx, label="real") pl.legend() pl.grid() pl.savefig("Delay_diagnostic_FFT.png") pl.close(diag_fig) coeff = float(info['chirp_t'][0]) / float( np.abs(info['freq'][0] - info['chirp_f'][0])) print_debug("Coefficient is: " + str(coeff)) print_debug("Max low freq found: " + str(freq[Pxx.argmax()])) delay = freq[Pxx.argmax()] * coeff delay = int(delay * 2e8) / 2.e8 print_debug("Delay found %d ns" % int(delay * 1e9)) return delay
def puv_quick(pressure, u, v, depth, height_of_pressure, height_of_velocity, sampling_frequency, fft_length=512, rho=1025., first_frequency_cutoff=1 / 50, infra_gravity_cutoff=0.05, last_frequency_cutoff=1 / 5, fft_window_type='hanning', show_diagnostic_plot=False, check_variances=False, variance_error=0.0, overlap_length='default'): """ Determine wave heights from pressure, east_velocity, v velocity data Parameters ---------- pressure : array_like pressure (dbar) u : array_like u velocities (m/s) v : array_like v velocities (m/s) depth : float Average water depth (m, positive number) height_of_pressure : float Height of pressure sensor off bottom (m, positive number) height_of_velocity : float Height of velocity sensor off bottom (m, positive number) sampling_frequency : float Hz fft_length : int Length of data to window and process rho : float Water density (kg/m^3) fft_window_type : str Data fft_window for spectral calculation, per scipy signal package first_frequency_cutoff : float Low-frequency cutoff for wave motions infra_gravity_cutoff : float Infra-gravity wave frequency cutoff last_frequency_cutoff : float High-frequency cutoff for wave motions show_diagnostic_plot : bool print plots and other checks check_variances : bool test to see if variance is preserved in calculations variance_error : float tolerance for variance preservation, in percent overlap_length : str "default" or int length, default will result in fft_length / 2 Returns ------- dict:: 'Hrmsp': Hrms (=Hmo) from pressure 'Hrmsu': Hrms from u,v 'ubr': Representative orbital velocity amplitude in freq. band ( first_frequency_cutoff <= f <= last_frequency_cutoff ) (m/s) 'omegar': Representative orbital velocity (radian frequency) 'Tr': Representative orbital velocity period (s) 'Tpp': Peak period from pressure (s) 'Tpu': Peak period from velocity (s) 'phir': Representative orbital velocity direction (angles from x-axis, positive ccw) 'azr': Representative orb. velocity direction (deg; geographic azimuth; ambiguous =/- 180 degrees) 'ublo': ubr in freq. band (f <= first_frequency_cutoff) (m/s) 'ubhi': ubr in freq. band (f >= last_frequency_cutoff) (m/s) 'ubig': ubr in infra-gravity freq. band (first_frequency_cutoff f <= 1/20) (m/s) 'figure': figure handle 'axis': axis handle 'variance_test_passed': True if passing References ---------- Madsen (1994) Coastal Engineering 1994, Proc., 24th, Intl. Conf., Coastal Eng. Res. Council / ASCE. pp.384-398. (esp. p. 395) Thorton & Guza Acknowledgements ---------------- converted to python and updated by Marinna Martini from Chris Sherwood's puvq.m. puvq.m also had contributions from Laura Landerman and Patrick Dickudt """ gravity = 9.81 # m/s^2 if fft_window_type is 'hanning': fft_window_type = 'hann' # this is just the way scipy signal likes it if overlap_length is "default": overlap_length = int(np.floor(fft_length / 2)) pressure = spsig.detrend(pressure) u = spsig.detrend(u) v = spsig.detrend(v) # compute wave height from velocities # Determine velocity spectra for u and v [frequencies, Gpp] = spsig.welch(rho * gravity * pressure, fs=sampling_frequency, window=fft_window_type, nperseg=fft_length, noverlap=overlap_length) df = frequencies[2] - frequencies[1] [_, Guu] = spsig.welch(u, fs=sampling_frequency, window=fft_window_type, nperseg=fft_length, noverlap=overlap_length) [_, Gvv] = spsig.welch(v, fs=sampling_frequency, window=fft_window_type, nperseg=fft_length, noverlap=overlap_length) # determine wave number omega = np.array([2 * np.pi * x for x in frequencies ]) # omega must be numpy array for qkfs # catch numpy errors np.seterr(divide='ignore', invalid='ignore') k = qkfs(omega, float(depth)) # make sure it is float, or qkfs will bomb np.seterr(divide=None, invalid=None) # compute linear wave transfer function kh = k * depth kzp = k * height_of_pressure kzuv = k * height_of_velocity nf = len(omega) Hp = np.ones(nf) Huv = np.ones(nf) # change wavenumber at 0 Hz to 1 to avoid divide by zero i = np.array( range(nf) ) # this is an index, thus needs to start at first element, in this case 0 # for some reason in the MATLAB version CRS tests omega for nans instead of k. # Here we test k also because that's where the nans show up if np.isnan(omega[0]) or np.isnan( k[0]) or (omega[0] <= 0): # 0 Hz is the first element i = i[1:] Hp[0] = 1 Huv[0] = 1 Hp[i] = rho * gravity * (np.cosh(kzp[i]) / np.cosh(kh[i])) Huv[i] = omega[i] * (np.cosh(kzuv[i]) / np.sinh(kh[i])) # combine horizontal velocity spectra Guv = Guu + Gvv # create cut off frequency, so noise is not magnified # at least in first testing, subtracting 1 here got closer to the intended freq. cutoff value ff = np.argmax(frequencies > first_frequency_cutoff) - 1 lf = np.argmax(frequencies > last_frequency_cutoff) # Determine wave height for velocity spectra Snp = Gpp[ff:lf] / (Hp[ff:lf]**2) Snu = Guv[ff:lf] / (Huv[ff:lf]**2) fclip = frequencies[ff:lf] # Determine rms wave height (multiply by another sqrt(2) for Hs) # Thornton and Guza say Hrms = sqrt(8 mo) Hrmsu = 2 * np.sqrt(2 * np.sum(Snu * df)) Hrmsp = 2 * np.sqrt(2 * np.sum(Snp * df)) # These are representative orbital velocities for w-c calculations, # according to Madsen (1994) Coastal Engineering 1994, Proc., 24th # Intl. Conf., Coastal Eng. Res. Council / ASCE. pp.384-398. # (esp. p. 395) ubr = np.sqrt(2 * np.sum(Guv[ff:lf] * df)) ubr_check = np.sqrt(2 * np.var(u) + 2 * np.var(v)) omegar = np.sum(omega[ff:lf] * Guv[ff:lf] * df) / np.sum(Guv[ff:lf] * df) Tr = 2 * np.pi / omegar if len(np.where(np.isnan(Snp))) > 0 | len(np.where(Snp == 0)) > 0: Tpp = np.nan else: jpeak = np.argmax(Snp) # index location of the maximum value Tpp = 1 / fclip[jpeak] if len(np.where(np.isnan(Snu))) > 0 | len(np.where(Snu == 0)) > 0: Tpu = np.nan else: jpeak = np.argmax(Snu) Tpu = 1 / fclip[jpeak] # phi is angle wrt to x axis; this assumes Guu is in x direction # phir = atan2( sum(Guu(ff:lf)*df), sum(Gvv(ff:lf)*df) ); # this is the line changed on 6/24/03 - I still think it is wrong (CRS) # phir = atan2( sum(Gvv(ff:lf)*df), sum(Guu(ff:lf)*df) ); # This is Jessie's replacement for direction # 12/08 Jessie notes that Madsen uses velocity and suggests # Suu = sqrt(Guu); # Svv = sqrt(Gvv); # Suv = sqrt(Guv); # but I (CRS) think eqn. 24 is based on u^2, so following is ok: rr = np.corrcoef(u, v) ortest = np.sign(rr[1][0]) phir = np.arctan2(ortest * np.sum(Gvv[ff:lf] * df), np.sum(Guu[ff:lf] * df)) # convert to degrees; convert to geographic azimuth (0-360, 0=north) azr = 90 - (180 / np.pi) * phir # Freq. bands for variance contributions ig = np.max(np.where(frequencies <= infra_gravity_cutoff)) # low freq, infragravity, high-freq if 1 < ff: ublo = np.sqrt(2 * np.sum(Guv[1:ff] * df)) else: ublo = 0 if ig > ff: ubig = np.sqrt(2 * np.sum(Guv[ff:ig] * df)) else: ubig = 0 if lf < fft_length: ubhi = np.sqrt(2 * np.sum(Guv[lf:] * df)) else: ubhi = 0 ws = { 'Hrmsp': Hrmsp, 'Hrmsu': Hrmsu, 'ubr': ubr, 'ubr_check': ubr_check, 'omegar': omegar, 'Tr': Tr, 'Tpp': Tpp, 'Tpu': Tpu, 'phir': phir, 'azr': azr, 'ublo': ublo, 'ubhi': ubhi, 'ubig': ubig, } if check_variances: variance_preserved = test_variances(u, v, pressure, Gpp, Guu, Gvv, df, allowable_error=variance_error) ws['variance_test_passed'] = variance_preserved if show_diagnostic_plot: fig, ax = plot_spectra(Guu, Gvv, Guv, Gpp, frequencies, first_frequency_cutoff, ff, last_frequency_cutoff, lf, infra_gravity_cutoff, ig) ws['figure'] = fig ws['axis'] = ax return ws
fig, axes = plt.subplots(2, 2, figsize=(8, 4)) # Plot the timeseries ax = axes[0][0] ax.plot(times, 1e9 * signal1, lw=0.5) ax.set(xlabel='Time (s)', xlim=times[[0, -1]], ylabel='Amplitude (Am)', title='Signal 1') ax = axes[0][1] ax.plot(times, 1e9 * signal2, lw=0.5) ax.set(xlabel='Time (s)', xlim=times[[0, -1]], title='Signal 2') # Power spectrum of the first timeseries f, p = welch(signal1, fs=sfreq, nperseg=128, nfft=256) ax = axes[1][0] # Only plot the first 100 frequencies ax.plot(f[:100], 20 * np.log10(p[:100]), lw=1.) ax.set(xlabel='Frequency (Hz)', xlim=f[[0, 99]], ylabel='Power (dB)', title='Power spectrum of signal 1') # Compute the coherence between the two timeseries f, coh = coherence(signal1, signal2, fs=sfreq, nperseg=100, noverlap=64) ax = axes[1][1] ax.plot(f[:50], coh[:50], lw=1.) ax.set(xlabel='Frequency (Hz)', xlim=f[[0, 49]], ylabel='Coherence',
def timeseriesPUV(p, u, v, t, waterDepth, gaugeDepth): """The goal with this function is to create time series anaylysis work flow runs welch method fft with 512 record segments, with 1/4 overlab and 5 freq bin band averaging corrects pressure spectra to surface spectra using pressure response function below parameters and makes them into magical wave data Args: p: pressure in cm u: u velocities v: v velocities t: time stamp waterDepth: positive in meters gaugeDepth: negative in meters frequency: spectra a1: interped to np.arange(0.04, 0.5, 0.0075) b1: interped to np.arange(0.04, 0.5, 0.0075) a2: interped to np.arange(0.04, 0.5, 0.0075) b2: interped to np.arange(0.04, 0.5, 0.0075) Returns: param frequency spectra """ from scipy.signal import welch, csd Fsamp = 1 / np.median(np.diff(t)) # sample frequency (not period) nseg = 512 # 512 overlap = nseg / 4 bave = 5 # number of spectral bands to average (taken from kent) # Calculate spectra in each componant # x is north, y is east in kents code (used for a's b's) pDemeaned = (p - np.mean(p)) / 100 # demean pressure and convert to meters [f1, Sp] = welch(x=pDemeaned, window='hanning', fs=Fsamp, nperseg=nseg, noverlap=overlap, nfft=None, return_onesided=True, detrend='linear') [f1, Su] = welch(x=u, window='hanning', fs=Fsamp, nperseg=nseg, noverlap=overlap, nfft=None, return_onesided=True, detrend='linear') [f1, Sv] = welch(x=v, window='hanning', fs=Fsamp, nperseg=nseg, noverlap=overlap, nfft=None, return_onesided=True, detrend='linear') # create cross spectral power across the 3 [f1, CrossPU] = csd(y=pDemeaned, x=u, fs=Fsamp, nperseg=nseg, noverlap=overlap, return_onesided=True, window='hann') [f1, CrossPV] = csd(y=pDemeaned, x=v, fs=Fsamp, nperseg=nseg, noverlap=overlap, return_onesided=True, window='hann') [f1, CrossUV] = csd(y=v, x=u, fs=Fsamp, nperseg=nseg, noverlap=overlap, return_onesided=True, window='hann') ## now Do some frequency band Averaging # first remove first index of array "remove DC compoonents" f1 = f1[1:] Sp = np.real(Sp[1:]) Su = np.real(Su[1:]) Sv = np.real(Sv[1:]) CrossPU = CrossPU[1:] CrossPV = CrossPV[1:] CrossUV = CrossUV[1:] # correcting Pressure spectra to surface spectra L, _, _ = dispersion(waterDepth, T=1 / f1) prF = prFunc(L, waterDepth, gaugeDepth) # Sp = Sp / prF ** 2 # getting surface corrected energy spectrum # Beginning to Setup For Band Averaging dk = int(np.floor(bave / 2)) ki = 0 freq, SpAve, SuAve, SvAve, CrossPUave, CrossPVave, CrossUVave = [], [], [], [], [], [], [] for kk in range(dk + 1, len(Sp) - dk, bave): avgIdxs = np.linspace(kk - dk, kk + dk, num=int((kk + dk) - (kk - dk) + 1), endpoint=True, dtype=int) freq = np.append(freq, f1[int(kk)]) # taking the first frequency for the bin label # bin averaging frequency spectra across bave frequency bins SpAve.append(np.sum(Sp[avgIdxs]) / bave) SuAve.append(np.sum(Su[avgIdxs]) / bave) SvAve.append(np.sum(Sv[avgIdxs]) / bave) # bin averaging cross correlations CrossPUave.append(np.sum(CrossPU[avgIdxs]) / bave) # Press - FRF X CrossPVave.append(np.sum(CrossPV[avgIdxs]) / bave) # Press - FRF Y CrossUVave.append(np.sum(CrossUV[avgIdxs]) / bave) # FRF X - FRF Y # convert back to Numpy array freq = np.array(freq) SpAve = np.array(SpAve) SuAve = np.array(SuAve) SvAve = np.array(SvAve) CrossPUave = np.array(CrossPUave) CrossPVave = np.array(CrossPVave) CrossUVave = np.array(CrossUVave) # Extracting as and bs a1 = np.imag(CrossPUave) / np.sqrt(SpAve * (SuAve + SvAve)) b1 = -np.imag(CrossPVave) / np.sqrt(SpAve * (SuAve + SvAve)) a2 = (SuAve - SvAve) / (SvAve + SuAve) b2 = -2 * np.real(CrossUVave) / (SvAve + SuAve) wfreq = np.arange(0.04, 0.5, 0.0075) # frequencies to interp to wDeg = np.arange(0, 360, 5) # interpolating to reasonable frequency banding import scipy.interpolate as interp f = interp.interp1d(freq, a1, kind='linear') a1interp = f(wfreq) f = interp.interp1d(freq, a2, kind='linear') a2interp = f(wfreq) f = interp.interp1d(freq, b1, kind='linear') b1interp = f(wfreq) f = interp.interp1d(freq, b2, kind='linear') b2interp = f(wfreq) f = interp.interp1d(freq, SpAve, kind='linear') fspec = f(wfreq) # mlmSpec = mlm(freqs=freq, dirs=np.arange(0,360,5), c11=SpAve, c22=SuAve, c33=SvAve, c23=np.real(CrossUVave), q12=np.imag(CrossPUave), q13=np.imag(CrossPVave)) return fspec, a1interp, b1interp, a2interp, b2interp
vvec = numpy.array(v_vec) tvec = numpy.array(t_vec) numpy.save( 'Output/' + cellname + modelname + '_NumberOfSyns_' + str(synnum) + '_Frequency_' + str(rate) + '_Voltage.npy', vvec) numpy.save( 'Output/' + cellname + modelname + '_NumberOfSyns_' + str(synnum) + '_Frequency_' + str(rate) + '_Time.npy', tvec) apctimes = numpy.array(h.apctimes) spikebinvec = numpy.zeros(len(tvec)) for x in apctimes: spikebinvec[numpy.where(tvec == x)] = 1 dt = h.dt f, Pxx_den = signal.welch(spikebinvec, 1 / (dt / 1000), nperseg=25000) if synnum == 0: Pxx_den0 = Pxx_den f0 = f Areas[rcount][scount] = numpy.trapz(Pxx_den[(f > 4) & (f < 12)], x=f[(f > 4) & (f < 12)]) Power[rcount][scount] = numpy.max(Pxx_den[(f > rate - 1) & (f < rate + 1)]) # Power[rcount][scount] = numpy.max(Pxx_den[f==rate]) if synnum != 0: Pxx_den_Subtracted = Pxx_den - Pxx_den0 AreasSubtracted[rcount][scount] = numpy.trapz( Pxx_den[(f > 4) & (f < 12)], x=f[(f > 4) & (f < 12)]) - numpy.trapz( Pxx_den0[(f0 > 4) & (f0 < 12)], x=f0[(f0 > 4) & (f0 < 12)]) PowerSubtracted[rcount][scount] = numpy.max(
def test_welch_psd_behavior(self): # generate data by adding white noise and a sinusoid data_length = 5000 sampling_period = 0.001 signal_freq = 100.0 noise = np.random.normal(size=data_length) signal = [ np.sin(2 * np.pi * signal_freq * t) for t in np.arange(0, data_length * sampling_period, sampling_period) ] data = n.AnalogSignal(np.array(signal + noise), sampling_period=sampling_period * pq.s, units='mV') # consistency between different ways of specifying segment length freqs1, psd1 = elephant.spectral.welch_psd(data, len_segment=data_length // 5, overlap=0) freqs2, psd2 = elephant.spectral.welch_psd(data, n_segments=5, overlap=0) self.assertTrue((psd1 == psd2).all() and (freqs1 == freqs2).all()) # frequency resolution and consistency with data freq_res = 1.0 * pq.Hz freqs, psd = elephant.spectral.welch_psd(data, frequency_resolution=freq_res) self.assertAlmostEqual(freq_res, freqs[1] - freqs[0]) self.assertEqual(freqs[psd.argmax()], signal_freq) freqs_np, psd_np = elephant.spectral.welch_psd( data.magnitude.flatten(), fs=1 / sampling_period, frequency_resolution=freq_res) self.assertTrue((freqs == freqs_np).all() and (psd == psd_np).all()) # check of scipy.signal.welch() parameters params = { 'window': 'hamming', 'nfft': 1024, 'detrend': 'linear', 'return_onesided': False, 'scaling': 'spectrum' } for key, val in params.items(): freqs, psd = elephant.spectral.welch_psd(data, len_segment=1000, overlap=0, **{key: val}) freqs_spsig, psd_spsig = spsig.welch(np.rollaxis( data, 0, len(data.shape)), fs=1 / sampling_period, nperseg=1000, noverlap=0, **{key: val}) self.assertTrue((freqs == freqs_spsig).all() and (psd == psd_spsig).all()) # - generate multidimensional data for check of parameter `axis` num_channel = 4 data_length = 5000 data_multidim = np.random.normal(size=(num_channel, data_length)) freqs, psd = elephant.spectral.welch_psd(data_multidim) freqs_T, psd_T = elephant.spectral.welch_psd(data_multidim.T, axis=0) self.assertTrue(np.all(freqs == freqs_T)) self.assertTrue(np.all(psd == psd_T.T))
for j, ch in enumerate(ch_plot): leg = [] fb_counter = 0 for jj, key in enumerate(keys): x = raw[key] style = '--' if fb_counter > 0 else '' w = 2 if 'FB' in key: fb_counter += 1 style = '' w = fb_counter y = x[:, channels.index(ch)] if ch != 'ICA' else np.dot( x, spatial) f, Pxx = welch( y, fs, nperseg=2048, ) axes[j].plot(f, Pxx, style, c=cm(key), linewidth=w, alpha=0.8 if 'FB' in key else 1) x_plot = np.abs(hilbert(fft_filter(y, fs, band=mu_band))) threshold = coef * x_median[channels.index( ch)] if ch != 'ICA' else coef * x_f_median leg.append('{}'.format(key)) axes[j].set_xlim(7, 15) axes[j].axvline(x=mu_band[0], color='k', alpha=0.5)
baseline_closed = baseline.loc[12001:24001, :] nodis = nodis_epoch.to_data_frame().reset_index(drop=True) buzz = buzz_epoch.to_data_frame().reset_index(drop=True) neutral = neutral_epoch.to_data_frame().reset_index(drop=True) for electrode in parietal: #Choose electrodes to investigate data_baseline_open = baseline_open[electrode] data_baseline_closed = baseline_closed[electrode] data_nodis = nodis[electrode] data_buzz = buzz[electrode] data_neutral = neutral[electrode] #Compute Welch transform freqs_baseline_open, psd_baseline_open = signal.welch( data_baseline_open, Fs, nperseg=sliding_window, noverlap=n_overlap) freqs_baseline_closed, psd_baseline_closed = signal.welch( data_baseline_closed, Fs, nperseg=sliding_window, noverlap=n_overlap) freqs_nodis, psd_nodis = signal.welch(data_nodis, Fs, nperseg=sliding_window, noverlap=n_overlap) freqs_buzz, psd_buzz = signal.welch(data_buzz, Fs, nperseg=sliding_window, noverlap=n_overlap) freqs_neutral, psd_neutral = signal.welch(data_neutral, Fs,
def test_empty_input_other_axis(self): for shape in [(3, 0), (0, 5, 2)]: f, p = welch(np.empty(shape), axis=1) assert_array_equal(f.shape, shape) assert_array_equal(p.shape, shape)
freq_aux = np.array([]) psd_aux = np.array([]) windows = np.array([49, 35, 10, 2, 0.5 ]) / dt # the size of the windows in days/dt lims = [0.08, 1, 3, 10, 20] # limit frequency for windows freq, psd = sg.periodogram(temp, fs=1. / dt) ind, = np.where(freq < lims[0]) freq_aux = np.concatenate((freq_aux, freq[ind])) psd_aux = np.concatenate((psd_aux, psd[ind])) for i in range(0, len(lims) - 1): freq, psd = sg.welch(temp, fs=1. / dt, window='hanning', nperseg=windows[i], noverlap=0.15) ind, = np.where(((freq >= lims[i]) & (freq < lims[i + 1]))) freq_aux = np.concatenate((freq_aux, freq[ind])) psd_aux = np.concatenate((psd_aux, psd[ind])) print(1) freq, psd = sg.welch(temp, fs=1. / dt, window='hanning', nperseg=windows[-1], noverlap=0.15) ind, = np.where(freq >= lims[-1]) freq_aux = np.concatenate((freq_aux, freq[ind])) psd_aux = np.concatenate((psd_aux, psd[ind]))
chirpLen_s = chirpLen_s + baseline_s + end_s times_s = np.arange(0, chirpLen_s, 1.0 / sr) numSamples = times_s[-1] * sr bin_window = .5 #s bin_window_step = bin_window * sr bin_step = .1 #s bin_step_step = bin_step * sr Pxx_dens = list() freqlimit = np.max([start_Hz, stop_Hz]) * 2 t_fft = np.arange(bin_window / 2, chirpLen_s - bin_window / 2, bin_step) for start_idx, end_idx in zip( np.arange(0, numSamples - bin_window_step, bin_step_step), np.arange(bin_window_step, numSamples, bin_step_step)): f, Pxx_den = signal.welch(chirp[int(start_idx):int(end_idx)], sr, nperseg=bin_window_step) Pxx_dens.append(Pxx_den[:np.argmax(f > freqlimit)]) #% f_plot = f[:np.argmax(f > freqlimit)] fig = plt.figure(figsize=[5, 5]) ax_chirp = fig.add_subplot(211) ax_fft = fig.add_subplot(212) ax_chirp.plot(times_s, chirp) fftfig = ax_fft.imshow(np.stack(Pxx_dens).T[::-1, :], extent=[0, 3, 0, 1]) yticks = ax_fft.get_yticks() yticks_f = f_plot[np.asarray(yticks * (len(f_plot) - 1), int)] ax_fft.set_yticklabels(yticks_f) xticks = ax_fft.get_xticks() / 3
def plotNodes(i): global data start_time = time.time() inlet = StreamInlet(streams[0]) # get a new sample sample = inlet.pull_sample() newdata = np.asarray(sample[0][:n]) # print(newdata) # delete first row of data data = np.delete(data, 0, 0) # add newdata as a row at the end of data. columns=electrodes rows=timestep data = np.vstack([data, newdata]) data = np.transpose(data) # compute power spectrum of data f, ps = sps.welch(data, fs=26) print("ps", ps) # get the amplitudes associated with the various bands of frequencies extractAmplitudeDelta = getAmplitudesByFrequencyBand(ps, 0) extractAmplitudeTheta = getAmplitudesByFrequencyBand(ps, 1) extractAmplitudeAlpha = getAmplitudesByFrequencyBand(ps, 2) tempDelta = np.asarray(extractAmplitudeDelta) tempTheta = np.asarray(extractAmplitudeTheta) tempAlpha = np.asarray(extractAmplitudeAlpha) # temp holds mean of each row in extractAmplitude tempDelta = np.mean(tempDelta, axis=1) tempTheta = np.mean(tempTheta, axis=1) tempAlpha = np.mean(tempAlpha, axis=1) # square all values to make them 0 <= x <= 1 tempDelta = np.square(tempDelta) tempTheta = np.square(tempTheta) tempAlpha = np.square(tempAlpha) # calculate zscores for the array zscoreArrayDelta = stats.zscore(tempDelta) zscoreArrayTheta = stats.zscore(tempTheta) zscoreArrayAlpha = stats.zscore(tempAlpha) # do relative here # next line creates positive and negative zscores, so if the value was between 0 to 0.5, it is # scaled to between -1 and 0, and if the value was between 0.5 and 1, it is scaled to between # 0 and 1 zscoreArrayDelta = ( (zscoreArrayDelta / np.amax(zscoreArrayDelta)) / 2) + 0.5 zscoreArrayTheta = ( (zscoreArrayTheta / np.amax(zscoreArrayTheta)) / 2) + 0.5 zscoreArrayAlpha = ( (zscoreArrayAlpha / np.amax(zscoreArrayAlpha)) / 2) + 0.5 # define vectors for plot colors and opacity # altColors = freqs / 33 colorsDelta = cmap(zscoreArrayDelta) colorsTheta = cmap(zscoreArrayTheta) colorsAlpha = cmap(zscoreArrayAlpha) # colors.astype(float) # colors[:, -1] = maxes / maxes.max() # print(altColors) # print(colors) ax1.set_xlim(-6, 6) ax1.set_ylim(-6, 6) ax2.set_xlim(-6, 6) ax2.set_ylim(-6, 6) ax3.set_xlim(-6, 6) ax3.set_ylim(-6, 6) # ax1.scatter(x, y, s = 100, c = altColors, cmap = plt.cm.jet_r) ax1.scatter(x, y, s=100, c=colorsDelta) ax2.scatter(x, y, s=100, c=colorsTheta) ax3.scatter(x, y, s=100, c=colorsAlpha) elapsed_time = time.time() - start_time
def test_no_detrending(self): x = np.arange(10, dtype=np.float64) + 0.04 f1, p1 = welch(x, nperseg=10, detrend=False) f2, p2 = welch(x, nperseg=10, detrend=lambda x: x) assert_allclose(f1, f2, atol=1e-15) assert_allclose(p1, p2, atol=1e-15)