Пример #1
0
def fourier(B, dx, dt):
    from scipy.fft import rfft2, rfftfreq
    Bwk = rfft2(B)
    w = rfftfreq(B.shape[1], d=dt)
    k = rfftfreq(B.shape[0], d=dx)
    k = k * 2 * np.pi
    w = w * 2 * np.pi
    return Bwk, w, k
Пример #2
0
def inverse_psf_rfft(psf, shape=None, l=20, mode='laplacian'):
    """
    Computes the real FFT of a regularized inversed 2D PSF (or projected 3D)
    This follows the convention of fft.rfft: only half the spectrum is computed.

    Parameters
    ----------
    psf : array [ZXY] or [XY]
        The 2D PSF (if 3D, will be projected on Z axis).
    shape : tuple (int, int), optional
        Shape of the full-sized desired PSF
        (if None, will be the same as the PSF), by default None.
    l : int, optional
        Regularization lambda, by default 20
    mode : str, optional
        The regularizer used, by default laplacian.
        One of: ['laplacian', 'constant']

    Returns
    -------
    array [XY]
        The real FFT of the inverse PSF.

    Raises
    ------
    ValueError
        If the PSF has incorrect number of dimensions.
        If the regularizer is unknown.
    """

    if psf.ndim == 3:
        psf = psf.sum(0)
    elif psf.ndim != 2:
        raise ValueError("Invalid dimensions for PSF: {}".format(psf.ndim))

    if shape is None:
        shape = psf.shape

    psf_fft = fft.rfft2(psf, s=shape)

    # We need to shift the PSF so that the center is located at the (0, 0) pixel
    # otherwise deconvolving will shift every pixel
    freq = fft.rfftfreq(shape[1])
    phase_shift = freq * 2 * np.pi * ((psf.shape[1] - 1) // 2)
    psf_fft *= np.exp(1j * phase_shift[None, :])

    freq = fft.fftfreq(shape[0])
    phase_shift = freq * 2 * np.pi * ((psf.shape[0] - 1) // 2)
    psf_fft *= np.exp(1j * phase_shift[:, None])

    if mode == 'laplacian':
        # Laplacian regularization filter to avoid NaN
        filt = [[0, -0.25, 0], [-0.25, 1, -0.25], [0, -0.25, 0]]
        reg = np.abs(fft.rfft2(filt, s=shape))**2
    elif mode == 'constant':
        reg = 1
    else:
        raise ValueError('Unknown regularizer: {}'.format(mode))

    return psf_fft.conjugate() / (np.abs(psf_fft)**2 + l * reg)
Пример #3
0
def time_fourier(
    x,
    *ys,
    sampleFactor=1,
    interpKind='linear',
    minFreq='auto',
    maxFreq='auto',
    minAmps=None,
    maxAmps=None,
):
    if minAmps is None: minAmps = [None for y in ys]
    if maxAmps is None: maxAmps = [None for y in ys]
    x, *ys = time_smooth(x, *ys, sampleFactor=sampleFactor, kind=interpKind)
    N = len(x)
    T = np.diff(x).mean()
    freqs = rfftfreq(N, T)[:N // 2]
    if minFreq is None: minFreq = min(freqs)
    elif minFreq == 'auto': minFreq = (1 / np.ptp(x)) * 10
    if maxFreq is None: maxFreq = max(freqs)
    elif maxFreq == 'auto': maxFreq = (1 / T) / 10
    mask = np.logical_and(freqs >= minFreq, freqs <= maxFreq)
    freqs = freqs[mask]
    w = blackman(N)
    amps = []
    for y, minAmp, maxAmp in zip(ys, minAmps, maxAmps):
        y = y - y.mean()
        amp = np.abs(rfft(y * w))[:N // 2]
        if not minAmp is None: amp = np.where(amp < minAmp, 0, amp)
        if not maxAmp is None: amp = np.where(amp > maxAmp, maxAmp, amp)
        amps.append(amp[mask])
    return (freqs, *amps)
Пример #4
0
    def _set_freqs(self):

        # Set freqs indexes
        if self._sides == "onesided":
            self._freqs = rfftfreq(self._nfft, 1 / self._fs)
        else:
            self._freqs = fftfreq(self._nfft, 1 / self._fs)
Пример #5
0
def spectral_plots(signal, sample_rate, pitch=None):
    N = len(signal)
    X = rfft(signal, N)
    Xmag = np.abs(X)
    freq = rfftfreq(N, 1 / sample_rate)

    fig, ax = plt.subplots(3, 1, sharex=True)
    fig.set_figheight(5)
    if pitch:
        for ax_ in ax:
            ax_.axvline(pitch, linestyle='--', color='black')

    ax[0].plot(freq, Xmag)
    ax[0].yaxis.set_ticklabels([])
    ax[0].set_ylabel('spectrum')

    ax[1].plot(freq, np.abs(func['ACF'](Xmag)))
    ax[1].yaxis.set_ticklabels([])
    ax[1].set_ylabel('ACF')

    Nh = 10  # for example
    hps = 20 * np.log10(
        [np.sum(Xmag[k:Nh * k:k]) for k in range(1, len(freq))])
    hss = np.array(
        [20 * np.sum(np.log(Xmag[k:Nh * k:k])) for k in range(1, len(freq))])
    ax[2].plot(freq[1:], normalize(hps), label='product')
    ax[2].plot(freq[1:], normalize(hss), label='sum')
    ax[2].legend()
    ax[2].yaxis.set_ticklabels([])
    ax[2].set_ylabel('harmonic sum/product')

    ax[-1].set_xlim(0, 5000)
    ax[-1].set_xlabel('frequency (Hz)')

    plt.show()
Пример #6
0
def fft_plot(yf: np.ndarray, fname: str):
    '''
    Plots the FFT

    params:
    ---
    yf (np.ndarray): input data to plot
    fname (str): save file name
    '''
    N = int((config.SAMPLE_RATE / config.RESAMPLE_RATE) * config.DURATION)
    xf = rfftfreq(N - 1, 1 / int(config.SAMPLE_RATE / config.RESAMPLE_RATE))

    _, axs = plt.subplots(nrows=1, figsize=(11, 9))
    plt.rcParams['font.size'] = '14'

    for label in (axs.get_xticklabels() + axs.get_yticklabels()):
        label.set_fontsize(14)

    plt.plot(xf, yf)
    axs.set_title('Frequency spectra')
    axs.set_ylabel('Signal strength', fontsize=14)
    axs.set_xlabel('Frequency (Hz)', fontsize=14)

    file_location = eda_config.OUTPUT_DATA_DIR / Path(f'{fname}.png')
    plt.savefig(file_location)
    def actualizarGraficoLectura(self):
        #preparar datos a plotear

        self.ploteando = True

        tamano = len(self.tarea.datosLeidos[0])
        if tamano > self.maximoPuntos:
            liminferior = tamano - self.maximoPuntos - 1
        elif tamano:
            liminferior = 0
        else:
            self.ploteando = False
            return

        datos = []

        for c in enumerate(self.tarea.datosLeidos):
            datos.append(self.tarea.datosLeidos[c[0]][liminferior:])

        for p in enumerate(self.lineas):
            # print(p)
            p[1].setData(datos[0], datos[self.indicesPlot[p[0]] + 1])
            yf = rfft(datos[self.indicesPlot[p[0]] + 1])
            xf = rfftfreq(len(datos[0]), 1 / self.tarea.freq)
            self.lineasFreq[p[0]].setData(xf, np.abs(yf))
        #plotear ffts

        self.ploteando = False
Пример #8
0
def detect_coughs(
    file='sounds/samples/vi95kMQ65UeU7K1wae12D1GUeXd2/sample-1613658921823.m4a'
):
    # Replace the below random code with something meaningful which
    # generates a one-column dataframe with a column named "peak_start"
    y, sr = librosa.load(file)  # sr is the sampling rate
    N = y.shape[0]  # N is number of samples

    yf = rfft(y)
    xf = rfftfreq(N, 1 / sr)  # Going to frequency domain

    points_per_freq = len(xf1) / (sr / 2)
    target_idx_100 = int(points_per_freq * 100)
    target_idx_2000 = int(points_per_freq * 2000)

    # Removing all frequencies except 100-2000 Hz, as this is the typical range of frequencies for a cough from an adult.
    # Reference: https://pubmed.ncbi.nlm.nih.gov/12666872/
    yf[:target_idx_100 + 1] = 0
    yf[target_idx_2000 - 1:] = 0

    new_sig = irfft(yf)  # Going back to time domain with filtered signal

    peaks_array = find_peaks(
        new_sig, prominence=0.02
    )[0]  #Finding start of peaks in filtered signal, should correspond to coughs
    peaks = peaks_array / sr  # The time instant of starting of peak is arrived at by dividing by sampling rate
    out = pd.DataFrame({'peak_start': peaks})
    return (out)
Пример #9
0
def stftfreq(wsize, sfreq=None):  # noqa: D401
    """Compute frequencies of stft transformation.

    Parameters
    ----------
    wsize : int
        Size of stft window.
    sfreq : float
        Sampling frequency. If None the frequencies are given between 0 and pi
        otherwise it's given in Hz.

    Returns
    -------
    freqs : array
        The positive frequencies returned by stft.

    See Also
    --------
    stft
    istft
    """
    from scipy.fft import rfftfreq
    freqs = rfftfreq(wsize)
    if sfreq is not None:
        freqs *= float(sfreq)
    return freqs
Пример #10
0
 def _preprocess_spectrum(self, spectrum, low_cutoff_res, high_cutoff_res):
     """Cuts off low and high frequencies and then subtracts the background by
     calculating a lower envelope to the min peaks (ctf zero crossings).
     Also finds an upper envelope to be used as a damping function for computing
     forward models.
     """
     low_cutoff_freq = 1 / low_cutoff_res
     high_cutoff_freq = 1 / high_cutoff_res
     freqencies = fft.rfftfreq(n=self.full_spectrum.shape[0],
                               d=self.pixelsize)
     # dft indices of low and high cutoffs
     self._low_idx = np.argmax(freqencies > low_cutoff_freq)
     self._high_idx = np.argmax(freqencies > high_cutoff_freq)
     # get envelopes
     bottom_envelope, self._upper_envelope = self._get_envelopes(
         spectrum, self._low_idx, self._high_idx)
     # cut off high frequencies
     spectrum = spectrum[:, :self._high_idx]
     spectrum = np.vstack(
         (spectrum[:self._high_idx, :], spectrum[-self._high_idx:, :]))
     spectrum = fft.fftshift(spectrum, axes=0)
     # subtract bottom envelope
     x = range(spectrum.shape[1])
     y = range(-spectrum.shape[0] // 2, spectrum.shape[0] // 2)
     X, Y = np.meshgrid(x, y)
     r = np.sqrt(X**2 + Y**2)
     spectrum -= bottom_envelope(r - self._low_idx)
     # zero out distances not between low_idx and high_idx
     w = np.where((r < self._low_idx) | (r > self._high_idx))
     spectrum[w[0], w[1]] = 0
     return spectrum
Пример #11
0
 def _ctf_array(self, z1, z2, major_semiaxis_angle, phase_shift):
     """Returns a 2D array of CTF values in the same shape as the reduced spectrum"""
     # calculate defocus matrix
     minor_semiaxis_angle = 90 + major_semiaxis_angle
     minor_semiaxis = np.array([
         np.cos(minor_semiaxis_angle * np.pi / 180),
         np.sin(minor_semiaxis_angle * np.pi / 180),
     ]).reshape(2, 1)
     semiaxes, _ = np.linalg.qr(np.hstack((minor_semiaxis, np.identity(2))))
     defocus_matrix = semiaxes @ [[z1, 0], [0, z2]] @ semiaxes.transpose()
     # vectorize ctf calculation
     kx = fft.rfftfreq(n=self.full_spectrum.shape[0], d=self.pixelsize)
     kx = kx[:self._high_idx]
     ky = fft.fftfreq(n=self.full_spectrum.shape[0], d=self.pixelsize)
     ky = np.hstack((ky[:self._high_idx], ky[-self._high_idx:]))
     ky = fft.fftshift(ky)
     KX, KY = np.meshgrid(kx, ky)
     chi_args = (
         defocus_matrix,
         KX,
         KY,
         self.electron_wavelength,
         self.spherical_abberation,
         phase_shift,
     )
     return ctf(self.amplitude_contrast, chi_args)
    def binned_fft(self,
                   data: np.ndarray,
                   target_sample_rate: int,
                   original_sample_rate: int = 48000) -> np.ndarray:

        # # Get the "normalized" FFT based on the sample rates

        # " The height is a reflection of power density, so if you double the sampling frequency,
        # and hence half the width of each frequency bin, you'll double the amplitude of the FFT result."
        # >> https://wiki.analytica.com/FFT
        #
        # 2^(new_sample_rate/original_sample_rate) = power gain
        # Divide by that but offset by 1 since if new fs = old fs we multiply by 1/2^0 = 1
        #
        try:
            raw_fft = self.fft(data) * (2**math.log2(
                original_sample_rate / target_sample_rate))
        except TypeError as e:
            print(e)
            sys.exit()

        # raw_fft = self.fft(data)

        # # TODO: wont work for old fs and new fs equal
        # if original_sample_rate != target_sample_rate:
        #     raw_fft *= (math.log10(original_sample_rate / target_sample_rate) / math.log10(2))

        # # Get the frequencies that FFT represent based on the sample rate

        # Get the frequencies that the indexes determine
        fftf = rfftfreq(raw_fft.shape[0], 1 / target_sample_rate)

        # # Return pairs of [[freq], [fft]] array
        return np.array([fftf, raw_fft], dtype=object)
Пример #13
0
    def spectrum_contour(self,
                         comp,
                         axis_vals,
                         axis_mode='half_channel',
                         fig=None,
                         ax=None,
                         pcolor_kw=None,
                         **kwargs):
        if not comp in ('x', 'z'):
            raise ValueError(" Variable `comp' must eiher be 'x' or 'z'\n")

        axis_vals = misc_utils.check_list_vals(axis_vals)
        y_index_axis_vals = indexing.y_coord_index_norm(
            self._avg_data, axis_vals, None, axis_mode)
        Ruu_all = self.autocorrDF[comp]  #[:,axis_vals,:]
        shape = Ruu_all.shape
        Ruu = np.zeros((shape[0], len(axis_vals), shape[2]))
        for i, vals in zip(range(shape[2]), y_index_axis_vals):
            Ruu[:, :, i] = Ruu_all[:, vals, i]

        kwargs = cplt.update_subplots_kw(kwargs,
                                         figsize=[10, 4 * len(axis_vals)])
        fig, ax = cplt.create_fig_ax_without_squeeze(len(axis_vals),
                                                     fig=fig,
                                                     ax=ax,
                                                     **kwargs)

        coord = self._meta_data.CoordDF[comp].copy()[:shape[0]]
        x_axis = self._avg_data._return_xaxis()

        pcolor_kw = cplt.update_pcolor_kw(pcolor_kw)

        for i in range(len(axis_vals)):
            wavenumber_spectra = np.zeros((int(0.5 * shape[0]) + 1, shape[2]),
                                          dtype=np.complex128)
            for j in range(shape[2]):
                wavenumber_spectra[:, j] = fft.rfft(Ruu[:, i, j])
            comp_size = shape[0]
            wavenumber_comp = 2 * np.pi * fft.rfftfreq(comp_size,
                                                       coord[1] - coord[0])

            X, Y = np.meshgrid(x_axis, wavenumber_comp)
            ax[i] = ax[i].pcolormesh(X, Y, np.abs(wavenumber_spectra),
                                     **pcolor_kw)

            ax[i].axes.set_ylabel(r"$\kappa_%s$" % comp)

            title = r"$%s=%.3g$"%("y" if axis_mode=='half_channel' \
                        else r"\delta_u" if axis_mode=='disp_thickness' \
                        else r"\theta" if axis_mode=='mom_thickness' else "y^+", axis_vals[i] )

            ax[i].axes.set_ylim(
                [np.amin(wavenumber_comp[1:]),
                 np.amax(wavenumber_comp)])
            ax[i].axes.set_title(title)  # ,fontsize=15,loc='left')

            fig.colorbar(ax[i], ax=ax[i].axes)

        return fig, ax
def calculate_peak(waves, chunksize, sampling_rate, start, cycles):
    yf = rfft(waves)
    xf = rfftfreq(waves.size, 1 / sampling_rate)

    peak = np.where(np.abs(yf) == np.abs(yf).max())[0][0]
    peak = round((peak / ((chunksize) / sampling_rate)), 2)

    return peak
Пример #15
0
 def fourier_transform(self,df, name_column, show = False):
     myarray = np.asarray((df[name_column]))
     N = len(myarray)
     yf = rfft(myarray)
     xf = rfftfreq(N, 1 / analyzer.simple_rate)
     if (show == True):
         plt.plot(xf, np.abs(yf))
         plt.show()
     return yf[1]
def FourierTransformPower(Powers, Times):
    # Do FFT (real) on the input powers
    # Returns the frequency values and the corresponding amplitude
    FFTPowers = fft.rfft(Powers)
    nPoints = len(Times)
    SampleSpacing = (Times.max() - Times.min()) / nPoints
    FFTFreqs = fft.rfftfreq(nPoints, d=SampleSpacing)
    FFTPowers = numpy.abs(FFTPowers)
    return FFTFreqs, FFTPowers
Пример #17
0
def fourier_transform(arr, name):
    arr = arr - np.mean(arr)
    N = len(arr)

    yf = rfft(arr)
    xf = rfftfreq(N, 1)

    plt.plot(xf, np.abs(yf), label='{}'.format(name))

    return yf, xf
Пример #18
0
def makeFilter(shape: List[int], alpha: float, dtype=float) -> np.ndarray:
    assert 1 <= len(shape) <= 2, "shape must be one or two elements"
    if len(shape) == 1:
        shape = [shape[0], shape[0]]

    # Generate filter in the frequency domain
    fy = sf.fftfreq(shape[0])[:, np.newaxis].astype(dtype)
    fx = sf.rfftfreq(shape[1])[np.newaxis, :].astype(dtype)
    H2 = (fx**2 + fy**2)**(alpha / 2.0)

    return sf.fftshift(sf.irfft2(H2))
Пример #19
0
def plot_fourier(frame_rate, np_frames, output_file):
    """Plot Fourier Transformation of audio sample."""
    plt_fourier = pyplot
    n = len(np_frames)
    #norm_frames = np.int16((byte_frames / byte_frames.max()) * 32767)

    yf = rfft(np_frames)
    xf = rfftfreq(n, 1 / frame_rate)

    fig = plt_fourier.figure(num=None, figsize=(12, 7.5), dpi=100)
    plt_fourier.plot(xf, np.abs(yf))
    plt_fourier.savefig(output_file)
Пример #20
0
 def get_1d_average(self, spectrum, horizontal_res=50, sigma_ratio=1 / 60):
     """Returns a 1D signal of the vertical spectrum inside the cutoff range"""
     freqencies = fft.rfftfreq(n=self.full_spectrum.shape[0],
                               d=self.pixelsize)
     width = np.argmax(freqencies > 1 / horizontal_res)
     vertical_strip = spectrum[self._low_idx:self._high_idx, :width]
     vertical_1d = np.average(vertical_strip, axis=1)
     sigma = sigma_ratio * len(vertical_1d)
     vertical_1d = ndimage.gaussian_filter1d(vertical_1d,
                                             sigma=sigma,
                                             mode="nearest")
     return vertical_1d
Пример #21
0
        def calculate():
            self.sample_rate, self.audio = wavfile.read(self.audiofile)
            self.audio = np.transpose(self.audio)
            self.duration = len(self.audio[:][0]) / float(self.sample_rate)
            self.audio_fft = [None] * self.audio.ndim
            self.audio_fft[0] = rfft(self.audio[0])
            self.audio_fft[1] = rfft(self.audio[1])
            self.freq = rfftfreq(self.audio[0].size, 1. / self.sample_rate)

            print(
                f"Sample Rate: {self.sample_rate} with {self.audio.ndim} channels"
            )
Пример #22
0
def fft(x, fs):
    """
    FFT function

    :param x: input data for fft
    :param fs: sample frequency [Hz]
    :return: frequency [Hz], magnitude
    """

    n = len(x)
    y = np.abs(rfft(x))
    f = rfftfreq(n, 1/fs)
    return f, y
Пример #23
0
 def _get_approx_defocus(self, first_zero_crossing_idx):
     # get approximate defocus from first zero crossing
     freqencies = fft.rfftfreq(n=self.full_spectrum.shape[0],
                               d=self.pixelsize)
     k_first_zero_crossing = freqencies[self._low_idx +
                                        first_zero_crossing_idx]
     chi_first_zero_crossing = -0.5
     approximate_defocus = (
         chi_first_zero_crossing - 10 *
         (1 / 4) * self.spherical_abberation * self.electron_wavelength**3 *
         k_first_zero_crossing**4) * (
             -2 /
             (100 * self.electron_wavelength * k_first_zero_crossing**2))
     return approximate_defocus
Пример #24
0
def spectrum(a, delta=1, **kwargs):
    """
    Return frequencies, amplitude and phase of FFT.
    """
    nfreq = kwargs.get('nfreq')
    if nfreq is None:
        nfreq = next_fast_len(a.size)
    spectrum = rfft(a, nfreq)
    freqs = rfftfreq(n=nfreq, d=delta)

    am = np.abs(spectrum)
    ph = np.angle(spectrum)

    return freqs, am, ph
Пример #25
0
def analyze_audio(audio):
    # Just extract one column (mono) since it's stereo
    audio = audio[:,0]
    yf = rfft(audio)
    # Return in abs because we want the module from a complex number, despite having only real part (because of the rrft)
    yf_s = Series(abs(yf))
    
    # The band where we want to detect our signal 17-21kHz
    yf_s = yf_s[17000:21000]
    print(yf_s.nlargest(20))


    # Show on graph the correspondant point
    xf = rfftfreq(POINTS, 1 / FS)
    plt.plot(xf, np.abs(yf))
    plt.show()
Пример #26
0
def fourier_tf(data, fs=128, viz=False, tmp_signal=None, tmp_channel=None):

    if isinstance(data, pd.DataFrame):
        tmp = np.absolute(
            rfftn(data.values.reshape(data.shape[0], 14, 512), axes=2))

    else:

        tmp = np.absolute(rfftn(data.reshape(data.shape[0], 14, 512), axes=2))

    fft_freq = rfftfreq(512, 1.0 / fs)

    if viz == True:
        plt.plot(fft_freq, t[tmp_signal, tmp_channel, :])

    return tmp
Пример #27
0
def Peak_amplitude(a, cutoff):
  ################################################################
  # calculates peak amplitude from a signal and a frequency band #
  #                                                              #
  # a : a signal (time series)                                   #
  # cutoff : frequency band                                      #
  ################################################################
  fs = 20    #Hertz
  yf = rfft(a)
  #power spectra
  ps = 2*(np.abs(yf)**2.0)
  M = len(ps)
  xf = rfftfreq(M, 1/fs)
  idx = np.logical_and(xf >= cutoff[0], xf <= cutoff[1])
  cutoff_idx = np.where(idx)[0]
  #peak amplitude
  pa = max(ps[cutoff_idx]/max(ps))
  return pa
Пример #28
0
def _mt_spectra(x, dpss, sfreq, n_fft=None):
    """Compute tapered spectra.

    Parameters
    ----------
    x : array, shape=(..., n_times)
        Input signal
    dpss : array, shape=(n_tapers, n_times)
        The tapers
    sfreq : float
        The sampling frequency
    n_fft : int | None
        Length of the FFT. If None, the number of samples in the input signal
        will be used.

    Returns
    -------
    x_mt : array, shape=(..., n_tapers, n_times)
        The tapered spectra
    freqs : array
        The frequency points in Hz of the spectra
    """
    from scipy.fft import rfft, rfftfreq
    if n_fft is None:
        n_fft = x.shape[-1]

    # remove mean (do not use in-place subtraction as it may modify input x)
    x = x - np.mean(x, axis=-1, keepdims=True)

    # only keep positive frequencies
    freqs = rfftfreq(n_fft, 1. / sfreq)

    # The following is equivalent to this, but uses less memory:
    # x_mt = fftpack.fft(x[:, np.newaxis, :] * dpss, n=n_fft)
    n_tapers = dpss.shape[0] if dpss.ndim > 1 else 1
    x_mt = np.zeros(x.shape[:-1] + (n_tapers, len(freqs)),
                    dtype=np.complex128)
    for idx, sig in enumerate(x):
        x_mt[idx] = rfft(sig[..., np.newaxis, :] * dpss, n=n_fft)
    # Adjust DC and maybe Nyquist, depending on one-sided transform
    x_mt[..., 0] /= np.sqrt(2.)
    if x.shape[1] % 2 == 0:
        x_mt[..., -1] /= np.sqrt(2.)
    return x_mt, freqs
Пример #29
0
    def run(self, win_data: WindowedData) -> SpectraData:
        """
        Perform the FFT

        Data is padded to the next fast length before performing the FFT to
        speed up processing. Therefore, the output length may not be as
        expected.

        Parameters
        ----------
        win_data : WindowedData
            The input windowed data

        Returns
        -------
        SpectraData
            The Fourier transformed output
        """
        from scipy.fft import next_fast_len, rfftfreq

        metadata_dict = win_data.metadata.dict()
        data = {}
        spectra_levels_metadata = []
        messages = []
        logger.info("Performing fourier transforms of windowed decimated data")
        for ilevel in range(win_data.metadata.n_levels):
            logger.info(f"Transforming level {ilevel}")
            level_metadata = win_data.metadata.levels_metadata[ilevel]
            win_size = level_metadata.win_size
            n_transform = next_fast_len(win_size, real=True)
            logger.debug(
                f"Padding size {win_size} to next fast len {n_transform}")
            freqs = rfftfreq(n=n_transform, d=1.0 / level_metadata.fs).tolist()
            data[ilevel] = self._get_level_data(level_metadata,
                                                win_data.get_level(ilevel),
                                                n_transform)
            spectra_levels_metadata.append(
                self._get_level_metadata(level_metadata, freqs))
            messages.append(f"Calculated spectra for level {ilevel}")
        metadata = self._get_metadata(metadata_dict, spectra_levels_metadata)
        metadata.history.add_record(self._get_record(messages))
        logger.info("Fourier transforms completed")
        return SpectraData(metadata, data)
Пример #30
0
def texshadeFFT(x: np.ndarray, alpha: float) -> np.ndarray:
    """FFT-based texture shading elevation

  Given an array `x` of elevation data and an `alpha` > 0, apply the
  texture-shading algorithm using the full (real-only) FFT: the entire `x` array
  will be FFT'd.

  `alpha` is the shading detail factor, i.e., the power of the
  fractional-Laplacian operator. `alpha=0` means no detail (output is the
  input). `alpha=2.0` is the full (non-fractional) Laplacian operator and is
  probably too high. `alpha <= 1.0` seem aesthetically pleasing.

  Returns an array the same dimensions as `x` that contains the texture-shaded
  version of the input array.

  If `x` is memory-mapped and/or your system doesn't have 5x `x`'s memory
  available, consider using `texshade.texshadeSpatial`, which implements a
  low-memory version of the algorithm by approximating the frequency response of
  the fractional-Laplacian filter with a finite impulse response filter applied
  in the spatial-domain.

  Implementation note: this function uses Scipy's FFTPACK routines (in
  `scipy.fftpack`) instead of Numpy's FFT (`numpy.fft`) because the former can
  return single-precision float32. In newer versions of Numpy/Scipy, this
  advantage may have evaporated [1], [2].

  [1] https://github.com/numpy/numpy/issues/6012
  [2] https://github.com/scipy/scipy/issues/2487
  """
    Nyx = [nextprod([2, 3, 5, 7], x) for x in x.shape]

    # Generate filter in the frequency domain
    fy = sf.fftfreq(Nyx[0])[:, np.newaxis].astype(x.dtype)
    fx = sf.rfftfreq(Nyx[1])[np.newaxis, :].astype(x.dtype)
    H2 = (fx**2 + fy**2)**(alpha / 2.0)

    # Compute the FFT of the input and apply the filter
    xr = sf.rfft2(x, s=Nyx) * H2
    H2 = None  # potentially trigger GC here to reclaim H2's memory
    xr = sf.irfft2(xr)
    # Return the same size as input
    return xr[:x.shape[0], :x.shape[1]]