def compute(self, waveforms, window_length, increment, samplerate=16000, min_freq=0, max_freq=None, nstd=6, offset=50): signal, stimulus = waveforms self.time, self.frequencies, spec = gaussian_stft(signal, samplerate, window_length, increment, min_freq=min_freq, max_freq=max_freq, nstd=nstd)[:3] stim_spec = gaussian_stft(stimulus, samplerate, window_length, increment, min_freq=min_freq, max_freq=max_freq, nstd=nstd)[2] ratio_mask = np.abs(spec) ** self.alpha / np.abs(stim_spec) ** self.alpha ratio_mask = np.maximum(0, np.minimum(1, ratio_mask)).T stim_spec = log_spectrogram(np.abs(stim_spec), offset=offset).T self.mean = np.mean(stim_spec, axis=0) stim_spec -= self.mean return stim_spec, ratio_mask
def cross_spectral_density(s1, s2, sample_rate, window_length, increment, min_freq=0, max_freq=np.inf): """ Computes the cross-spectral density between signals s1 and s2 by computing the product of their power spectra. First the Gaussian-windowed spectrograms of s1 and s2 are computed, then the product of the power spectra at each time point is computed, then the products are averaged across time to produce an estimate of the cross spectral density. :param s1: The first signal. :param s2: The second signal. :param sample_rate: The sample rates of the signals. :param window_length: The length of the window used to compute the STFT (units=seconds) :param increment: The spacing between the points of the STFT (units=seconds) :param min_freq: The minimum frequency to analyze (units=Hz, default=0) :param max_freq: The maximum frequency to analysize (units=Hz, default=nyquist frequency) :return: freq,csd: The frequency bands evaluated, and the cross-spectral density. """ # compute the complex-spectrograms of the signals t1, freq1, tf1, rms1 = gaussian_stft(s1, sample_rate, window_length=window_length, increment=increment, min_freq=min_freq, max_freq=max_freq) t2, freq2, tf2, rms2 = gaussian_stft(s2, sample_rate, window_length=window_length, increment=increment, min_freq=min_freq, max_freq=max_freq) # multiply the complex spectrograms csd = tf1*tf2 # take the power spectrum csd = np.abs(csd) # average across time csd = csd.mean(axis=1) return freq1,csd
def cross_spectral_density(s1, s2, sample_rate, window_length, increment, min_freq=0, max_freq=np.inf): """ Computes the cross-spectral density between signals s1 and s2 by computing the product of their power spectra. First the Gaussian-windowed spectrograms of s1 and s2 are computed, then the product of the power spectra at each time point is computed, then the products are averaged across time to produce an estimate of the cross spectral density. :param s1: The first signal. :param s2: The second signal. :param sample_rate: The sample rates of the signals. :param window_length: The length of the window used to compute the STFT (units=seconds) :param increment: The spacing between the points of the STFT (units=seconds) :param min_freq: The minimum frequency to analyze (units=Hz, default=0) :param max_freq: The maximum frequency to analysize (units=Hz, default=nyquist frequency) :return: freq,csd: The frequency bands evaluated, and the cross-spectral density. """ # compute the complex-spectrograms of the signals t1, freq1, tf1, rms1 = gaussian_stft(s1, sample_rate, window_length=window_length, increment=increment, min_freq=min_freq, max_freq=max_freq) t2, freq2, tf2, rms2 = gaussian_stft(s2, sample_rate, window_length=window_length, increment=increment, min_freq=min_freq, max_freq=max_freq) # multiply the complex spectrograms csd = tf1 * tf2 # take the power spectrum csd = np.abs(csd) # average across time csd = csd.mean(axis=1) return freq1, csd
def spectrogram(s, sample_rate, spec_sample_rate, freq_spacing, min_freq=0, max_freq=None, nstd=6, log=True, noise_level_db=80, rectify=True, cmplx = True): """ Given a sound pressure waveform, compute the log spectrogram. See documentation on gaussian_stft for arguments and return values. log: whether or not to take the log of th power and convert to decibels, defaults to True noise_level_db: the threshold noise level in decibels, anything below this is set to zero. unused of log=False """ increment = 1.0 / spec_sample_rate window_length = nstd / (2.0*np.pi*freq_spacing) t,freq,timefreq,rms = gaussian_stft(s, sample_rate, window_length, increment, nstd=nstd, min_freq=min_freq, max_freq=max_freq) if cmplx: return t, freq, timefreq, rms if log: #create log spectrogram (power in decibels) abstimefreq = np.abs(timefreq) maxabs = np.max(abstimefreq) spec = 20.0*np.log10(abstimefreq/maxabs) + noise_level_db if rectify: #rectify spectrogram spec[spec < 0.0] = 0.0 else: spec = np.abs(timefreq) rms = spec.std(axis=0, ddof=1) return t,freq,spec,rms
def test_delta(self): dur = 30. sample_rate = 1e3 nt = int(dur * sample_rate) t = np.arange(nt) / sample_rate freqs = np.linspace(0.5, 1.5, nt) # freqs = np.ones_like(t)*2. s = np.sin(2 * np.pi * freqs * t) center_freqs = np.arange(0.5, 4.5, 0.5) psi = lambda _t, _f, _bw: (np.pi * _bw**2)**(-0.5) * np.exp( 2 * np.pi * complex(0, 1) * _f * _t) * np.exp(-_t**2 / _bw**2) """ scalogram = np.zeros([len(center_freqs), nt]) bandwidth = 1. nstd = 6 nwt = int(bandwidth*nstd*sample_rate) wt = np.arange(nwt) / sample_rate for k,f in enumerate(center_freqs): w = psi(wt, f, bandwidth) scalogram[k, :] = convolve1d(s, w) """ win_len = 2. spec_t, spec_freq, spec, spec_rms = gaussian_stft( s, sample_rate, win_len, 100e-3) fi = (spec_freq < 10) & (spec_freq > 0) plt.figure() gs = plt.GridSpec(100, 1) ax = plt.subplot(gs[:30, 0]) plt.plot(t, s, 'k-', linewidth=4.0, alpha=0.7) wa = WaveletAnalysis(s, dt=1. / sample_rate, frequency=True) ax = plt.subplot(gs[35:, 0]) power = wa.wavelet_power scales = wa.scales t = wa.time T, S = np.meshgrid(t, scales) # ax.contourf(T, S, power, 100) # ax.set_yscale('log') # plt.imshow(np.abs(scalogram)**2, interpolation='nearest', aspect='auto', cmap=plt.cm.afmhot_r, origin='lower', # extent=[t.min(), t.max(), min(center_freqs), max(center_freqs)]) plot_spectrogram(spec_t, spec_freq[fi], np.abs(spec[fi, :])**2, ax=ax, colorbar=False, colormap=plt.cm.afmhot_r) plt.plot(t, freqs, 'k-', alpha=0.7, linewidth=4.0) plt.axis('tight') plt.show()
def compute(self, waveform, window_length, increment, samplerate=16000, min_freq=0, max_freq=None, nstd=6, offset=50): self.time, self.frequencies, spec = gaussian_stft(waveform, samplerate, window_length, increment, min_freq=min_freq, max_freq=max_freq, nstd=nstd)[:3] return log_spectrogram(np.abs(spec), offset=offset).T
def get_syllable_props(agg, stim_id, syllable_order, data_dir): wave_pad = 20e-3 i = (agg.df.stim_id == stim_id) & (agg.df.syllable_order == syllable_order) bird = agg.df[i].bird.values[0] start_time = agg.df[i].start_time.values[0] - wave_pad end_time = agg.df[i].end_time.values[0] + wave_pad xindex = agg.df[i].xindex.values[0] aprops = {aprop: agg.Xraw[xindex, k] for k, aprop in enumerate(USED_ACOUSTIC_PROPS)} aprops['start_time'] = start_time aprops['end_time'] = end_time duration = end_time - start_time sfile = os.path.join(data_dir, bird, 'stims.h5') # get the raw sound pressure waveform sound_manager = SoundManager(HDF5Store, sfile, read_only=True, db_args={'read_only': True}) wave = sound_manager.reconstruct(stim_id) wave_sr = wave.samplerate wave = np.array(wave).squeeze() wave /= np.abs(wave).max() wave *= aprops['maxAmp'] wave_t = np.arange(len(wave)) / wave_sr wave_si = np.min(np.where(wave_t >= start_time)[0]) wave_ei = wave_si + int(duration * wave_sr) amp_env = temporal_envelope(wave, wave_sr, cutoff_freq=200.0) amp_env /= amp_env.max() amp_env *= wave.max() # compute the spectrogram spec_sr = 1000. spec_t, spec_freq, spec, spec_rms = gaussian_stft(wave, float(wave_sr), 0.007, 1. / spec_sr, min_freq=300., max_freq=8000.) spec = np.abs(spec) ** 2 log_transform(spec, dbnoise=70) spec_si = np.min(np.where(spec_t >= start_time)[0]) spec_ei = spec_si + int(duration * spec_sr) # compute power spectrum ps_freq, ps = power_spectrum(wave[wave_si:wave_ei], wave_sr, log=False, hanning=False) return {'wave_t':wave_t, 'wave':wave, 'wave_si':wave_si, 'wave_ei':wave_ei, 'ps_freq':ps_freq, 'ps':ps, 'amp_env':amp_env, 'spec_t':spec_t, 'spec_freq':spec_freq, 'spec':spec, 'spec_si':spec_si, 'spec_ei':spec_ei, 'spec_sample_rate':spec_sr, 'aprops':aprops }
import matplotlib.pyplot as plt from scipy.io.wavfile import read import numpy as np from lasp.timefreq import gaussian_stft from lasp.sound import plot_spectrogram import pdb fname = 'DCCalls16x16/fbird8call1.wav' wf = read(fname, 'r')[1] # Frames: 30870.00d, Rate: 44100.00 wl = 0.007 # 7ms ic = 0.001 # 1ms t, freq, timefreq, rms = gaussian_stft(wf, 44100, wl, ic) spec = np.abs(timefreq) spec = spec / spec.max() nz = spec > 0 spec[nz] = 20 * np.log10(spec[nz]) + 50 spec[spec < 0] = 0 plot_spectrogram(t, freq, spec) plt.show()
def coherence_jn(s1, s2, sample_rate, window_length, increment, min_freq=0, max_freq=None, return_coherency=False): """ Computes the coherence between two signals by averaging across time-frequency representations created using a Gaussian-windowed Short-time Fourier Transform. Uses jacknifing to estimate the variance of the coherence. :param s1: The first signal :param s2: The second signal :param sample_rate: The sample rates of the signals. :param window_length: The length of the window used to compute the STFT (units=seconds) :param increment: The spacing between the points of the STFT (units=seconds) :param min_freq: The minimum frequency to analyze (units=Hz, default=0) :param max_freq: The maximum frequency to analyze (units=Hz, default=nyquist frequency) :param return_coherency: Whether or not to return the time domain coherency (default=False) :return: freq,coherence,coherence_var,phase_coherence,phase_coherence_var,[coherency,coherency_t]: freq is an array of frequencies that the coherence was computed at. coherence is an array of length len(freq) that contains the coherence at each frequency. coherence_var is the variance of the coherence. phase_coherence is the average cosine phase difference at each frequency, and phase_coherence_var is the variance of that measure. coherency is only returned if return_coherency=True, it is the inverse fourier transform of the complex- valued coherency. """ t1, freq1, tf1, rms1 = gaussian_stft(s1, sample_rate, window_length=window_length, increment=increment, min_freq=min_freq, max_freq=max_freq) t2, freq2, tf2, rms2 = gaussian_stft(s2, sample_rate, window_length=window_length, increment=increment, min_freq=min_freq, max_freq=max_freq) cross_spec12 = tf1*np.conj(tf2) ps1 = np.abs(tf1)**2 ps2 = np.abs(tf2)**2 # compute the coherence using all the data csd = cross_spec12.sum(axis=1) denom = ps1.sum(axis=1)*ps2.sum(axis=1) c_amp = np.abs(csd) / np.sqrt(denom) cohe = c_amp**2 # compute the phase coherence using all the data c_phase = np.cos(np.angle(csd)) # make leave-one-out estimates of the complex coherence jn_estimates_amp = list() jn_estimates_phase = list() jn_estimates_cohe = list() njn = tf1.shape[1] for k in range(njn): i = np.ones([njn], dtype='bool') i[k] = False csd = cross_spec12[:, i].sum(axis=1) denom = ps1[:, i].sum(axis=1)*ps2[:, i].sum(axis=1) c_amp = np.abs(csd) / np.sqrt(denom) jn_estimates_amp.append(c_amp) jn_estimates_cohe.append(njn*cohe - (njn-1)*(c_amp**2)) c_phase = np.cos(np.angle(csd)) jn_estimates_phase.append(c_phase) jn_estimates_amp = np.array(jn_estimates_amp) jn_estimates_cohe = np.array(jn_estimates_cohe) jn_estimates_phase = np.array(jn_estimates_phase) # estimate the variance of the coherence jn_mean_amp = jn_estimates_amp.mean(axis=0) jn_diff_amp = (jn_estimates_amp - jn_mean_amp)**2 c_var_amp = ((njn-1) / float(njn)) * jn_diff_amp.sum(axis=0) cohe_unbiased = jn_estimates_cohe.mean(axis=0) cohe_se = jn_estimates_cohe.std(axis=0)/np.sqrt(njn) # estimate the variance of the phase coherence jn_mean_phase = jn_estimates_phase.mean(axis=0) jn_diff_phase = (jn_estimates_phase - jn_mean_phase)**2 c_phase_var = ((njn-1) / float(njn)) * jn_diff_phase.sum(axis=0) assert c_amp.max() <= 1.0, "c_amp.max()=%f" % c_amp.max() assert c_amp.min() >= 0.0, "c_amp.min()=%f" % c_amp.min() assert np.sum(np.isnan(c_amp)) == 0, "NaNs in c_amp!" if return_coherency: # compute the complex-valued coherency z = csd / denom # make the complex-valued coherency symmetric around zero sym_z = np.zeros([len(z)*2 - 1], dtype='complex') sym_z[len(z)-1:] = z sym_z[:len(z)-1] = (z[1:])[::-1] # do an fft shift so the inverse fourier transform works sym_z = fftshift(sym_z) if len(sym_z) % 2 == 1: # shift zero from end of shift_lags to beginning sym_z = np.roll(sym_z, 1) coherency = ifft(sym_z) coherency = fftshift(coherency.real) dt = 1. / sample_rate hc = (len(coherency) - 1) / 2 coherency_t = np.arange(-hc, hc+1, 1)*dt """ import matplotlib.pyplot as plt plt.figure() plt.plot(coherency_t, coherency, 'k-') plt.axis('tight') plt.show() """ return freq1,c_amp,c_var_amp,c_phase,c_phase_var,coherency,coherency_t, cohe_unbiased, cohe_se else: return freq1,c_amp,c_var_amp,c_phase,c_phase_var, cohe_unbiased, cohe_se
import matplotlib.pyplot as plt from scipy.io.wavfile import read import numpy as np from lasp.timefreq import gaussian_stft from lasp.sound import plot_spectrogram import pdb fname = 'DCCalls16x16/fbird8call1.wav' wf = read(fname,'r')[1] # Frames: 30870.00d, Rate: 44100.00 wl = 0.007 # 7ms ic = 0.001 # 1ms t,freq,timefreq,rms = gaussian_stft(wf, 44100, wl, ic) spec = np.abs(timefreq) spec = spec/spec.max() nz = spec > 0 spec[nz] = 20*np.log10(spec[nz]) + 50 spec[spec < 0] = 0 plot_spectrogram(t, freq, spec) plt.show()
def coherence_jn(s1, s2, sample_rate, window_length, increment, min_freq=0, max_freq=None, return_coherency=False): """ Computes the coherence between two signals by averaging across time-frequency representations created using a Gaussian-windowed Short-time Fourier Transform. Uses jacknifing to estimate the variance of the coherence. :param s1: The first signal :param s2: The second signal :param sample_rate: The sample rates of the signals. :param window_length: The length of the window used to compute the STFT (units=seconds) :param increment: The spacing between the points of the STFT (units=seconds) :param min_freq: The minimum frequency to analyze (units=Hz, default=0) :param max_freq: The maximum frequency to analyze (units=Hz, default=nyquist frequency) :param return_coherency: Whether or not to return the time domain coherency (default=False) :return: freq,coherence,coherence_var,phase_coherence,phase_coherence_var,[coherency,coherency_t]: freq is an array of frequencies that the coherence was computed at. coherence is an array of length len(freq) that contains the coherence at each frequency. coherence_var is the variance of the coherence. phase_coherence is the average cosine phase difference at each frequency, and phase_coherence_var is the variance of that measure. coherency is only returned if return_coherency=True, it is the inverse fourier transform of the complex- valued coherency. """ if s1.shape != s2.shape: raise AssertionError('s1 and s2 must have the same shape') if s1.ndim == 1: s1, s2 = [np.array(i, ndmin=2) for i in [s1, s2]] tf1, tf2 = list(), list() for i, (is1, is2) in enumerate(zip(s1, s2)): t1, freq1, itf1, rms1 = gaussian_stft(is1, sample_rate, window_length=window_length, increment=increment, min_freq=min_freq, max_freq=max_freq) t2, freq2, itf2, rms2 = gaussian_stft(is2, sample_rate, window_length=window_length, increment=increment, min_freq=min_freq, max_freq=max_freq) tf1.append(itf1) tf2.append(itf2) tf1, tf2 = [np.hstack(i) for i in [tf1, tf2]] cross_spec12 = tf1 * np.conj(tf2) ps1 = np.abs(tf1)**2 ps2 = np.abs(tf2)**2 # compute the coherence using all the data csd = cross_spec12.sum(axis=1) denom = ps1.sum(axis=1) * ps2.sum(axis=1) c_amp = np.abs(csd) / np.sqrt(denom) cohe = c_amp**2 # compute the phase coherence using all the data c_phase = np.cos(np.angle(csd)) # make leave-one-out estimates of the complex coherence jn_estimates_amp = list() jn_estimates_phase = list() jn_estimates_cohe = list() njn = tf1.shape[1] for k in range(njn): i = np.ones([njn], dtype='bool') i[k] = False csd = cross_spec12[:, i].sum(axis=1) denom = ps1[:, i].sum(axis=1) * ps2[:, i].sum(axis=1) c_amp = np.abs(csd) / np.sqrt(denom) jn_estimates_amp.append(c_amp) jn_estimates_cohe.append(njn * cohe - (njn - 1) * (c_amp**2)) c_phase = np.cos(np.angle(csd)) jn_estimates_phase.append(c_phase) jn_estimates_amp = np.array(jn_estimates_amp) jn_estimates_cohe = np.array(jn_estimates_cohe) jn_estimates_phase = np.array(jn_estimates_phase) # estimate the variance of the coherence jn_mean_amp = jn_estimates_amp.mean(axis=0) jn_diff_amp = (jn_estimates_amp - jn_mean_amp)**2 c_var_amp = ((njn - 1) / float(njn)) * jn_diff_amp.sum(axis=0) cohe_unbiased = jn_estimates_cohe.mean(axis=0) cohe_se = jn_estimates_cohe.std(axis=0) / np.sqrt(njn) # estimate the variance of the phase coherence jn_mean_phase = jn_estimates_phase.mean(axis=0) jn_diff_phase = (jn_estimates_phase - jn_mean_phase)**2 c_phase_var = ((njn - 1) / float(njn)) * jn_diff_phase.sum(axis=0) assert c_amp.max() <= 1.0, "c_amp.max()=%f" % c_amp.max() assert c_amp.min() >= 0.0, "c_amp.min()=%f" % c_amp.min() assert np.sum(np.isnan(c_amp)) == 0, "NaNs in c_amp!" if return_coherency: # compute the complex-valued coherency z = csd / denom # make the complex-valued coherency symmetric around zero sym_z = np.zeros([len(z) * 2 - 1], dtype='complex') sym_z[len(z) - 1:] = z sym_z[:len(z) - 1] = (z[1:])[::-1] # do an fft shift so the inverse fourier transform works sym_z = fftshift(sym_z) if len(sym_z) % 2 == 1: # shift zero from end of shift_lags to beginning sym_z = np.roll(sym_z, 1) coherency = ifft(sym_z) coherency = fftshift(coherency.real) dt = 1. / sample_rate hc = (len(coherency) - 1) / 2 coherency_t = np.arange(-hc, hc + 1, 1) * dt """ import matplotlib.pyplot as plt plt.figure() plt.plot(coherency_t, coherency, 'k-') plt.axis('tight') plt.show() """ return freq1, c_amp, c_var_amp, c_phase, c_phase_var, coherency, coherency_t, cohe_unbiased, cohe_se else: return freq1, c_amp, c_var_amp, c_phase, c_phase_var, cohe_unbiased, cohe_se