def batchreconstructcompact(self, img): nim = img.shape[0] r = np.mod(nim, 6) if r > 0: # pad with empty frames so total number of frames is divisible by 6 img = np.concatenate((img, np.zeros((6 - r, self.N, self.N), np.single))) nim = nim + 6 - r nim3 = nim // 3 imf = fft.rfft2(img) * self._prefilter[:, 0:self.N // 2 + 1] img2 = np.zeros([nim, 2 * self.N, 2 * self.N], dtype=np.single) for i in range(0, nim, 3): self._carray1[:, 0:self.N // 2, 0:self.N // 2 + 1] = imf[i:i + 3, 0:self.N // 2, 0:self.N // 2 + 1] self._carray1[:, 3 * self.N // 2:2 * self.N, 0:self.N // 2 + 1] = imf[i:i + 3, self.N // 2:self.N, 0:self.N // 2 + 1] img2[i:i + 3, :, :] = fft.irfft2(self._carray1) * self._reconfactor res = np.zeros((nim3, 2 * self.N, 2 * self.N), dtype=np.single) imgf = fft.rfft(img2[:, :self.N, :self.N], nim, 0)[:nim3 // 2 + 1, :, :] res[:, :self.N, :self.N] = fft.irfft(imgf, nim3, 0) imgf = fft.rfft(img2[:, :self.N, self.N:2 * self.N], nim, 0)[:nim3 // 2 + 1, :, :] res[:, :self.N, self.N:2 * self.N] = fft.irfft(imgf, nim3, 0) imgf = fft.rfft(img2[:, self.N:2 * self.N, :self.N], nim, 0)[:nim3 // 2 + 1, :, :] res[:, self.N:2 * self.N, :self.N] = fft.irfft(imgf, nim3, 0) imgf = fft.rfft(img2[:, self.N:2 * self.N, self.N:2 * self.N], nim, 0)[:nim3 // 2 + 1, :, :] res[:, self.N:2 * self.N, self.N:2 * self.N] = fft.irfft(imgf, nim3, 0) res = fft.irfft2(fft.rfft2(res) * self._postfilter[:, :self.N + 1]) return res
def seek_record_read(self, offset, size): if offset % self.recordsize != 0 or size % self.recordsize != 0: raise ValueError( "size and offset must be an integer number of records") raw = self.fh_raw.seek_record_read(offset, size) if self.npol == 2 and self._raw_data_class == AROCHIMERawData: raw = raw.view(raw.dtype.fields.values()[0][0]) raw = raw.reshape(-1, self.fh_raw.nchan, self.npol) nyq_pad = np.zeros((raw.shape[0], 1, self.npol), dtype=raw.dtype) raw = np.concatenate((raw, nyq_pad), axis=1) # Get pseudo-timestream pd = irfft(raw, axis=1, **_rfftargs) # Set up for deconvolution fpd = rfft(pd, axis=0, **_rfftargs) del pd if self.fh is None or self.fh.shape[0] != fpd.shape[0]: lh = np.zeros((raw.shape[0], self.h.shape[1])) lh[:self.h.shape[0]] = self.h self.fh = rfft(lh, axis=0, **_rfftargs).conj() del lh # FT of Wiener deconvolution kernel fg = self.fh.conj() / (np.abs(self.fh)**2 + (1 / self.sn)**2) # Deconvolve and get deconvolved timestream rd = irfft(fpd * fg[..., np.newaxis], axis=0, **_rfftargs).reshape(-1, self.npol) # select actual part requested self.offset = offset + size # view as a record array return rd.astype('f4')
def seek_record_read(self, offset, size): if offset % self.recordsize != 0 or size % self.recordsize != 0: raise ValueError("size and offset must be an integer number of records") raw = self.fh_raw.seek_record_read(offset, size) if self.npol == 2 and self._raw_data_class == AROCHIMERawData: raw = raw.view(raw.dtype.fields.values()[0][0]) raw = raw.reshape(-1, self.fh_raw.nchan, self.npol) nyq_pad = np.zeros((raw.shape[0], 1, self.npol), dtype=raw.dtype) raw = np.concatenate((raw, nyq_pad), axis=1) # Get pseudo-timestream pd = irfft(raw, axis=1, **_rfftargs) # Set up for deconvolution fpd = rfft(pd, axis=0, **_rfftargs) del pd if self.fh is None or self.fh.shape[0] != fpd.shape[0]: lh = np.zeros((raw.shape[0], self.h.shape[1])) lh[:self.h.shape[0]] = self.h self.fh = rfft(lh, axis=0, **_rfftargs).conj() del lh # FT of Wiener deconvolution kernel fg = self.fh.conj() / (np.abs(self.fh)**2 + (1/self.sn)**2) # Deconvolve and get deconvolved timestream rd = irfft(fpd * fg[..., np.newaxis], axis=0, **_rfftargs).reshape(-1, self.npol) # select actual part requested self.offset = offset + size # view as a record array return rd.astype('f4')
def read(self, samples): raw = self.fh.read(samples) raw = np.swapaxes(raw, 1, 2) nyq_pad = np.zeros((raw.shape[0], 1, self.npol), dtype=raw.dtype) raw = np.concatenate((raw, nyq_pad), axis=1) # Get pseudo-timestream pd = irfft(raw, axis=1) # Set up for deconvolution fpd = rfft(pd, axis=0) del pd lh = np.zeros((raw.shape[0], self.h.shape[1])) lh[:self.h.shape[0]] = self.h fh = rfft(lh, axis=0).conj() del lh # FT of Wiener deconvolution kernel fg = fh.conj() / (np.abs(fh)**2 + (1 / self.sn)**2) # Deconvolve and get deconvolved timestream rd = irfft(fpd * fg[..., np.newaxis], axis=0).reshape(-1, self.npol) # view as a record array return rd.astype('f4')
def read(self, samples): raw = self.fh.read(samples) raw = np.swapaxes(raw, 1, 2) nyq_pad = np.zeros((raw.shape[0], 1, self.npol), dtype=raw.dtype) raw = np.concatenate((raw, nyq_pad), axis=1) # Get pseudo-timestream pd = irfft(raw, axis=1) # Set up for deconvolution fpd = rfft(pd, axis=0) del pd lh = np.zeros((raw.shape[0], self.h.shape[1])) lh[:self.h.shape[0]] = self.h fh = rfft(lh, axis=0).conj() del lh # FT of Wiener deconvolution kernel fg = fh.conj() / (np.abs(fh)**2 + (1/self.sn)**2) # Deconvolve and get deconvolved timestream rd = irfft(fpd * fg[..., np.newaxis], axis=0).reshape(-1, self.npol) # view as a record array return rd.astype('f4')
def plotGottleibShuNoise(length, signalFunc, numSeries=16): source = signalFunc(length, numSeries) suppressed, g_hat = gottliebShu(source, numSeries) regibbsed = spectralLowpass(suppressed, numSeries) plot( source, suppressed, regibbsed, 'Filtered result', 'result_gottleibShu_' + signalFunc.__name__ + '.png', ) # Plot spectrum. source_spec = rfft(source)[0:numSeries + 1] regibbsed_spec = rfft(regibbsed)[0:numSeries + 1] source_power = numpy.abs(source_spec) regibbsed_power = numpy.abs(regibbsed_spec) source_phase = numpy.angle(source_spec) regibbsed_phase = numpy.angle(regibbsed_spec) fig = pyplot.figure(figsize=(8, 6)) ax11 = fig.add_subplot(221) ax11.set_title('Signal power') ax11.grid() ax11.plot(source_power) ax21 = fig.add_subplot(222) ax21.set_title('Signal phase') ax21.grid() ax21.set_ylim(-numpy.pi, numpy.pi) ax21.plot(source_phase) ax12 = fig.add_subplot(223) ax12.set_title('Filtered result power') ax12.grid() ax12.plot(regibbsed_power) ax22 = fig.add_subplot(224) ax22.set_title('Filtered result phase') ax22.grid() ax22.set_ylim(-numpy.pi, numpy.pi) ax22.plot(regibbsed_phase) fig.tight_layout() fig.savefig('spectrum_comparison_' + signalFunc.__name__ + '.png') pyplot.close()
def display_radMUSIC(self, frequency, npoints=360, signals=1, shw=True, block_run=False): """Display a polar plot of estimated DOA using the MUSIC algorithm Arguments: frequency (float): The frequency to use for the MUSIC calculation. npoints (int): The total number of points around the circle at which to evaluate. signals (int): The numbers of signals to locate. shw (bool): Show the plot? If False, will return the data that was to be plotted. block_run (bool): Pause execution of the file while the figure is open? Set to True for running in the command-line. """ X = 2 * np.pi * np.arange(start=0, stop=npoints) / npoints self.dataFFT = fft_pack.rfft(self.data, axis=0, n=2 * self.data.shape[0]) pos = fft_pack.rfftfreq(2 * self.data.shape[0]) * self.sample_rate actidx = np.argmin(abs(pos - frequency)) cors, _ = self._MUSIC1D_((pos[actidx], actidx), X, numsignals=signals) if shw: plt.figure() ax = plt.subplot(111, projection='polar') ax.plot(X, cors) ax.set_title("Estimated Acoustic Source Direction") plt.show(block=block_run) else: return cors
def ir2fr(ir, fs, N=None): """ Convert impulse response into frequency response. Returns single-sided RMS spectrum. :param ir: Impulser response :param fs: Sample frequency :param N: Blocks Calculates the positive frequencies using :func:`np.fft.rfft`. Corrections are then applied to obtain the single-sided spectrum. .. note:: Single-sided spectrum. Therefore, the amount of bins returned is either N/2 or N/2+1. """ #ir = ir - np.mean(ir) # Remove DC component. N = N if N else ir.shape[-1] fr = rfft(ir, n=N) / N f = np.fft.rfftfreq(N, 1.0 / fs) #/ 2.0 fr *= 2.0 fr[..., 0] /= 2.0 # DC component should not be doubled. if not N % 2: # if not uneven fr[..., -1] /= 2.0 # And neither should fs/2 be. #f = np.arange(0, N/2+1)*(fs/N) return f, fr
def ir2fr(ir, fs, N=None): """ Convert impulse response into frequency response. Returns single-sided RMS spectrum. :param ir: Impulser response :param fs: Sample frequency :param N: Blocks Calculates the positive frequencies using :func:`np.fft.rfft`. Corrections are then applied to obtain the single-sided spectrum. .. note:: Single-sided spectrum. Therefore, the amount of bins returned is either N/2 or N/2+1. """ #ir = ir - np.mean(ir) # Remove DC component. N = N if N else ir.shape[-1] fr = rfft(ir, n=N) / N f = np.fft.rfftfreq(N, 1.0/fs) #/ 2.0 fr *= 2.0 fr[..., 0] /= 2.0 # DC component should not be doubled. if not N%2: # if not uneven fr[..., -1] /= 2.0 # And neither should fs/2 be. #f = np.arange(0, N/2+1)*(fs/N) return f, fr
def compPhaseShifts4(y): try: sns.set_palette(sns.color_palette("husl", 20)) except: pass fig, ax = lab.subplots() fft = fftw.rfft(y) shifts = np.arange(-np.pi, np.pi, 0.01) for tZero in range(310, 330): print tZero causalityRatio = [] for i in range(0, len(shifts)): shiftedFFT = fftPhaseShift(fft, shifts[i]) shifted = fftw.irfft(shiftedFFT) causalityRatio.append( np.sum(shifted[:tZero]**2) / np.sum(shifted[tZero:]**2)) ax.plot(shifts, causalityRatio, label=tZero) ax.legend() fig.show() return
def __call__(self, max_peak_count=None, max_peak_frequency=None, min_peak_frequency=None, proc_name=None): # from sasha import sasha_configuration try: with systemtools.Timer("\t{}: [{}] Computing RFFT:".format(proc_name, self.frame_id)): fft = rfft(self.windowed_audio) with systemtools.Timer("\t{}: [{}] Locating peaks:".format(proc_name, self.frame_id)): peaks = [] mag = abs(fft) prev_mag = numpy.abs(mag[0]) this_mag = numpy.abs(mag[1]) next_mag = None for bin in range(2, len(mag) - 1): next_mag = numpy.abs(mag[bin]) if prev_mag < this_mag and next_mag < this_mag: frequency = (bin - 1) * self.fundamental amplitude = this_mag phase = numpy.angle(fft[bin - 1]) peak = Peak(frequency, amplitude, phase, frame_id=self.frame_id) peaks.append(peak) prev_mag = this_mag this_mag = next_mag self._peaks = self._filter_peaks( peaks, max_peak_count=max_peak_count, max_peak_frequency=max_peak_frequency, min_peak_frequency=min_peak_frequency, ) self._frequencies = tuple(_.frequency for _ in self) self._midis = tuple(_.midis for _ in self) except: import traceback traceback.print_exc()
def BasebandProcess(ar_data, band, SR, dt, N, DN, offset, i, dd_coh, ngate): print('ar_data', ar_data) fh = mark4.open(ar_data, 'rs', ntrack=64, decade=2010, sample_rate=SR, thread_ids=[2 * band, 2 * band + 1]) fh.seek(offset + i * (N - DN)) t0 = fh.tell(unit='time') print('t0', t0) t1 = t0.mjd print('t1', t1) print('N-DN', N - DN) print('dt', dt) print('ngate', ngate) # note ph is equilibrium to ((ph)*P0) / (P0/ngate) % ngate ph, ncycle = FindPhase(t0, N - DN, dt, ngate) ph %= ngate print('ph3', ph) z = fh.read(N) z = rfft(z, axis=0, **_fftargs) z *= dd_coh[..., np.newaxis] z = irfft(z, axis=0, **_fftargs)[:-DN] z = z.astype(np.float32) z = z * z return ph, z
def timePhaseShift(Y, shift): fft = fftw.rfft(Y) gainLin, phase = complexToGainAndPhase(fft) phase += shift # phase[phase>=np.pi] -= np.pi # phase[phase<=-np.pi] += np.pi fft = gainAndPhaseToComplex(gainLin, phase) outY = fftw.irfft(fft) return outY
def _shift(trace, shift): """Shift trace by given time and correct starttime => interpolation""" msg = ('interpolate trace %s with starttime %s to shift by %.6fs ' '(Fourier method)') log.debug(msg, trace.id, trace.stats.starttime, shift) nfft = next_fast_len(len(trace)) spec = rfft(trace.data, nfft) freq = rfftfreq(nfft, trace.stats.delta) spec *= np.exp(-2j * np.pi * freq * shift) trace.data = irfft(spec, nfft)[:len(trace)] trace.stats.starttime -= shift return trace
def correlation(graphA, graphB): """ Takes in two EVENLY SAMPLED graphs, then does the cross correlation in fourier space NOTE: I need to roll this a bit! Note to Note: Why? to draw it away from zero? Maybe no roll :( """ # fart,graphA = zeroPadEqual(np.arange(len(graphA)),graphA,len(graphA)*3) # fart,graphB = zeroPadEqual(np.arange(len(graphB)),graphB,len(graphB)*3) fftA = fftw.rfft(np.array(graphA)) fftB = fftw.rfft(np.array(graphB)) xCorr = np.conj(fftA) * fftB iXCorr = fftw.irfft(xCorr) # return np.roll(iXCorr,len(iXCorr)/2) return iXCorr
def display_radMUSICchunked(self, frequency, npoints=360, signals=1, shw=True, block_run=False, chunks=10): """Display a polar plot of estimated DOA using the MUSIC algorithm Arguments: frequency (float): The frequency to use for the MUSIC calculation. npoints (int): The total number of points around the circle at which to evaluate. signals (int): The numbers of signals to locate. shw (bool): Show the plot? If False, will return the data that was to be plotted. block_run (bool): Pause execution of the file while the figure is open? Set to True for running in the command-line. """ X = 2 * np.pi * np.arange(start=0, stop=npoints) / npoints tRxx = np.zeros((self.mics.shape[0], self.mics.shape[0]), dtype='complex128') indices = [ int(x) for x in np.linspace( 0, self.data.shape[0], num=chunks + 1, endpoint=True) ] for mark in np.arange(len(indices) - 1): dcr = self.data[indices[mark]:indices[mark + 1], :] print(dcr.shape) ft = fft_pack.rfft(dcr, axis=0, n=2 * self.data.shape[0]) pos = fft_pack.rfftfreq(2 * self.data.shape[0]) * self.sample_rate actidx = np.argmin(abs(pos - frequency)) tRxx += np.dot(ft[actidx:actidx + 1].T, np.conj(ft[actidx:actidx + 1])) tRxx /= chunks print(tRxx) # self.dataFFT = fft_pack.rfft(self.data, axis=0, n=2*self.data.shape[0]) cors, _ = self._MUSIC1D_((pos[actidx], actidx), X, numsignals=signals, SI=tRxx) if shw: plt.figure() ax = plt.subplot(111, projection='polar') ax.plot(X, cors) ax.set_title("Estimated Acoustic Source Direction") plt.show(block=block_run) else: return cors
def readPFB(self, samples): import timeit start_time = timeit.default_timer() raw = self.read(samples) raw = np.swapaxes(raw, 1, 2) nyq_pad = np.zeros((raw.shape[0], 1, self.npol), dtype=raw.dtype) raw = np.concatenate((raw, nyq_pad), axis=1) # Get pseudo-timestream pd = irfft(raw, axis=1) # Set up for deconvolution fpd = rfft(pd, axis=0) del pd #if not 'han' in self.__dict__ : lh = np.zeros((raw.shape[0], self.h.shape[1])) lh[:self.h.shape[0]] = self.h self.han = rfft(lh, axis=0).conj() del lh # FT of Wiener deconvolution kernel fg = self.han.conj() / (np.abs(self.han)**2 + (1 / self.sn)**2) print(fpd.shape) # Deconvolve and get deconvolved timestream rd = irfft(fpd * fg[..., np.newaxis], axis=0) print(rd.shape) rd = rd.reshape(-1, self.npol) print(timeit.default_timer() - start_time) # view as a record array return rd.astype('f4')
def render_plot(): out_dir = "img" pathlib.Path(out_dir).mkdir(exist_ok=True) x = numpy.linspace(-1, 1, 512) rich = numpy.linspace(0, 1, 1201) rich = 0.5 - 3 * rich * rich plotter = Plotter(out_dir, int(len(x) / 2) + 1) for w in rich: data = normalize(mdadx10_sine(x, w)) freq = to_decibel(rfft(data, planner_effort='FFTW_ESTIMATE')) plotter.plot(data, freq, x, w)
def makeCausalTime(y, tZero): """ If you have the time series, this makes it easier (but slightly slower! Two more FFTS!) you have to provide the pulse (in bins) """ fft = fftw.rfft(y) shifted = makeCausalFFT(fft, tZero) yOut = fftw.irfft(shifted) return yOut
def violet(N): """ Violet noise. Power increases with 6 dB per octave. :param N: Amount of samples. Power increases with +9 dB per octave. Power density increases with +6 dB per octave. """ x = np.random.randn(N) X = rfft(x) / N S = (np.arange(len(X)))# Filter y = (irfft(X*S)).real[0:N] return normalise(y)
def violet(N): """ Violet noise. Power increases with 6 dB per octave. :param N: Amount of samples. Power increases with +9 dB per octave. Power density increases with +6 dB per octave. """ x = np.random.randn(N) X = rfft(x) / N S = (np.arange(len(X))) # Filter y = (irfft(X * S)).real[0:N] return normalise(y)
def brown(N): """ Violet noise. :param N: Amount of samples. Power decreases with -3 dB per octave. Power density decreases with 6 dB per octave. """ x = np.random.randn(N) X = rfft(x) / N S = (np.arange(len(X))+1)# Filter y = (irfft(X/S)).real[0:N] return normalise(y)
def blue(N): """ Blue noise. :param N: Amount of samples. Power increases with 6 dB per octave. Power density increases with 3 dB per octave. """ x = np.random.randn(N) X = rfft(x) / N S = np.sqrt(np.arange(len(X))) # Filter y = (irfft(X * S)).real[0:N] return normalise(y)
def blue(N): """ Blue noise. :param N: Amount of samples. Power increases with 6 dB per octave. Power density increases with 3 dB per octave. """ x = np.random.randn(N) X = rfft(x) / N S = np.sqrt(np.arange(len(X)))# Filter y = (irfft(X*S)).real[0:N] return normalise(y)
def brown(N): """ Violet noise. :param N: Amount of samples. Power decreases with -3 dB per octave. Power density decreases with 6 dB per octave. """ x = np.random.randn(N) X = rfft(x) / N S = (np.arange(len(X)) + 1) # Filter y = (irfft(X / S)).real[0:N] return normalise(y)
def violet(N: int) -> np.ndarray: """ Violet noise. Power increases with 6 dB per octave. * N: Amount of samples. Power increases with +9 dB per octave. Power density increases with +6 dB per octave. https://github.com/python-acoustics """ x = white(N) X = rfft(x) / N S = np.arange(X.size) # Filter y = irfft(X * S).real[0:N] return normalise(y)
def apply_noise(y, target_snr_db=20): ## Adapted from: https://stackoverflow.com/questions/14058340/adding-noise-to-a-signal-in-python ## Apply random white noise to signal to reach target_snr_db x_watts = y ** 2 sig_avg_watts = np.mean(x_watts) sig_avg_db = 10 * np.log10(sig_avg_watts) # Calculate noise according to [2] then convert to watts noise_avg_db = sig_avg_db - float(target_snr_db) noise_avg_watts = 10 ** (noise_avg_db / 10) # Generate an sample of white noise mean_noise = 0 noise_volts = np.random.normal(mean_noise, noise_avg_watts, len(x_watts)) Xb = rfft(noise_volts) / len(noise_volts) Sb = np.arange(Xb.size)+1 # Filter yb = irfft(Xb/Sb).real[:len(noise_volts)] # Noise up the original signal noisy_signal = y + yb return np.clip(noisy_signal, -1, 1)
def batchreconstruct(self, img, n_output_frames=None): nim = img.shape[0] r = np.mod(nim, 14) if r > 0: # pad with empty frames so total number of frames is divisible by 14 img = np.concatenate((img, np.zeros((14 - r, self.N, self.N), np.single))) nim = nim + 14 - r imf = fft.rfft2(img) * self._prefilter[:, 0:self.N // 2 + 1] img2 = np.zeros([nim, 2 * self.N, 2 * self.N], dtype=np.single) for i in range(0, nim, 7): self._carray1[:, 0:self.N // 2, 0:self.N // 2 + 1] = imf[i:i + 7, 0:self.N // 2, 0:self.N // 2 + 1] self._carray1[:, 3 * self.N // 2:2 * self.N, 0:self.N // 2 + 1] = imf[i:i + 7, self.N // 2:self.N, 0:self.N // 2 + 1] img2[i:i + 7, :, :] = fft.irfft2(self._carray1) * self._reconfactor nim7 = nim // 7 if n_output_frames is None: n_output_frames = nim7 img3 = fft.irfft(fft.rfft(img2, nim, 0)[0:nim7 // 2 + 1, :, :], n_output_frames, 0) res = fft.irfft2(fft.rfft2(img3) * self._postfilter[:, :self.N + 1]) return res
def pink(N): """ Pink noise. :param N: Amount of samples. Pink noise has equal power in bands that are proportionally wide. Power density decreases with 3 dB per octave. """ # This method uses the filter with the following coefficients. #b = np.array([0.049922035, -0.095993537, 0.050612699, -0.004408786]) #a = np.array([1, -2.494956002, 2.017265875, -0.522189400]) #return lfilter(B, A, np.random.randn(N)) # Another way would be using the FFT x = np.random.randn(N) X = rfft(x) / N S = np.sqrt(np.arange(len(X)) + 1.) # +1 to avoid divide by zero y = (irfft(X / S)).real[0:N] return normalise(y)
def pink(N): """ Pink noise. :param N: Amount of samples. Pink noise has equal power in bands that are proportionally wide. Power density decreases with 3 dB per octave. """ # This method uses the filter with the following coefficients. #b = np.array([0.049922035, -0.095993537, 0.050612699, -0.004408786]) #a = np.array([1, -2.494956002, 2.017265875, -0.522189400]) #return lfilter(B, A, np.random.randn(N)) # Another way would be using the FFT x = np.random.randn(N) X = rfft(x) / N S = np.sqrt(np.arange(len(X))+1.) # +1 to avoid divide by zero y = (irfft(X/S)).real[0:N] return normalise(y)
def rfft(data, n_samples, sampling_rate, fft_norm): """ Calculate the FFT of a real-valued time-signal. The function returns only the right-hand side of the axis-symmetric spectrum. The normalization distinguishes between energy and power signals. Energy signals are not normalized in the forward transform. Power signals are normalized by their number of samples and to their effective value as well as compensated for the missing energy from the left-hand side of the spectrum. This ensures that the energy of the time signal and the right-hand side of the spectrum are equal and thus fulfill Parseval's theorem. Parameters ---------- data : array, double Array containing the time domain signal with dimensions (..., n_samples) n_samples : int The number of samples sampling_rate : number sampling rate in Hz fft_norm : 'unitary', 'amplitude', 'rms', 'power', 'psd' See documentation of :py:func:`~pyfar.dsp.fft.normalization`. Returns ------- spec : array, complex The complex valued right-hand side of the spectrum with dimensions (..., n_bins) """ # DFT spec = fft_lib.rfft(data, n=n_samples, axis=-1) # Normalization spec = normalization(spec, n_samples, sampling_rate, fft_norm, inverse=False, single_sided=True) return spec
def filtering(proj,geo,angles,parker): if parker: proj = parkerweight(proj.transpose(0,2,1),geo,angles,parker).transpose(0,2,1) # proj=parkerweight(proj,geo,angles,parker) filt_len = max(64,2 ** nextpow2(2 * geo.nDetector[0])) ramp_kernel = ramp_flat(filt_len) d = 1 filt = filter(geo.filter,ramp_kernel[0],filt_len,d) filt = np.kron(np.ones((geo.nDetector[1],1)),filt).transpose() for i in range(len(angles)): # Zero-padding: fproj = np.zeros((filt_len,geo.nDetector[1]),dtype=np.float32) fproj[int(filt_len / 2 - geo.nDetector[0] / 2):int(filt_len / 2 + geo.nDetector[0] / 2),:] = proj[:,:,i] # Fourier-transform: n_byte_align(fproj, simd_alignment) fproj = rfft(fproj, axis=0, threads=2) # Filter: fproj = fproj * filt[0:fproj.shape[0],:] # Inverse-Fourier: n_byte_align(fproj, simd_alignment) fproj = np.real(irfft(fproj, axis=0, threads=2)) end = len(fproj) # Crop: fproj = fproj[int(end / 2 - geo.nDetector[0] / 2):int(end / 2 + geo.nDetector[0] / 2),:] / 2 / geo.dDetector[0] * \ (2 * np.pi / len(angles)) / 2 * (geo.DSD / geo.DSO) proj[:,:,i] = fproj.astype(np.float32) return proj
def pink(N: int) -> np.ndarray: """ Pink noise. * N: Amount of samples. Pink noise has equal power in bands that are proportionally wide. Power density decreases with 3 dB per octave. https://github.com/python-acoustics """ # This method uses the filter with the following coefficients. # b = np.array([0.049922035, -0.095993537, 0.050612699, -0.004408786]) # a = np.array([1, -2.494956002, 2.017265875, -0.522189400]) # return lfilter(B, A, np.random.randn(N)) # Another way would be using the FFT x = white(N) X = rfft(x) / N S = np.sqrt(np.arange(X.size) + 1.0) # +1 to avoid divide by zero y = irfft(X / S).real[:N] return normalise(y) # extremely tiny value 1e-9 without normalization
def AF_MUSIC(self, focusing_freq=-1, npoints=1000, signals=1, shw=True, block_run=True, chunks=10): """Display a polar plot of estimated DOA using the MUSIC algorithm Arguments: focusing_freq (float): The frequency (in Hz) at which to perform the calculation. If <0, will default to 0.9*(spatial Nyquist frequency) npoints (int): The total number of points around the circle at which to evaluate. signals (int): The numbers of signals to locate. shw (bool): Show the plot? If False, will return the data that was to be plotted. block_run (bool): Pause execution of the file while the figure is open? Set to True for running in the command-line. chunks (int): How many sections to split the data up into. Will split up the data and average the result over the split sections """ omegas = np.linspace(0, 2 * np.pi, npoints, endpoint=False) rest = np.zeros_like(omegas) if focusing_freq < 0: focusing_freq = self.spatial_nyquist_freq * 0.9 # First generate Rxxs to get to T_autos # Tauto will go in here Tauto = np.zeros((self.mics.shape[0], self.mics.shape[0], self.data.shape[0] // 2 + 1), dtype="complex128") # Rxx will go in here Rxx = np.zeros((self.mics.shape[0], self.mics.shape[0], self.data.shape[0] // 2 + 1), dtype="complex128") # Ufi will go in here Ufi = np.zeros((self.mics.shape[0], self.mics.shape[0], self.data.shape[0] // 2 + 1), dtype="complex128") # Ryy will go in here Ryy = np.zeros((self.mics.shape[0], self.mics.shape[0], self.data.shape[0] // 2 + 1), dtype="complex128") # Split the data up into "chunks" sections indices = [ int(x) for x in np.linspace( 0, self.data.shape[0], num=chunks + 1, endpoint=True) ] # Calculate Rxx for mark in np.arange(len(indices) - 1): dcr = self.data[indices[mark]:indices[mark + 1], :] for chnl in np.arange(dcr.shape[1]): dcr[:, chnl] *= np.blackman(dcr.shape[0]) # dft is RFFT of current data chunk dft = fft_pack.rfft(dcr, axis=0, n=self.data.shape[0]).T dft.shape = (dft.shape[0], 1, dft.shape[1]) # print(dft.shape, self.data.shape, Tauto.shape) Rxx += np.einsum("jin,iln->jln", dft, np.conj(np.transpose(dft, (1, 0, 2)))) / chunks # The frequencies for Tauto and DFT. They all have the same length so this is fine to do outside the loop pos = fft_pack.rfftfreq(self.data.shape[0]) * self.sample_rate # focusing_freq_index is the index along dft and Tauto to find f_0 focusing_freq_index = np.argmin(np.abs(pos - focusing_freq)) eig_f0, v_f0 = np.linalg.eigh(Rxx[:, :, focusing_freq_index]) Uf0 = v_f0[:, np.argsort(np.abs(eig_f0))[::-1]] # Calculate Tautos for indx, fi in enumerate(pos): eig_fi, v_fi = np.linalg.eigh(Rxx[:, :, indx]) Ufi[:, :, indx] = v_fi[:, np.argsort(np.abs(eig_fi))[::-1]] Tauto[:, :, indx] = dot(Uf0, np.conj(Ufi[:, :, indx].T)) / np.sqrt( pos.shape[0]) # Calculate Ryy chunks = 1.0 indices = [ int(x) for x in np.linspace( 0, self.data.shape[0], num=chunks + 1, endpoint=True) ] for mark in np.arange(len(indices) - 1): dcr = self.data[indices[mark]:indices[mark + 1], :] for chnl in np.arange(dcr.shape[1]): dcr[:, chnl] *= np.blackman(dcr.shape[0]) # dft is RFFT of current data chunk dft = fft_pack.rfft(dcr, axis=0, n=self.data.shape[0]).T dft.shape = (dft.shape[0], 1, dft.shape[1]) # print(dft.shape, self.data.shape, Tauto.shape) Yi = np.einsum("abc,bdc->adc", Tauto, dft) Ryy += np.einsum("jin,iln->jln", Yi, np.conj(np.transpose(Yi, (1, 0, 2)))) / chunks Rcoh = np.sum(Ryy, axis=-1) / (self.data.shape[0] // 2 + 1) rest, _ = self._MUSIC1D_((focusing_freq, focusing_freq_index), omegas, SI=Rcoh) if shw: plt.figure() ax = plt.subplot(111, projection='polar') ax.plot(omegas, rest) ax.set_title("Estimated Acoustic Source Direction") plt.show(block=block_run) else: return rest
def fold(fh, comm, samplerate, fedge, fedge_at_top, nchan, nt, ntint, ngate, ntbin, ntw, dm, fref, phasepol, dedisperse='incoherent', do_waterfall=True, do_foldspec=True, verbose=True, progress_interval=100, rfi_filter_raw=None, rfi_filter_power=None, return_fits=False): """ FFT data, fold by phase/time and make a waterfall series Folding is done from the position the file is currently in Parameters ---------- fh : file handle handle to file holding voltage timeseries comm: MPI communicator or None will use size, rank attributes samplerate : Quantity rate at which samples were originally taken and thus double the band width (frequency units) fedge : float edge of the frequency band (frequency units) fedge_at_top: bool whether edge is at top (True) or bottom (False) nchan : int number of frequency channels for FFT nt, ntint : int total number nt of sets, each containing ntint samples in each file hence, total # of samples is nt*ntint, with each sample containing a single polarisation ngate, ntbin : int number of phase and time bins to use for folded spectrum ntbin should be an integer fraction of nt ntw : int number of time samples to combine for waterfall (does not have to be integer fraction of nt) dm : float dispersion measure of pulsar, used to correct for ism delay (column number density) fref: float reference frequency for dispersion measure phasepol : callable function that returns the pulsar phase for time in seconds relative to start of the file that is read. dedisperse : None or string (default: incoherent). None, 'incoherent', 'coherent', 'by-channel'. Note: None really does nothing do_waterfall, do_foldspec : bool whether to construct waterfall, folded spectrum (default: True) verbose : bool or int whether to give some progress information (default: True) progress_interval : int Ping every progress_interval sets return_fits : bool (default: False) return a subint fits table for rank == 0 (None otherwise) """ assert dedisperse in (None, 'incoherent', 'by-channel', 'coherent') need_fine_channels = dedisperse in ['by-channel', 'coherent'] assert nchan % fh.nchan == 0 if dedisperse in ['incoherent', 'by-channel'] and fh.nchan > 1: oversample = nchan // fh.nchan assert ntint % oversample == 0 else: oversample = 1 if dedisperse == 'coherent' and fh.nchan > 1: raise ValueError("Cannot coherently dedisperse channelized data.") if comm is None: mpi_rank = 0 mpi_size = 1 else: mpi_rank = comm.rank mpi_size = comm.size npol = getattr(fh, 'npol', 1) assert npol == 1 or npol == 2 if verbose > 1 and mpi_rank == 0: print("Number of polarisations={}".format(npol)) # initialize folded spectrum and waterfall # TODO: use estimated number of points to set dtype if do_foldspec: foldspec = np.zeros((ntbin, nchan, ngate, npol**2), dtype=np.float32) icount = np.zeros((ntbin, nchan, ngate), dtype=np.int32) else: foldspec = None icount = None if do_waterfall: nwsize = nt*ntint//ntw//oversample waterfall = np.zeros((nwsize, nchan, npol**2), dtype=np.float64) else: waterfall = None if verbose and mpi_rank == 0: print('Reading from {}'.format(fh)) nskip = fh.tell()/fh.blocksize if nskip > 0: if verbose and mpi_rank == 0: print('Starting {0} blocks = {1} bytes out from start.' .format(nskip, nskip*fh.blocksize)) dt1 = (1./samplerate).to(u.s) # need 2*nchan real-valued samples for each FFT if fh.telescope == 'lofar': dtsample = fh.dtsample else: dtsample = nchan // oversample * 2 * dt1 tstart = dtsample * ntint * nskip # pre-calculate time delay due to dispersion in coarse channels # for channelized data, frequencies are known tb = -1. if fedge_at_top else +1. if fh.nchan == 1: if getattr(fh, 'data_is_complex', False): # for complex data, really each complex sample consists of # 2 real ones, so multiply dt1 by 2. freq = fedge + tb * fftfreq(nchan, 2.*dt1) if dedisperse == 'coherent': fcoh = fedge + tb * fftfreq(nchan*ntint, 2.*dt1) fcoh.shape = (-1, 1) elif dedisperse == 'by-channel': fcoh = freq + tb * fftfreq(ntint, dtsample)[:, np.newaxis] else: # real data freq = fedge + tb * rfftfreq(nchan*2, dt1) if dedisperse == 'coherent': fcoh = fedge + tb * rfftfreq(ntint*nchan*2, dt1) fcoh.shape = (-1, 1) elif dedisperse == 'by-channel': fcoh = freq + tb * fftfreq(ntint, dtsample)[:, np.newaxis] freq_in = freq else: # Input frequencies may not be the ones going out. freq_in = fh.frequencies if oversample == 1: freq = freq_in else: freq = freq_in[:, np.newaxis] + tb * fftfreq(oversample, dtsample) fcoh = freq_in + tb * fftfreq(ntint, dtsample)[:, np.newaxis] # print('fedge_at_top={0}, tb={1}'.format(fedge_at_top, tb)) # By taking only up to nchan, we remove the top channel at the Nyquist # frequency for real, unchannelized data. ifreq = freq[:nchan].ravel().argsort() # pre-calculate time offsets in (input) channelized streams dt = dispersion_delay_constant * dm * (1./freq_in**2 - 1./fref**2) if need_fine_channels: # pre-calculate required turns due to dispersion. # # set frequency relative to which dispersion is coherently corrected if dedisperse == 'coherent': _fref = fref else: _fref = freq_in[np.newaxis, :] # (check via eq. 5.21 and following in # Lorimer & Kramer, Handbook of Pulsar Astronomy dang = (dispersion_delay_constant * dm * fcoh * (1./_fref-1./fcoh)**2) * u.cycle with u.set_enabled_equivalencies(u.dimensionless_angles()): dd_coh = np.exp(dang * 1j).conj().astype(np.complex64) # add dimension for polarisation dd_coh = dd_coh[..., np.newaxis] # Calculate the part of the whole file this node should handle. size_per_node = (nt-1)//mpi_size + 1 start_block = mpi_rank*size_per_node end_block = min((mpi_rank+1)*size_per_node, nt) for j in range(start_block, end_block): if verbose and j % progress_interval == 0: print('#{:4d}/{:4d} is doing {:6d}/{:6d} [={:6d}/{:6d}]; ' 'time={:18.12f}' .format(mpi_rank, mpi_size, j+1, nt, j-start_block+1, end_block-start_block, (tstart+dtsample*j*ntint).value)) # time since start # Just in case numbers were set wrong -- break if file ends; # better keep at least the work done. try: raw = fh.seek_record_read(int((nskip+j)*fh.blocksize), fh.blocksize) except(EOFError, IOError) as exc: print("Hit {0!r}; writing data collected.".format(exc)) break if verbose >= 2: print("#{:4d}/{:4d} read {} items" .format(mpi_rank, mpi_size, raw.size), end="") if npol == 2 and raw.dtype.fields is not None: raw = raw.view(raw.dtype.fields.values()[0][0]) if fh.nchan == 1: # raw.shape=(ntint*npol) raw = raw.reshape(-1, npol) else: # raw.shape=(ntint, nchan*npol) raw = raw.reshape(-1, fh.nchan, npol) if dedisperse == 'incoherent' and oversample > 1: raw = ifft(raw, axis=1, **_fftargs).reshape(-1, nchan, npol) raw = fft(raw, axis=1, **_fftargs) if rfi_filter_raw is not None: raw, ok = rfi_filter_raw(raw) if verbose >= 2: print("... raw RFI (zap {0}/{1})" .format(np.count_nonzero(~ok), ok.size), end="") if np.can_cast(raw.dtype, np.float32): vals = raw.astype(np.float32) else: assert raw.dtype.kind == 'c' vals = raw # For pre-channelized data, data are always complex, # and should have shape (ntint, nchan, npol). # For baseband data, we wish to get to the same shape for # incoherent or by_channel, or just to fully channelized for coherent. if fh.nchan == 1: # If we need coherent dedispersion, do FT of whole thing, # otherwise to output channels, mimicking pre-channelized data. if raw.dtype.kind == 'c': # complex data nsamp = len(vals) if dedisperse == 'coherent' else nchan vals = fft(vals.reshape(-1, nsamp, npol), axis=1, **_fftargs) else: # real data nsamp = len(vals) if dedisperse == 'coherent' else nchan * 2 vals = rfft(vals.reshape(-1, nsamp, npol), axis=1, **_rfftargs) # Sadly, the way data are stored depends on what FFT routine # one is using. We cannot deal with scipy's. if vals.dtype.kind == 'f': raise TypeError("Can no longer deal with scipy's format " "for storing FTs of real data.") if fedge_at_top: # take complex conjugate to ensure by-channel de-dispersion is # applied correctly. # This needs to be done for ARO data, since we are in 2nd Nyquist # zone; not clear it is needed for other telescopes. np.conj(vals, out=vals) # Now we coherently dedisperse, either all of it or by channel. if need_fine_channels: # for by_channel, we have vals.shape=(ntint, nchan, npol), # and want to FT over ntint to get fine channels; if vals.shape[0] > 1: fine = fft(vals, axis=0, **_fftargs) else: # for coherent, we just reshape: # (1, ntint*nchan, npol) -> (ntint*nchan, 1, npol) fine = vals.reshape(-1, 1, npol) # Dedisperse. fine *= dd_coh # Still have fine.shape=(ntint, nchan, npol), # w/ nchan=1 for coherent. if fine.shape[1] > 1 or raw.dtype.kind == 'c': vals = ifft(fine, axis=0, **_fftargs) else: vals = irfft(fine, axis=0, **_rfftargs) if fine.shape[1] == 1 and nchan > 1: # final FT to get requested channels if vals.dtype.kind == 'f': vals = vals.reshape(-1, nchan*2, npol) vals = rfft(vals, axis=1, **_rfftargs) else: vals = vals.reshape(-1, nchan, npol) vals = fft(vals, axis=1, **_fftargs) elif dedisperse == 'by-channel' and oversample > 1: vals = vals.reshape(-1, oversample, fh.nchan, npol) vals = fft(vals, axis=1, **_fftargs) vals = vals.transpose(0, 2, 1, 3).reshape(-1, nchan, npol) # vals[time, chan, pol] if verbose >= 2: print("... dedispersed", end="") if npol == 1: power = vals.real**2 + vals.imag**2 else: p0 = vals[..., 0] p1 = vals[..., 1] power = np.empty(vals.shape[:-1] + (4,), np.float32) power[..., 0] = p0.real**2 + p0.imag**2 power[..., 1] = p0.real*p1.real + p0.imag*p1.imag power[..., 2] = p0.imag*p1.real - p0.real*p1.imag power[..., 3] = p1.real**2 + p1.imag**2 if verbose >= 2: print("... power", end="") # current sample positions and corresponding time in stream isr = j*(ntint // oversample) + np.arange(ntint // oversample) tsr = (isr*dtsample*oversample)[:, np.newaxis] if rfi_filter_power is not None: power = rfi_filter_power(power, tsr.squeeze()) print("... power RFI", end="") # correct for delay if needed if dedisperse in ['incoherent', 'by-channel']: # tsample.shape=(ntint/oversample, nchan_in) tsr = tsr - dt if do_waterfall: # # loop over corresponding positions in waterfall # for iw in xrange(isr[0]//ntw, isr[-1]//ntw + 1): # if iw < nwsize: # add sum of corresponding samples # waterfall[iw, :] += np.sum(power[isr//ntw == iw], # axis=0)[ifreq] iw = np.round((tsr / dtsample / oversample).to(1) .value / ntw).astype(int) for k, kfreq in enumerate(ifreq): # sort in frequency while at it iwk = iw[:, (0 if iw.shape[1] == 1 else kfreq // oversample)] iwk = np.clip(iwk, 0, nwsize-1, out=iwk) iwkmin = iwk.min() iwkmax = iwk.max()+1 for ipow in range(npol**2): waterfall[iwkmin:iwkmax, k, ipow] += np.bincount( iwk-iwkmin, power[:, kfreq, ipow], iwkmax-iwkmin) if verbose >= 2: print("... waterfall", end="") if do_foldspec: ibin = (j*ntbin) // nt # bin in the time series: 0..ntbin-1 # times and cycles since start time of observation. tsample = tstart + tsr phase = (phasepol(tsample.to(u.s).value.ravel()) .reshape(tsample.shape)) # corresponding PSR phases iphase = np.remainder(phase*ngate, ngate).astype(np.int) for k, kfreq in enumerate(ifreq): # sort in frequency while at it iph = iphase[:, (0 if iphase.shape[1] == 1 else kfreq // oversample)] # sum and count samples by phase bin for ipow in range(npol**2): foldspec[ibin, k, :, ipow] += np.bincount( iph, power[:, kfreq, ipow], ngate) icount[ibin, k, :] += np.bincount( iph, power[:, kfreq, 0] != 0., ngate).astype(np.int32) if verbose >= 2: print("... folded", end="") if verbose >= 2: print("... done") #Commented out as workaround, this was causing "Referenced before assignment" errors with JB data #if verbose >= 2 or verbose and mpi_rank == 0: # print('#{:4d}/{:4d} read {:6d} out of {:6d}' # .format(mpi_rank, mpi_size, j+1, nt)) if npol == 1: if do_foldspec: foldspec = foldspec.reshape(foldspec.shape[:-1]) if do_waterfall: waterfall = waterfall.reshape(waterfall.shape[:-1]) return foldspec, icount, waterfall
======= if fh.telescope in ('arochime','arochime-raw'): # take complex conjugate to ensure by-channel de-dispersion is applied correctly vals = np.conj(vals) >>>>>>> e6d25c1bfcc5a3426bc62becc3b3075fbea23ebc if fh.nchan == 1: # If we need coherent dedispersion, do FT of whole thing, # otherwise to output channels, mimicking pre-channelized data. if raw.dtype.kind == 'c': # complex data nsamp = len(vals) if dedisperse == 'coherent' else nchan vals = fft(vals.reshape(-1, nsamp, npol), axis=1, **_fftargs) else: # real data nsamp = len(vals) if dedisperse == 'coherent' else nchan * 2 vals = rfft(vals.reshape(-1, nsamp, npol), axis=1, **_rfftargs) # Sadly, the way data are stored depends on what FFT routine # one is using. We cannot deal with scipy's. if vals.dtype.kind == 'f': raise TypeError("Can no longer deal with scipy's format " "for storing FTs of real data.") if fedge_at_top: # take complex conjugate to ensure by-channel de-dispersion is # applied correctly. # This needs to be done for ARO data, since we are in 2nd Nyquist # zone; not clear it is needed for other telescopes. np.conj(vals, out=vals) # Now we coherently dedisperse, either all of it or by channel. if need_fine_channels:
def AF_MUSIC2D(self, focusing_freq=-1, signals=1, xrange=(-50, 50), yrange=(-50, 50), xstep=False, ystep=False, colormap="gist_heat", shw=True, block_run=True, no_fig=False, chunks=10): """Displays a heatmap for visual inspection of AF-MUSIC-based location estimation. Generates a grid of provided dimension/resolution, and evaluates the AF-MUSIC algorithm at each point on the grid. Arguments: focusing_freq (float): The frequency (in Hz) at which to perform the calculation. If <0, will default to 0.9*(spatial Nyquist frequency) signals (int): The number of signals to locate. xrange (float, float): The lower and upper bound in the x-direction. yrange (float, float): The lower and upper bound in the y-direction. xstep (float): If given, determines the size of the steps in the x-direction. Otherwise defaults to 1000 steps. ystep (float): If given, determines the size of the steps in the y-direction. Otherwise defaults to 1000 steps. colormap (str): The colour map for the heatmap. See https://matplotlib.org/examples/color/colormaps_reference.html shw (bool): If False, return the axis object rather than display. block_run (bool): Pause execution of the file while the figure is open? Set to True for running in the command-line. no_fig (bool): If True, return the heatmap grid rather than plot it. Returns: np.array: Returns EITHER the current (filled) heatmap domain if no_fig == True, OR a handle to the displayed figure. """ raise NotImplementedError self.dataFFT = fft_pack.rfft(self.data, axis=0).T self.numbins = self.dataFFT.shape[1] pos = fft_pack.rfftfreq(self.data.shape[0]) * self.sample_rate if focusing_freq < 0: focusing_freq = self.spatial_nyquist_freq * 0.45 # focusing_freq = pos[np.argmax(self.dataFFT[0, :])] else: focusing_freq = 1000 idxs = np.array(np.arange(pos.shape[0])) refidx = np.argmin(abs(pos - focusing_freq)) Rcoh = np.zeros((self.dataFFT.shape[0], self.dataFFT.shape[0]), dtype='complex128') ul, self.Uf0 = la.eigh( dot(self.dataFFT[:, refidx:refidx + 1], self.dataFFT[:, refidx:refidx + 1].conj().T) / self.dataFFT.shape[0]) ul = ul.real self.Uf0 = self.Uf0[:, argsort(abs(ul))[::-1]] pool = Pool(processes=7) res = pool.map(self._UfitoRyy_, idxs) pool.close() for r in res: Rcoh += r if xstep and ystep: xdom = np.linspace(start=xrange[0], stop=xrange[1], num=int((xrange[1] - xrange[0]) // xstep)) ydom = np.linspace(start=yrange[0], stop=yrange[1], num=int((yrange[1] - yrange[0]) // ystep)) else: xdom = np.linspace(start=xrange[0], stop=xrange[1], num=1000) ydom = np.linspace(start=yrange[0], stop=yrange[1], num=1000) self._hm_domain_ = np.zeros((len(ydom), len(xdom))) xdom, ydom = np.meshgrid(xdom, ydom) self._hm_domain_ = self._MUSIC2D_((pos[refidx], refidx), xdom, ydom, numsignals=signals, SI=Rcoh) if no_fig: return self._hm_domain_ f = plt.figure() plt.imshow(self._hm_domain_, cmap=colormap, interpolation='none', origin='lower', extent=[xrange[0], xrange[1], yrange[0], yrange[1]]) plt.colorbar() plt.xlabel("Horiz. Dist. from Center of Array [m]") plt.ylabel("Vert. Dist. from Center of Array [m]") if shw: plt.show(block=block_run) return else: return f
def stft(x, binsize=1024, overlap_factor=.5, hopsize=None, window='hamming', **kwargs): """ STFT, Short-Term Fourier Transform. Parameters: ----------- x: 2d-ndarray, (n_ch, n_samp) Multi-channel signal. binsize: int Window size for processing FFT on. overlap_factor: float The percentage of overlapping between consecutive windows. hopsize: int The sample size required to jump to the next row. window: str (default: 'hamming') The window used to create overlapping slices of the time domain signal. kwargs: The key-word arguments for rfft. Return: ------- X: ndarray, (n_ch, n_win, binsize // 2) """ # Sanity check if not np.isrealobj(x): raise ValueError("x is not a real valued array.") if x.ndim > 2: raise ValueError( "The dimension of the ndarray must be less than or equal to 2!") x = np.atleast_2d(x) n_ch, n_samp = x.shape if hopsize is not None: _overlap_factor = hopsize / binsize if overlap_factor != _overlap_factor: raise ValueError( "The 'overlap_factor' calculated from hopsize/binsize does not match the input." ) if overlap_factor in [0, 1] and binsize != hopsize != n_samp: binsize = n_samp hopsize = 0 if overlap_factor else binsize else: hopsize = int(binsize * (1 - overlap_factor)) if hopsize is None else hopsize if hopsize: n_win = n_samp / hopsize n_win = int(n_win + 1) if overlap_factor else int(n_win) length = hopsize else: n_win = 1 length = binsize if overlap_factor in [0, 1]: _x = np.zeros((n_ch, n_win * length)) else: _x = np.zeros((n_ch, (n_win + 1) * length)) _x[:, binsize // 2:binsize // 2 + n_samp] = x # Process win_ = get_window(window, binsize) frames = stride_tricks.as_strided(_x, shape=(n_ch, n_win, binsize), strides=(_x.strides[0], _x.strides[1] * hopsize, _x.strides[1])) X = fft.rfft(frames * win_, **kwargs) return X
def toFrequencyResponse(data): dat = rfft(data, planner_effort="FFTW_ESTIMATE") return 20 * numpy.log10(numpy.abs(dat))