Example #1
0
    def test_boxcar(self):
        w = windows.get_window('boxcar', 12)
        assert_array_equal(w, np.ones_like(w))

        # window is a tuple of len 1
        w = windows.get_window(('boxcar',), 16)
        assert_array_equal(w, np.ones_like(w))
Example #2
0
    def test_boxcar(self):
        w = windows.get_window('boxcar', 12)
        assert_array_equal(w, np.ones_like(w))

        # window is a tuple of len 1
        w = windows.get_window(('boxcar',), 16)
        assert_array_equal(w, np.ones_like(w))
def windowff(nslices,kind=None):
   """
      Returns a window function to enforce quasi-preiodicity
      on an aperiodic signal. Window options are:
      BlackmanHarris, Hanning, Blackman, FlatTop, Welch, Tukey
   """
   import scipy.signal.windows as w
   if kind is None: 
      return np.ones(nslices)
   elif kind.lower() == 'tukey':
      return w.get_window((kind.lower(),0.1),nslices)
   else:
      return w.get_window(kind.lower(),nslices)
Example #4
0
    def dziel_na_segmenty(self, window, nperseg, input_length):

        if nperseg > input_length:
            nperseg = input_length
        win = get_window(window, nperseg)

        return win, nperseg
Example #5
0
def window_filter(curve: 'Curve',
                  window_size: int,
                  window_type: ty.Union[str, abc.Callable] = 'hann',
                  mode: str = 'reflect',
                  cval: float = 0.0) -> np.ndarray:
    """Smoothes a curve using moving average filter with the given window [1]_

    References
    ----------
    .. [1] `The windows in scipy
           <https://docs.scipy.org/doc/scipy/reference/signal.windows.html#module-scipy.signal.windows>`_

    """

    if callable(window_type):
        try:
            window = window_type(window_size)
        except Exception as err:
            raise ValueError(
                f'Cannot create the window using {window_type}: {err}'
            ) from err
    else:
        window = windows.get_window(window_type, window_size, fftbins=False)

    window /= window.sum()

    return ndimage.convolve1d(
        curve.data,
        weights=window,
        mode=mode,
        cval=cval,
        axis=0,
    )
Example #6
0
def test_rollingmean_detrend(series):
    x = series(np.arange(12 * 365.25), "tas")
    det = RollingMeanDetrend(group="time", win=29, min_periods=1)
    fx = det.fit(x)
    dx = fx.detrend(x)
    xt = fx.retrend(dx)

    np.testing.assert_array_almost_equal(dx.isel(time=slice(30, 3500)), 0)
    np.testing.assert_array_almost_equal(xt, x)

    # weights + grouping
    x = xr.DataArray(
        np.sin(2 * np.pi * np.arange(11 * 365) / 365),
        dims=("time", ),
        coords={
            "time":
            xr.cftime_range("2010-01-01",
                            periods=11 * 365,
                            freq="D",
                            calendar="noleap")
        },
    )
    w = windows.get_window("triang", 11, False)
    det = RollingMeanDetrend(group=Grouper("time.dayofyear", window=3),
                             win=11,
                             weights=w)
    fx = det.fit(x)
    assert fx.ds.trend.notnull().sum() == 365
Example #7
0
    def test_basic(self):
        M = 100
        w = windows.kaiser_bessel_derived(M, beta=4.0)
        w2 = windows.get_window(('kaiser bessel derived', 4.0),
                                M,
                                fftbins=False)
        assert_allclose(w, w2)

        # Test for Princen-Bradley condition
        assert_allclose(w[:M // 2]**2 + w[-M // 2:]**2, 1.)

        # Test actual values from other implementations
        # M = 2:  sqrt(2) / 2
        # M = 4:  0.518562710536, 0.855039598640
        # M = 6:  0.436168993154, 0.707106781187, 0.899864772847
        # Ref:https://github.com/scipy/scipy/pull/4747#issuecomment-172849418
        assert_allclose(
            windows.kaiser_bessel_derived(2, beta=np.pi / 2)[:1],
            np.sqrt(2) / 2)

        assert_allclose(
            windows.kaiser_bessel_derived(4, beta=np.pi / 2)[:2],
            [0.518562710536, 0.855039598640])

        assert_allclose(
            windows.kaiser_bessel_derived(6, beta=np.pi / 2)[:3],
            [0.436168993154, 0.707106781187, 0.899864772847])
Example #8
0
    def test_array_as_window(self):
        # github issue 3603
        osfactor = 128
        sig = np.arange(128)

        win = windows.get_window(('kaiser', 8.0), osfactor // 2)
        with assert_raises(ValueError, match='must have the same length'):
            resample(sig, len(sig) * osfactor, window=win)
Example #9
0
 def __init__(self, window, source=None, **kw_get_win):
     if isinstance(window, str) and source:
         from scipy.signal.windows import get_window
         window = get_window(window, Nx=source.blocksize, **kw_get_win)
     else:
         from numpy import asarray
         window = asarray(window, dtype=float)
     self.window = window
Example #10
0
    def test_array_as_window(self):
        # github issue 3603
        osfactor = 128
        sig = np.arange(128)

        win = windows.get_window(('kaiser', 8.0), osfactor // 2)
        assert_raises(ValueError, resample,
                      (sig, len(sig) * osfactor), {'window': win})
Example #11
0
    def test_array_as_window(self):
        # github issue 3603
        osfactor = 128
        sig = np.arange(128)

        win = windows.get_window(('kaiser', 8.0), osfactor // 2)
        assert_raises(ValueError, resample,
                      (sig, len(sig) * osfactor), {'window': win})
Example #12
0
def compute_iq(spectra, fields_in_list, fields_out_list, window=None):
    """
    Computes the IQ data from the spectra through an inverse Fourier transform

    Parameters
    ----------
    spectra : Spectra radar object
        Object containing the spectra
    fields_in_list : list of str
        list of input spectra fields names
    fields_out_list : list of str
        list with the output IQ fields names obtained from the input fields
    window : string, tupple or None
        Parameters of the window used to obtain the spectra. The parameters
        are the ones corresponding to function
        scipy.signal.windows.get_window. If it is not None the inverse will be
        used to multiply the IQ data obtained by the IFFT

    Returns
    -------
    radar : IQ radar object
        radar object containing the IQ fields

    """
    radar = deepcopy(spectra)
    radar.fields = {}
    for field_name_in, field_name_out in zip(fields_in_list, fields_out_list):
        if field_name_out in ('IQ_hh_ADU', 'IQ_vv_ADU'):
            iq = np.ma.masked_all(
                (spectra.nrays, spectra.ngates, spectra.npulses_max),
                dtype=np.complex64)
            for ray, npuls in enumerate(spectra.npulses['data']):
                ray_data = spectra.fields[field_name_in]['data'][
                    ray, :, 0:npuls].filled(0.)
                iq[ray, :,
                   0:npuls] = np.fft.ifft(np.fft.ifftshift(ray_data, axes=-1),
                                          axis=-1) * npuls

                if window is not None:
                    wind = get_window(window, npuls)
                    wind = wind / np.sqrt(np.sum(np.power(wind, 2.)) / npuls)
                    wind = np.broadcast_to(np.atleast_2d(wind),
                                           (spectra.ngates, npuls))
                    iq[ray, :, 0:npuls] /= wind
        else:
            iq = np.ma.masked_all(
                (spectra.nrays, spectra.ngates, spectra.npulses_max),
                dtype=np.float32)
            for ray, npuls in enumerate(spectra.npulses['data']):
                iq[ray, :, 0:npuls] = spectra.fields[field_name_in]['data'][
                    ray, :, 0:npuls] * npuls

        field_dict = get_metadata(field_name_out)
        field_dict['data'] = iq
        radar.fields.update({field_name_out: field_dict})

    return radar
def get_offset_features(features_matlab_path, songName, data_out,
                        target_smear_width, frame_len, context_len,
                        audio_offset, pitch_shift, boundaries):
    """Load feature data files of offset hop durations and append only the boundary-neighborhood frames to the dataset. To improve data class imbalance.
	
	Parameters:
	--
	songName (string): name of the data file
	data_out (dict): features for default hop duration
	target_smear_width (int): size of boundary-neighborhood (in seconds)
	frame_len (float): duration of a frame (in seconds)
	context_len (int): number of +-context frames
	audio_offset (float): offset value (in seconds) added to audio signal
	pitch_shift (int): pitch shift (in +/-semitones)
	boundaries (numpy array or list): set of boundary positions for the song (in seconds)
	
	Returns:
	--
	numpy ndarray: feature data for frames in the neighborhood
	"""

    data_offset = sio.loadmat(
        os.path.join(
            features_matlab_path,
            songName + '_' + str(audio_offset) + '_' + str(pitch_shift)))
    data_offset = make_feature_subsets(data_offset, context_len)

    for bound in boundaries:
        bound = int(bound.strip()) - audio_offset
        bound_frame = int(bound / frame_len)
        data_out['rhythm'] = np.vstack(
            (data_out['rhythm'],
             data_offset['rhythm'][bound_frame -
                                   int(target_smear_width / 2):bound_frame +
                                   int(target_smear_width / 2), :]))
        data_out['mfcc'] = np.vstack(
            (data_out['mfcc'],
             data_offset['mfcc'][bound_frame -
                                 int(target_smear_width / 2):bound_frame +
                                 int(target_smear_width / 2), :]))
        data_out['timbre'] = np.vstack(
            (data_out['timbre'],
             data_offset['timbre'][bound_frame -
                                   int(target_smear_width / 2):bound_frame +
                                   int(target_smear_width / 2), :]))
        data_out['all'] = np.vstack(
            (data_out['all'],
             data_offset['all'][bound_frame -
                                int(target_smear_width / 2):bound_frame +
                                int(target_smear_width / 2), :]))
        data_out['labels'] = np.vstack(
            (data_out['labels'],
             np.atleast_2d(windows.get_window('boxcar',
                                              target_smear_width)).T))

    return data_out
Example #14
0
File: iq.py Project: nal-li/pyart
def compute_spectra(radar, fields_in_list, fields_out_list, window=None):
    """
    Computes the spectra from IQ data through a Fourier transform

    Parameters
    ----------
    radar : radar object
        Object containing the IQ data
    fields_in_list : list of str
        list of input IQ data fields names
    fields_out_list : list of str
        list with the output spectra fields names obtained from the input
        fields
    window : string, tupple or None
        Parameters of the window used to obtain the spectra. The
        parameters are the ones corresponding to function
        scipy.signal.windows.get_window. If None no window will be used

    Returns
    -------
    spectra : spectra radar object
        radar object containing the spectra fields

    """
    spectra = deepcopy(radar)
    spectra.fields = {}
    for field_name_in, field_name_out in zip(fields_in_list, fields_out_list):
        if field_name_in in ('IQ_hh_ADU', 'IQ_vv_ADU'):
            spectrum = np.ma.masked_all(
                (radar.nrays, radar.ngates, radar.npulses_max),
                dtype=np.complex64)
            for ray, npuls in enumerate(radar.npulses['data']):
                wind_data = radar.fields[field_name_in]['data'][
                    ray, :, 0:npuls].filled(0.)
                if window is not None:
                    wind = get_window(window, npuls)
                    wind = wind/np.sqrt(np.sum(np.power(wind, 2.))/npuls)
                    wind = np.broadcast_to(
                        np.atleast_2d(wind), (radar.ngates, npuls))
                    wind_data *= wind

                spectrum[ray, :, 0:npuls] = np.fft.fftshift(
                    np.fft.fft(wind_data, axis=-1)/npuls, axes=-1)
        else:
            spectrum = np.ma.masked_all(
                (radar.nrays, radar.ngates, radar.npulses_max),
                dtype=np.float32)
            for ray, npuls in enumerate(radar.npulses['data']):
                spectrum[ray, :, 0:npuls] = radar.fields[field_name_in]['data'][
                    ray, :, 0:npuls]/npuls

        field_dict = get_metadata(field_name_out)
        field_dict['data'] = spectrum
        spectra.fields.update({field_name_out: field_dict})

    return spectra
Example #15
0
def filter_spectrum(intensity: float, window="hanning", sigma=0.5):
    """
    Apply a specified window function to a signal. The window functions are
    taken from the `signal.windows` module of SciPy, so check what is available
    before throwing it into this function.

    The window function is convolved with the signal by taking the time-
    domain product, and doing the inverse FFT to get the convolved spectrum
    back.

    The one exception is the gaussian window - if a user specifies "gaussian"
    for the window function, the actual window function applied here is a
    half gaussian, i.e. a 1D gaussian blur.

    Parameters
    ----------
    dataframe: pandas DataFrame
        Pandas dataframe containing the spectral information
    int_col: str, optional
        Column name to reference the signal
    window: str, optional
        Name of the window function as implemented in SciPy.
    sigma:

    Returns
    -------
    new_y: array_like
        Numpy 1D array containing the convolved signal
    """
    if window not in dir(windows):
        raise Exception("Specified window not available in SciPy.")
    data_length = len(intensity)
    if window == "gaussian":
        x = np.arange(data_length)
        window = lineshapes.gaussian(
            x, 1., 0., sigma
        )
    else:
        window = windows.get_window(window, data_length)
    fft_y = np.fft.fft(intensity)
    # Convolve the signal with the window function
    new_y = np.fft.ifft(
        window * fft_y
    )
    # Return only the real part of the FFT
    new_y = np.abs(new_y)
    return new_y
Example #16
0
    def forward(self,
                signal,
                ndct=512,
                numoverlap=256,
                window='boxcar',
                MFCC=False):
        signal = np.array(signal)
        if MFCC == False:
            win = get_window(window, ndct)
            listdct = []
            for i in range(0, signal.shape[0] - ndct, numoverlap):
                listdct.append(dct(signal[i:i + ndct] * win))
        else:
            listdct = mfcc(signal,
                           samplerate=512,
                           winlen=1,
                           winstep=0.5,
                           nfft=ndct)

        return np.array(listdct)
Example #17
0
def fourier_transform(dipole,
                      dt,
                      omega,
                      max_harmonic=30,
                      zero_padding_factor=10,
                      window='blackman',
                      t_phase=0,
                      time_axis=0):
    '''Handles the Fourier transform for HHG with all the extra subtleties.
			'dipole' is the time-dependent dipole moment (as a numpy array)
			'dt' is the time step
			'omega' is the reference frequency, to measure the harmonics against
			'max_harmonic' is the highest frequency harmonic to return
			'zero_padding_factor' is the factor by which the signal duration is increased via zero padding
			'window' is the name of the window to use (see scipy.signal for the options)
			't_phase' is the time relative to which the phase of the harmonics is measured. Typically the peak of the laser pulse.
			'axis' is used when 'dipole' is a multidimensional array to indicate which axis is time
		This function returns both the frequencies (in units of omega) and the (complex) hhg spectrum.
	'''
    #Total duration of the signal, after zero padding
    num_samples = dipole.shape[time_axis]
    t_max = zero_padding_factor * dt * num_samples
    #Spacing in frequency domain
    dw = 2 * np.pi / t_max
    #Frequencies in units of omega
    freq = np.arange(0, max_harmonic, dw / omega)
    #Calculate the dipole acceleration in time domain by taking the second derivative.
    dipole = np.gradient(np.gradient(dipole, dt, axis=time_axis),
                         dt,
                         axis=time_axis)
    #Multiply by the window function
    dipole *= get_window(window, num_samples)
    #Compute the Fourier transform with zero-padding
    spec = np.fft.rfft(dipole,
                       n=zero_padding_factor * num_samples,
                       axis=time_axis)
    #Shift the phase to be measured relative to 't_phase'.
    spec = multiply_along_axis(spec, np.exp(1j * t_phase * freq * omega))
    #Truncate the spectrum at the max harmonic, and also remove
    #the first point to avoid division by zero later
    return freq[1:], spec[1:len(freq)]
def save_feats_labels(songdata, audio_offsets=[], pitch_shifts=[]):
    """ Generate frame-level labels from GT boundary annotations (binary: 1 for boundary, 0 for non-boundary) and save the features and labels together
	
	Parameters:
	--
	_songdata (pd DataFrame): data from GT annotations csv file
	"""

    for songNo in range(songdata.shape[0]):
        boundaries = songdata['Boundaries'][songNo].split(',')

        data = sio.loadmat(
            os.path.join(features_matlab_path,
                         songdata['Concert name'][songNo]))
        data_out = utils.make_feature_subsets(data, context_len)

        n_frames = data_out['all'].shape[0]

        smear_win = windows.get_window('boxcar', target_smear_width)

        boundLabels = np.zeros(n_frames)
        for i_bound in range(1, len(boundaries)):
            boundary = int(boundaries[i_bound].strip())
            boundLabels[boundary // frame_len -
                        target_smear_width // 2:boundary // frame_len +
                        target_smear_width // 2] = smear_win
        data_out['labels'] = np.atleast_2d(boundLabels).T

        for pitch_shift in pitch_shifts:
            for audio_offset in audio_offsets:
                if (pitch_shift == 0) & (audio_offset == 0): continue
                data_out = utils.get_offset_features(
                    features_matlab_path, songdata['Concert name'][songNo],
                    data_out, target_smear_width, frame_len, context_len,
                    audio_offset, pitch_shift, boundaries)

        np.save(
            os.path.join(features_RF_path,
                         songdata['Concert name'][songNo] + '.npy'), data_out)
    return
Example #19
0
def main(fname, window):
    d = ""
    with open(fname, 'r') as f:
        d = f.read()

    header, data = ReadKeyValueDataFile(d, header_char='#', delim = ':')
    header = dict(header)
    x, y = get_adjusted_values(header, data)
    sampling_rate = x[1]-x[0]

    window_obj = windows.get_window(window, len(x))
    x = np.array(x*window_obj)
    f = scipy.fft.fft(y)
    sp = scipy.fft.fftshift(f)

    freq = scipy.fft.fftshift(scipy.fft.fftfreq(len(x), sampling_rate))

    plt.plot(freq/1e6, np.abs(sp))
    plt.xlabel("Frequency (MHz)")
    yunit = header['YUNIT'].strip("\"'")
    plt.ylabel("Amplitude ({})".format(yunit))
    plt.xlim([0, max(freq)/1e6])
    plt.yscale("log")
    plt.show()
Example #20
0
 def test_kaiser_float(self):
     win1 = windows.get_window(7.2, 64)
     win2 = windows.kaiser(64, 7.2, False)
     assert_allclose(win1, win2)
Example #21
0
 def CreateSegments(self, Window, nperseg, inputLenght):
     if nperseg > inputLenght:
         nperseg = inputLenght
     Window = get_window(Window, nperseg)
     return Window, nperseg
Example #22
0
Description:
Make sure the windowing effects are well-understood

Date:
3/9/2021

Author: Hunter Akins

Institution: Scripps Institution of Oceanography, UC San Diego
"""

from scipy.signal.windows import get_window

window_len = 1024
N_fft = 4 * 8096
hamm = get_window('hamming', window_len)

transfer_func = np.fft.fft(hamm)
freqs = np.fft.fftfreq(window_len, 1 / 1500)

transfer_func = np.square(abs(transfer_func))
transfer_func /= np.max(transfer_func)
trans_db = 10 * np.log10(transfer_func)

plt.figure()
plt.plot(freqs, trans_db)

hamm_pad = np.pad(hamm, (0, N_fft - window_len), 'constant')
transfer_func = np.fft.fft(hamm_pad)
freqs = np.fft.fftfreq(N_fft, 1 / 1500)
Example #23
0
 def test_cheb_even(self):
     with suppress_warnings() as sup:
         sup.filter(UserWarning, "This window is not suitable")
         w = windows.get_window(('chebwin', 40), 54, fftbins=False)
     assert_array_almost_equal(w, cheb_even_true, decimal=4)
def gen_dataset(features_out_path,
                texwin_len,
                context_len,
                targ_smear_width,
                audio_offsets=[0],
                pitch_shifts=[0]):

    smear_win = windows.get_window('boxcar', targ_smear_width)

    dataset_ids = {}
    dataset_labels = {}
    print('\n----------\n')
    for i_song in range(songdata.shape[0]):
        print('Generating data for song no %d' % i_song)
        dataset_ids[str(i_song)] = []
        dataset_labels[str(i_song)] = {}
        boundaries = songdata['Boundaries'][i_song].split(',')

        for i_pitch in pitch_shifts:
            if i_pitch == 0:
                filepath = os.path.join(
                    audio_dir, songdata['Concert name'][i_song] + '.wav')
            else:
                filepath = os.path.join(
                    audio_dir, 'pitch_shifted',
                    songdata['Concert name'][i_song] + '_' + str(i_pitch) +
                    '.wav')

            for offset in audio_offsets:
                audio, sr = librosa.load(filepath, sr=16000)
                audio = audio[int(sr * offset):]

                features = utils.get_frame_level_melgrams(audio)
                audio = []

                labels = np.zeros(features.shape[0])
                for boundary in boundaries:
                    boundary = int(boundary.strip()) - offset
                    labels[int(boundary / hop_len_sub) -
                           targ_smear_width // 2:int(boundary / hop_len_sub) +
                           targ_smear_width // 2] = smear_win

                dataset_ids_temp = []  #IDs of this version of the audio
                labels_temp = [
                ]  #retaining labels only in boundary neighborhood

                for i_frame in range(features.shape[0]):
                    ID = '%d_%d_%f_%d' % (i_song, i_pitch, offset, i_frame)
                    mel_specgram_frame = features[i_frame, ]

                    if (((i_pitch == 0) & (offset == 0)) |
                        (labels[i_frame] > 0)):
                        np.save(
                            os.path.join(features_out_path, ID),
                            np.reshape(mel_specgram_frame,
                                       (mel_specgram_frame.shape[0],
                                        mel_specgram_frame.shape[1], 1)))
                        dataset_ids_temp.append(ID)
                        labels_temp.append(labels[i_frame])

                dataset_ids[str(i_song)].extend(dataset_ids_temp)
                dataset_labels[str(i_song)].update(
                    dict(zip(dataset_ids_temp, labels_temp)))
    return dataset_ids, dataset_labels
Example #25
0
def test_get_pcen_settings():
    settings = get_pcen_settings()

    assert type(settings) == dict

    assert 'sr' in settings
    assert isinstance(settings['sr'], Real)
    assert settings['sr'] > 0

    assert 'fmin' in settings
    assert isinstance(settings['fmin'], Real)
    assert settings['fmin'] > 0

    assert 'fmax' in settings
    assert isinstance(settings['fmax'], Real)
    assert settings['fmax'] > settings['fmin']
    assert settings['sr'] / 2.0 >= settings['fmax']

    assert 'hop_length' in settings
    assert isinstance(settings['hop_length'], int)
    assert settings['hop_length'] > 0

    assert 'n_fft' in settings
    assert isinstance(settings['n_fft'], int)
    assert settings['n_fft'] > 0

    assert 'n_mels' in settings
    assert isinstance(settings['n_mels'], int)
    assert settings['n_fft'] > settings['n_mels'] > 0

    assert 'pcen_delta' in settings
    assert isinstance(settings['pcen_delta'], float)
    assert settings['pcen_delta'] > 0

    assert 'pcen_time_constant' in settings
    assert isinstance(settings['pcen_time_constant'], float)
    assert settings['pcen_time_constant'] > 0

    assert 'pcen_norm_exponent' in settings
    assert isinstance(settings['pcen_norm_exponent'], float)
    assert settings['pcen_norm_exponent'] > 0

    assert 'pcen_power' in settings
    assert isinstance(settings['pcen_power'], float)
    assert settings['pcen_power'] > 0

    assert 'top_freq_id' in settings
    assert isinstance(settings['top_freq_id'], int)
    assert settings['top_freq_id'] > 0

    assert 'win_length' in settings
    assert isinstance(settings['win_length'], int)
    assert settings['win_length'] > 0

    assert 'n_hops' in settings
    assert isinstance(settings['n_hops'], int)
    assert settings['n_hops'] > 0

    assert 'window' in settings
    assert isinstance(settings['window'], string_types)
    # Make sure window is valid
    get_window(settings['window'], 5)
Example #26
0
 def test_dpss(self):
     win1 = windows.get_window(('dpss', 3), 64, fftbins=False)
     win2 = windows.dpss(64, 3)
     assert_array_almost_equal(win1, win2, decimal=4)
Example #27
0
 def test_cheb_even(self):
     with suppress_warnings() as sup:
         sup.filter(UserWarning, "This window is not suitable")
         w = windows.get_window(('chebwin', 40), 54, fftbins=False)
     assert_array_almost_equal(w, cheb_even_true, decimal=4)
Example #28
0
    def tocovdata(self, timeseries):
        """
        Return auto covariance function from data.

        Return
        -------
        acf : CovData1D object
            with attributes:
            data : ACF vector length L+1
            args : time lags  length L+1
            sigma : estimated large lag standard deviation of the estimate
                    assuming x is a Gaussian process:
                    if acf[k]=0 for all lags k>q then an approximation
                    of the variance for large samples due to Bartlett
                     var(acf[k])=1/N*(acf[0]**2+2*acf[1]**2+2*acf[2]**2+ ..+2*acf[q]**2)
                     for  k>q and where  N=length(x). Special case is
                     white noise where it equals acf[0]**2/N for k>0
            norm : bool
                If false indicating that auto_cov is not normalized

         Example:
         --------
         >>> import wafo.data
         >>> import wafo.objects as wo
         >>> x = wafo.data.sea()
         >>> ts = wo.mat2timeseries(x)
         >>> acf = ts.tocovdata(150)

         h = acf.plot()
        """
        lag = self.lag
        window = self.window
        detrend = self.detrend

        try:
            x = timeseries.data.flatten('F')
            dt = timeseries.sampling_period()
        except Exception:
            x = timeseries[:, 1:].flatten('F')
            dt = sampling_period(timeseries[:, 0])
        if self.dt is not None:
            dt = self.dt

        if self.tr is not None:
            x = self.tr.dat2gauss(x)

        n = len(x)
        indnan = np.isnan(x)
        if any(indnan):
            x = x - x[1 - indnan].mean()
            Ncens = n - indnan.sum()
            x[indnan] = 0.
        else:
            Ncens = n
            x = x - x.mean()
        if hasattr(detrend, '__call__'):
            x = detrend(x)

        nfft = 2 ** nextpow2(n)
        raw_periodogram = abs(fft(x, nfft)) ** 2 / Ncens
        # ifft = fft/nfft since raw_periodogram is real!
        auto_cov = np.real(fft(raw_periodogram)) / nfft

        if self.flag.startswith('unbiased'):
            # unbiased result, i.e. divide by n-abs(lag)
            auto_cov = auto_cov[:Ncens] * Ncens / np.arange(Ncens, 1, -1)

        if self.norm:
            auto_cov = auto_cov / auto_cov[0]

        if lag is None:
            lag = self._estimate_lag(auto_cov, Ncens)
        lag = min(lag, n - 2)
        if isinstance(window, str) or type(window) is tuple:
            win = get_window(window, 2 * lag - 1)
        else:
            win = np.asarray(window)
        auto_cov[:lag] = auto_cov[:lag] * win[lag - 1::]
        auto_cov[lag] = 0
        lags = slice(0, lag + 1)
        t = np.linspace(0, lag * dt, lag + 1)
        acf = CovData1D(auto_cov[lags], t)
        acf.sigma = np.sqrt(np.r_[0, auto_cov[0] ** 2,
                            auto_cov[0] ** 2 + 2 * np.cumsum(auto_cov[1:] ** 2)] / Ncens)
        acf.children = [PlotData(-2. * acf.sigma[lags], t),
                        PlotData(2. * acf.sigma[lags], t)]
        acf.plot_args_children = ['r:']
        acf.norm = self.norm
        return acf
Example #29
0
def _welch(x, y, fs=1.0, window='hanning', nperseg=256, noverlap=None,
          nfft=None, detrend='constant', scaling='density', axis=-1):
    """
    A helper function to estimate cross spectral density using Welch's method.
    This function is a slightly modified version of `scipy.signal.welch()` with
    modifications based on `matplotlib.mlab._spectral_helper()`.

    Welch's method [1]_ computes an estimate of the cross spectral density
    by dividing the data into overlapping segments, computing a modified
    periodogram for each segment and averaging the cross-periodograms.

    Parameters
    ----------
    x, y : array_like
        Time series of measurement values
    fs : float, optional
        Sampling frequency of the `x` and `y` time series in units of Hz.
        Defaults to 1.0.
    window : str or tuple or array_like, optional
        Desired window to use. See `get_window` for a list of windows and
        required parameters. If `window` is array_like it will be used
        directly as the window and its length will be used for nperseg.
        Defaults to 'hanning'.
    nperseg : int, optional
        Length of each segment.  Defaults to 256.
    noverlap: int, optional
        Number of points to overlap between segments. If None,
        ``noverlap = nperseg / 2``.  Defaults to None.
    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.
    detrend : str or function, optional
        Specifies how to detrend each segment. If `detrend` is a string,
        it is passed as the ``type`` argument to `detrend`. If it is a
        function, it takes a segment and returns a detrended segment.
        Defaults to 'constant'.
    scaling : { 'density', 'spectrum' }, optional
        Selects between computing the power spectral density ('density')
        where Pxx has units of V**2/Hz if x is measured in V and computing
        the power spectrum ('spectrum') where Pxx has units of V**2 if x is
        measured in V. Defaults to 'density'.
    axis : int, optional
        Axis along which the periodogram is computed; the default is over
        the last axis (i.e. ``axis=-1``).

    Returns
    -------
    f : ndarray
        Array of sample frequencies.
    Pxy : ndarray
        Cross spectral density or cross spectrum of x and y.

    Notes
    -----
    An appropriate amount of overlap will depend on the choice of window
    and on your requirements.  For the default 'hanning' window an
    overlap of 50% is a reasonable trade off between accurately estimating
    the signal power, while not over counting any of the data.  Narrower
    windows may require a larger overlap.

    If `noverlap` is 0, this method is equivalent to Bartlett's method [2]_.

    References
    ----------
    .. [1] P. Welch, "The use of the fast Fourier transform for the
           estimation of power spectra: A method based on time averaging
           over short, modified periodograms", IEEE Trans. Audio
           Electroacoust. vol. 15, pp. 70-73, 1967.
    .. [2] M.S. Bartlett, "Periodogram Analysis and Continuous Spectra",
           Biometrika, vol. 37, pp. 1-16, 1950.
    """
    # TODO: This function should be replaced by `scipy.signal.csd()`, which
    # will appear in SciPy 0.16.0.

    # The checks for if y is x are so that we can use the same function to
    # obtain both power spectrum and cross spectrum without doing extra
    # calculations.
    same_data = y is x
    # Make sure we're dealing with a numpy array. If y and x were the same
    # object to start with, keep them that way
    x = np.asarray(x)
    if same_data:
        y = x
    else:
        if x.shape != y.shape:
            raise ValueError("x and y must be of the same shape.")
        y = np.asarray(y)

    if x.size == 0:
        return np.empty(x.shape), np.empty(x.shape)

    if axis != -1:
        x = np.rollaxis(x, axis, len(x.shape))
        if not same_data:
            y = np.rollaxis(y, axis, len(y.shape))

    if x.shape[-1] < nperseg:
        warnings.warn('nperseg = %d, is greater than x.shape[%d] = %d, using '
                      'nperseg = x.shape[%d]'
                      % (nperseg, axis, x.shape[axis], axis))
        nperseg = x.shape[-1]

    if isinstance(window, string_types) or type(window) is tuple:
        win = get_window(window, nperseg)
    else:
        win = np.asarray(window)
        if len(win.shape) != 1:
            raise ValueError('window must be 1-D')
        if win.shape[0] > x.shape[-1]:
            raise ValueError('window is longer than x.')
        nperseg = win.shape[0]

    if scaling == 'density':
        scale = 1.0 / (fs * (win * win).sum())
    elif scaling == 'spectrum':
        scale = 1.0 / win.sum()**2
    else:
        raise ValueError('Unknown scaling: %r' % scaling)

    if noverlap is None:
        noverlap = nperseg // 2
    elif noverlap >= nperseg:
        raise ValueError('noverlap must be less than nperseg.')

    if nfft is None:
        nfft = nperseg
    elif nfft < nperseg:
        raise ValueError('nfft must be greater than or equal to nperseg.')

    if not hasattr(detrend, '__call__'):
        detrend_func = lambda seg: signaltools.detrend(seg, type=detrend)
    elif axis != -1:
        # Wrap this function so that it receives a shape that it could
        # reasonably expect to receive.
        def detrend_func(seg):
            seg = np.rollaxis(seg, -1, axis)
            seg = detrend(seg)
            return np.rollaxis(seg, axis, len(seg.shape))
    else:
        detrend_func = detrend

    step = nperseg - noverlap
    indices = np.arange(0, x.shape[-1] - nperseg + 1, step)

    for k, ind in enumerate(indices):
        x_dt = detrend_func(x[..., ind:ind + nperseg])
        xft = fftpack.fft(x_dt * win, nfft)
        if same_data:
            yft = xft
        else:
            y_dt = detrend_func(y[..., ind:ind + nperseg])
            yft = fftpack.fft(y_dt * win, nfft)
        if k == 0:
            Pxy = (xft * yft.conj())
        else:
            Pxy *= k / (k + 1.0)
            Pxy += (xft * yft.conj()) / (k + 1.0)
    Pxy *= scale
    f = fftpack.fftfreq(nfft, 1.0 / fs)

    if axis != -1:
        Pxy = np.rollaxis(Pxy, -1, axis)

    return f, Pxy
Example #30
0
def _spectral_helper(x, y, fs=1.0, window='hann', nperseg=256,
                    noverlap=None, nfft=None, detrend='constant',
                    return_onesided=True, scaling='spectrum', axis=-1,
                    mode='psd'):
    """
    Calculate various forms of windowed FFTs for PSD, CSD, etc.
    This is a helper function that implements the commonality between the
    psd, csd, and spectrogram functions. It is not designed to be called
    externally. The windows are not averaged over; the result from each window
    is returned.

    Parameters
    ---------
    x : array_like
        Array or sequence containing the data to be analyzed.
    y : array_like
        Array or sequence containing the data to be analyzed. If this is
        the same object in memoery as x (i.e. _spectral_helper(x, x, ...)),
        the extra computations are spared.
    fs : float, optional
        Sampling frequency of the time series. Defaults to 1.0.
    window : str or tuple or array_like, optional
        Desired window to use. See `get_window` for a list of windows and
        required parameters. If `window` is array_like it will be used
        directly as the window and its length will be used for nperseg.
        Defaults to 'hann'.
    nperseg : int, optional
        Length of each segment.  Defaults to 256.
    noverlap : int, optional
        Number of points to overlap between segments. If None,
        ``noverlap = nperseg // 2``.  Defaults to None.
    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.
    detrend : str or function or False, optional
        Specifies how to detrend each segment. If `detrend` is a string,
        it is passed as the ``type`` argument to `detrend`.  If it is a
        function, it takes a segment and returns a detrended segment.
        If `detrend` is False, no detrending is done.  Defaults to 'constant'.
    return_onesided : bool, optional
        If True, return a one-sided spectrum for real data. If False return
        a two-sided spectrum. Note that for complex data, a two-sided
        spectrum is always returned.
    scaling : { 'density', 'spectrum' }, optional
        Selects between computing the cross spectral density ('density')
        where `Pxy` has units of V**2/Hz and computing the cross spectrum
        ('spectrum') where `Pxy` has units of V**2, if `x` and `y` are
        measured in V and fs is measured in Hz.  Defaults to 'density'
    axis : int, optional
        Axis along which the periodogram is computed; the default is over
        the last axis (i.e. ``axis=-1``).
    mode : str, optional
        Defines what kind of return values are expected. Options are ['psd',
        'complex', 'magnitude', 'angle', 'phase'].

    Returns
    -------
    freqs : ndarray
        Array of sample frequencies.
    t : ndarray
        Array of times corresponding to each data segment
    result : ndarray
        Array of output data, contents dependent on *mode* kwarg.

    References
    ----------
    .. [1] Stack Overflow, "Rolling window for 1D arrays in Numpy?",
        http://stackoverflow.com/a/6811241
    .. [2] Stack Overflow, "Using strides for an efficient moving average
        filter", http://stackoverflow.com/a/4947453

    Notes
    -----
    Adapted from matplotlib.mlab
    .. versionadded:: 0.16.0
    """
    from scipy import fftpack
    from scipy.signal import signaltools
    from scipy.signal.windows import get_window

    if mode not in ['psd', 'complex', 'magnitude', 'angle', 'phase']:
        raise ValueError("Unknown value for mode %s, must be one of: "
                         "'default', 'psd', 'complex', "
                         "'magnitude', 'angle', 'phase'" % mode)

    # If x and y are the same object we can save ourselves some computation.
    same_data = y is x

    if not same_data and mode != 'psd':
        raise ValueError("x and y must be equal if mode is not 'psd'")

    axis = int(axis)

    # Ensure we have np.arrays, get outdtype
    x = np.asarray(x)
    if not same_data:
        y = np.asarray(y)
        outdtype = np.result_type(x,y,np.complex64)
    else:
        outdtype = np.result_type(x,np.complex64)

    if not same_data:
        # Check if we can broadcast the outer axes together
        xouter = list(x.shape)
        youter = list(y.shape)
        xouter.pop(axis)
        youter.pop(axis)
        try:
            outershape = np.broadcast(np.empty(xouter), np.empty(youter)).shape
        except ValueError:
            raise ValueError('x and y cannot be broadcast together.')

    if same_data:
        if x.size == 0:
            return np.empty(x.shape), np.empty(x.shape), np.empty(x.shape)
    else:
        if x.size == 0 or y.size == 0:
            outshape = outershape + (min([x.shape[axis], y.shape[axis]]),)
            emptyout = np.rollaxis(np.empty(outshape), -1, axis)
            return emptyout, emptyout, emptyout

    if x.ndim > 1:
        if axis != -1:
            x = np.rollaxis(x, axis, len(x.shape))
            if not same_data and y.ndim > 1:
                y = np.rollaxis(y, axis, len(y.shape))

    # Check if x and y are the same length, zero-pad if necessary
    if not same_data:
        if x.shape[-1] != y.shape[-1]:
            if x.shape[-1] < y.shape[-1]:
                pad_shape = list(x.shape)
                pad_shape[-1] = y.shape[-1] - x.shape[-1]
                x = np.concatenate((x, np.zeros(pad_shape)), -1)
            else:
                pad_shape = list(y.shape)
                pad_shape[-1] = x.shape[-1] - y.shape[-1]
                y = np.concatenate((y, np.zeros(pad_shape)), -1)

    # X and Y are same length now, can test nperseg with either
    if x.shape[-1] < nperseg:
        warnings.warn('nperseg = {0:d}, is greater than input length = {1:d}, '
                      'using nperseg = {1:d}'.format(nperseg, x.shape[-1]))
        nperseg = x.shape[-1]

    nperseg = int(nperseg)
    if nperseg < 1:
        raise ValueError('nperseg must be a positive integer')

    if nfft is None:
        nfft = nperseg
    elif nfft < nperseg:
        raise ValueError('nfft must be greater than or equal to nperseg.')
    else:
        nfft = int(nfft)

    if noverlap is None:
        noverlap = nperseg//2
    elif noverlap >= nperseg:
        raise ValueError('noverlap must be less than nperseg.')
    else:
        noverlap = int(noverlap)

    # Handle detrending and window functions
    if not detrend:
        def detrend_func(d):
            return d
    elif not hasattr(detrend, '__call__'):
        def detrend_func(d):
            return signaltools.detrend(d, type=detrend, axis=-1)
    elif axis != -1:
        # Wrap this function so that it receives a shape that it could
        # reasonably expect to receive.
        def detrend_func(d):
            d = np.rollaxis(d, -1, axis)
            d = detrend(d)
            return np.rollaxis(d, axis, len(d.shape))
    else:
        detrend_func = detrend

    if isinstance(window, string_types) or type(window) is tuple:
        win = get_window(window, nperseg)
    else:
        win = np.asarray(window)
        if len(win.shape) != 1:
            raise ValueError('window must be 1-D')
        if win.shape[0] != nperseg:
            raise ValueError('window must have length of nperseg')

    if np.result_type(win,np.complex64) != outdtype:
        win = win.astype(outdtype)

    if mode == 'psd':
        if scaling == 'density':
            scale = 1.0 / (fs * (win*win).sum())
        elif scaling == 'spectrum':
            scale = 1.0 / win.sum()**2
        else:
            raise ValueError('Unknown scaling: %r' % scaling)
    else:
        scale = 1

    if return_onesided is True:
        if np.iscomplexobj(x):
            sides = 'twosided'
        else:
            sides = 'onesided'
            if not same_data:
                if np.iscomplexobj(y):
                    sides = 'twosided'
    else:
        sides = 'twosided'

    if sides == 'twosided':
        num_freqs = nfft
    elif sides == 'onesided':
        if nfft % 2:
            num_freqs = (nfft + 1)//2
        else:
            num_freqs = nfft//2 + 1

    # Perform the windowed FFTs
    result = _fft_helper(x, win, detrend_func, nperseg, noverlap, nfft)
    result = result[..., :num_freqs]
    freqs = fftpack.fftfreq(nfft, 1/fs)[:num_freqs]

    if not same_data:
        # All the same operations on the y data
        result_y = _fft_helper(y, win, detrend_func, nperseg, noverlap, nfft)
        result_y = result_y[..., :num_freqs]
        result = np.conjugate(result) * result_y
    elif mode == 'psd':
        result = np.conjugate(result) * result
    elif mode == 'magnitude':
        result = np.absolute(result)
    elif mode == 'angle' or mode == 'phase':
        result = np.angle(result)
    elif mode == 'complex':
        pass

    result *= scale
    if sides == 'onesided':
        if nfft % 2:
            result[...,1:] *= 2
        else:
            # Last point is unpaired Nyquist freq point, don't double
            result[...,1:-1] *= 2

    t = np.arange(nperseg/2, x.shape[-1] - nperseg/2 + 1, nperseg - noverlap)/float(fs)

    if sides != 'twosided' and not nfft % 2:
        # get the last value correctly, it is negative otherwise
        freqs[-1] *= -1

    # we unwrap the phase here to handle the onesided vs. twosided case
    if mode == 'phase':
        result = np.unwrap(result, axis=-1)

    result = result.astype(outdtype)

    # All imaginary parts are zero anyways
    if same_data and mode != 'complex':
        result = result.real

    # Output is going to have new last axis for window index
    if axis != -1:
        # Specify as positive axis index
        if axis < 0:
            axis = len(result.shape)-1-axis

        # Roll frequency axis back to axis where the data came from
        result = np.rollaxis(result, -1, axis)
    else:
        # Make sure window/time index is last axis
        result = np.rollaxis(result, -1, -2)

    return freqs, t, result
Example #31
0
def energy_correction(window, n_samples):
    window = windows.get_window(window, n_samples)
    return len(window) / np.sum(window**2)
Example #32
0
def timeseries_to_spectrogram(timeseries: Timeseries,
                              fft_size: int = 1024,
                              n_samples: int = 1024,
                              n_records: int = None,
                              synchronization_offset: int = 0,
                              overlap: float = 0.0,
                              window: str = None):
    """
    # TODO: Introduce overlap + windowing

    Args:
        n_records:
        synchronization_offset:
        timeseries:
        fft_size:
        n_samples:
        overlap:
        window: str

    Returns:

    """

    if overlap >= 1:
        raise ValueError("Overlap percentage must be less than 100%")
    if overlap < 0:
        raise ValueError("Overlap percentage must be equal or greater than 0%")

    total_samples = n_samples + synchronization_offset
    overlap_samples = n_samples * (1 - overlap)

    if n_records is None:
        n_records = int(
            ((len(timeseries.data) - total_samples) // overlap_samples)) + 1

    start_samples = [
        int(i * total_samples * (1 - overlap)) for i in range(n_records)
    ]
    time_data = np.zeros((fft_size, n_records), dtype=float)

    # Reshape the timeseries data into bins of n_time_samples:
    input_data = np.reshape(np.array(
        list(
            zip(*(timeseries.data['amplitude'][i:i + total_samples]
                  for i in start_samples)))), (total_samples, n_records),
                            order='F')
    # input_data = np.reshape(timeseries.data['amplitude'][:(n_records * total_samples)], (total_samples, n_records),
    #                         order='F')
    time_data[:n_samples, :] = input_data[:n_samples, :]

    if window is None:
        window = np.ones(n_samples)
    else:
        window = windows.get_window(window, n_samples)

    # Apply window
    time_data *= np.transpose(np.tile(window, (time_data.shape[1], 1)))

    spectrogram_data = fft.fft(time_data / timeseries.sample_rate,
                               fft_size,
                               axis=0)
    t_res = timeseries.duration() / (int(
        ((len(timeseries.data) - total_samples) // overlap_samples)) + 1)
    f_res = timeseries.sample_rate / fft_size

    return Spectrogram(spectrogram_data, f_res, t_res)
def _welch(x,
           y,
           fs=1.0,
           window='hanning',
           nperseg=256,
           noverlap=None,
           nfft=None,
           detrend='constant',
           scaling='density',
           axis=-1):
    """
    A helper function to estimate cross spectral density using Welch's method.
    This function is a slightly modified version of `scipy.signal.welch()` with
    modifications based on `matplotlib.mlab._spectral_helper()`.

    Welch's method [1]_ computes an estimate of the cross spectral density
    by dividing the data into overlapping segments, computing a modified
    periodogram for each segment and averaging the cross-periodograms.

    Parameters
    ----------
    x, y : array_like
        Time series of measurement values
    fs : float, optional
        Sampling frequency of the `x` and `y` time series in units of Hz.
        Defaults to 1.0.
    window : str or tuple or array_like, optional
        Desired window to use. See `get_window` for a list of windows and
        required parameters. If `window` is array_like it will be used
        directly as the window and its length will be used for nperseg.
        Defaults to 'hanning'.
    nperseg : int, optional
        Length of each segment.  Defaults to 256.
    noverlap: int, optional
        Number of points to overlap between segments. If None,
        ``noverlap = nperseg / 2``.  Defaults to None.
    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.
    detrend : str or function, optional
        Specifies how to detrend each segment. If `detrend` is a string,
        it is passed as the ``type`` argument to `detrend`. If it is a
        function, it takes a segment and returns a detrended segment.
        Defaults to 'constant'.
    scaling : { 'density', 'spectrum' }, optional
        Selects between computing the power spectral density ('density')
        where Pxx has units of V**2/Hz if x is measured in V and computing
        the power spectrum ('spectrum') where Pxx has units of V**2 if x is
        measured in V. Defaults to 'density'.
    axis : int, optional
        Axis along which the periodogram is computed; the default is over
        the last axis (i.e. ``axis=-1``).

    Returns
    -------
    f : ndarray
        Array of sample frequencies.
    Pxy : ndarray
        Cross spectral density or cross spectrum of x and y.

    Notes
    -----
    An appropriate amount of overlap will depend on the choice of window
    and on your requirements.  For the default 'hanning' window an
    overlap of 50% is a reasonable trade off between accurately estimating
    the signal power, while not over counting any of the data.  Narrower
    windows may require a larger overlap.

    If `noverlap` is 0, this method is equivalent to Bartlett's method [2]_.

    References
    ----------
    .. [1] P. Welch, "The use of the fast Fourier transform for the
           estimation of power spectra: A method based on time averaging
           over short, modified periodograms", IEEE Trans. Audio
           Electroacoust. vol. 15, pp. 70-73, 1967.
    .. [2] M.S. Bartlett, "Periodogram Analysis and Continuous Spectra",
           Biometrika, vol. 37, pp. 1-16, 1950.
    """
    # TODO: This function should be replaced by `scipy.signal.csd()`, which
    # will appear in SciPy 0.16.0.

    # The checks for if y is x are so that we can use the same function to
    # obtain both power spectrum and cross spectrum without doing extra
    # calculations.
    same_data = y is x
    # Make sure we're dealing with a numpy array. If y and x were the same
    # object to start with, keep them that way
    x = np.asarray(x)
    if same_data:
        y = x
    else:
        if x.shape != y.shape:
            raise ValueError("x and y must be of the same shape.")
        y = np.asarray(y)

    if x.size == 0:
        return np.empty(x.shape), np.empty(x.shape)

    if axis != -1:
        x = np.rollaxis(x, axis, len(x.shape))
        if not same_data:
            y = np.rollaxis(y, axis, len(y.shape))

    if x.shape[-1] < nperseg:
        warnings.warn('nperseg = %d, is greater than x.shape[%d] = %d, using '
                      'nperseg = x.shape[%d]' %
                      (nperseg, axis, x.shape[axis], axis))
        nperseg = x.shape[-1]

    if isinstance(window, string_types) or type(window) is tuple:
        win = get_window(window, nperseg)
    else:
        win = np.asarray(window)
        if len(win.shape) != 1:
            raise ValueError('window must be 1-D')
        if win.shape[0] > x.shape[-1]:
            raise ValueError('window is longer than x.')
        nperseg = win.shape[0]

    if scaling == 'density':
        scale = 1.0 / (fs * (win * win).sum())
    elif scaling == 'spectrum':
        scale = 1.0 / win.sum()**2
    else:
        raise ValueError('Unknown scaling: %r' % scaling)

    if noverlap is None:
        noverlap = nperseg // 2
    elif noverlap >= nperseg:
        raise ValueError('noverlap must be less than nperseg.')

    if nfft is None:
        nfft = nperseg
    elif nfft < nperseg:
        raise ValueError('nfft must be greater than or equal to nperseg.')

    if not hasattr(detrend, '__call__'):
        detrend_func = lambda seg: signaltools.detrend(seg, type=detrend)
    elif axis != -1:
        # Wrap this function so that it receives a shape that it could
        # reasonably expect to receive.
        def detrend_func(seg):
            seg = np.rollaxis(seg, -1, axis)
            seg = detrend(seg)
            return np.rollaxis(seg, axis, len(seg.shape))
    else:
        detrend_func = detrend

    step = nperseg - noverlap
    indices = np.arange(0, x.shape[-1] - nperseg + 1, step)

    for k, ind in enumerate(indices):
        x_dt = detrend_func(x[..., ind:ind + nperseg])
        xft = fftpack.fft(x_dt * win, nfft)
        if same_data:
            yft = xft
        else:
            y_dt = detrend_func(y[..., ind:ind + nperseg])
            yft = fftpack.fft(y_dt * win, nfft)
        if k == 0:
            Pxy = (xft * yft.conj())
        else:
            Pxy *= k / (k + 1.0)
            Pxy += (xft * yft.conj()) / (k + 1.0)
    Pxy *= scale
    f = fftpack.fftfreq(nfft, 1.0 / fs)

    if axis != -1:
        Pxy = np.rollaxis(Pxy, -1, axis)

    return f, Pxy
Example #34
0
def resample(x, up, down, npad=100, window='boxcar', n_jobs=1, verbose=None):
    """Resample the array x

    Operates along the last dimension of the array.

    Parameters
    ----------
    x : n-d array
        Signal to resample.
    up : float
        Factor to upsample by.
    down : float
        Factor to downsample by.
    npad : integer
        Number of samples to use at the beginning and end for padding.
    window : string or tuple
        See scipy.signal.resample for description.
    n_jobs : int | str
        Number of jobs to run in parallel. Can be 'cuda' if scikits.cuda
        is installed properly and CUDA is initialized.
    verbose : bool, str, int, or None
        If not None, override default verbose level (see mne.verbose).

    Returns
    -------
    xf : array
        x resampled.

    Notes
    -----
    This uses (hopefully) intelligent edge padding and frequency-domain
    windowing improve scipy.signal.resample's resampling method, which
    we have adapted for our use here. Choices of npad and window have
    important consequences, and the default choices should work well
    for most natural signals.

    Resampling arguments are broken into "up" and "down" components for future
    compatibility in case we decide to use an upfirdn implementation. The
    current implementation is functionally equivalent to passing
    up=up/down and down=1.
    """
    # make sure our arithmetic will work
    ratio = float(up) / down
    x, orig_shape = _prep_for_filtering(x, False)[:2]

    x_len = x.shape[1]
    if x_len > 0:
        # prep for resampling now
        orig_len = x_len + 2 * npad  # length after padding
        new_len = ratio * orig_len   # length after resampling padded signal
        to_remove = np.round(ratio * npad).astype(int)

        # figure out windowing function
        if window is not None:
            if callable(window):
                W = window(fftfreq(orig_len))
            elif isinstance(window, np.ndarray) and \
                    window.shape == (orig_len,):
                W = window
            else:
                W = ifftshift(get_window(window, orig_len))
        else:
            W = np.ones(orig_len)
        W *= (float(new_len) / float(orig_len))
        W = W.astype(np.complex128)

        # figure out if we should use CUDA
        n_jobs, cuda_dict, W = setup_cuda_fft_resample(n_jobs, W, new_len)

        # do the resampling using an adaptation of scipy's FFT-based resample()
        # use of the 'flat' window is recommended for minimal ringing
        if n_jobs == 1:
            y = np.zeros((len(x), new_len - 2 * to_remove), dtype=x.dtype)
            for xi, x_ in enumerate(x):
                y[xi] = fft_resample(x_, W, new_len, npad, to_remove,
                                     cuda_dict)
        else:
            if not isinstance(n_jobs, int):
                raise ValueError('n_jobs must be an integer, or "cuda"')
            parallel, p_fun, _ = parallel_func(fft_resample, n_jobs)
            y = parallel(p_fun(x_, W, new_len, npad, to_remove, cuda_dict)
                         for x_ in x)
            y = np.array(y)

        # Restore the original array shape (modified for resampling)
        orig_shape = list(orig_shape)
        orig_shape[-1] = y.shape[1]
        y.shape = tuple(orig_shape)
    else:
        warnings.warn('x has zero length along last axis, returning a copy of '
                      'x')
        y = x.copy()
    return y
Example #35
0
def _weight_data_matrix(data_matrix, window_type, data_transformation=None):
    window_length_in_samp = data_matrix[0].shape[0]
    window = get_window(window_type, window_length_in_samp, fftbins=False)
    if (data_transformation == 'group_delay'):
        window *= np.arange(window_length_in_samp)
    return data_matrix * window
Example #36
0
def welch(x, fs=1.0, window='hanning', nperseg=256, noverlap=None, nfft=None,
          detrend='constant', return_onesided=True, scaling='density', axis=-1):
    """
    Estimate power spectral density using Welch's method.
    Welch's method [1]_ computes an estimate of the power spectral density
    by dividing the data into overlapping segments, computing a modified
    periodogram for each segment and averaging the periodograms.
    Parameters
    ----------
    x : array_like
        Time series of measurement values
    fs : float, optional
        Sampling frequency of the `x` time series in units of Hz. Defaults
        to 1.0.
    window : str or tuple or array_like, optional
        Desired window to use. See `get_window` for a list of windows and
        required parameters. If `window` is array_like it will be used
        directly as the window and its length will be used for nperseg.
        Defaults to 'hanning'.
    nperseg : int, optional
        Length of each segment.  Defaults to 256.
    noverlap: int, optional
        Number of points to overlap between segments. If None,
        ``noverlap = nperseg / 2``.  Defaults to None.
    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.
    detrend : str or function or False, optional
        Specifies how to detrend each segment. If `detrend` is a string,
        it is passed as the ``type`` argument to `detrend`.  If it is a
        function, it takes a segment and returns a detrended segment.
        If `detrend` is False, no detrending is done.  Defaults to 'constant'.
    return_onesided : bool, optional
        If True, return a one-sided spectrum for real data. If False return
        a two-sided spectrum. Note that for complex data, a two-sided
        spectrum is always returned.
    scaling : { 'density', 'spectrum' }, optional
        Selects between computing the power spectral density ('density')
        where Pxx has units of V**2/Hz if x is measured in V and computing
        the power spectrum ('spectrum') where Pxx has units of V**2 if x is
        measured in V. Defaults to 'density'.
    axis : int, optional
        Axis along which the periodogram is computed; the default is over
        the last axis (i.e. ``axis=-1``).
    Returns
    -------
    f : ndarray
        Array of sample frequencies.
    Pxx : ndarray
        Power spectral density or power spectrum of x.
    See Also
    --------
    periodogram: Simple, optionally modified periodogram
    lombscargle: Lomb-Scargle periodogram for unevenly sampled data
    Notes
    -----
    An appropriate amount of overlap will depend on the choice of window
    and on your requirements.  For the default 'hanning' window an
    overlap of 50% is a reasonable trade off between accurately estimating
    the signal power, while not over counting any of the data.  Narrower
    windows may require a larger overlap.
    If `noverlap` is 0, this method is equivalent to Bartlett's method [2]_.
    .. versionadded:: 0.12.0
    References
    ----------
    .. [1] P. Welch, "The use of the fast Fourier transform for the
           estimation of power spectra: A method based on time averaging
           over short, modified periodograms", IEEE Trans. Audio
           Electroacoust. vol. 15, pp. 70-73, 1967.
    .. [2] M.S. Bartlett, "Periodogram Analysis and Continuous Spectra",
           Biometrika, vol. 37, pp. 1-16, 1950.
    Examples
    --------
    >>> from scipy import signal
    >>> import matplotlib.pyplot as plt
    Generate a test signal, a 2 Vrms sine wave at 1234 Hz, corrupted by
    0.001 V**2/Hz of white noise sampled at 10 kHz.
    >>> fs = 10e3
    >>> N = 1e5
    >>> amp = 2*np.sqrt(2)
    >>> freq = 1234.0
    >>> noise_power = 0.001 * fs / 2
    >>> time = np.arange(N) / fs
    >>> x = amp*np.sin(2*np.pi*freq*time)
    >>> x += np.random.normal(scale=np.sqrt(noise_power), size=time.shape)
    Compute and plot the power spectral density.
    >>> f, Pxx_den = signal.welch(x, fs, nperseg=1024)
    >>> plt.semilogy(f, Pxx_den)
    >>> plt.ylim([0.5e-3, 1])
    >>> plt.xlabel('frequency [Hz]')
    >>> plt.ylabel('PSD [V**2/Hz]')
    >>> plt.show()
    If we average the last half of the spectral density, to exclude the
    peak, we can recover the noise power on the signal.
    >>> np.mean(Pxx_den[256:])
    0.0009924865443739191
    Now compute and plot the power spectrum.
    >>> f, Pxx_spec = signal.welch(x, fs, 'flattop', 1024, scaling='spectrum')
    >>> plt.figure()
    >>> plt.semilogy(f, np.sqrt(Pxx_spec))
    >>> plt.xlabel('frequency [Hz]')
    >>> plt.ylabel('Linear spectrum [V RMS]')
    >>> plt.show()
    The peak height in the power spectrum is an estimate of the RMS amplitude.
    >>> np.sqrt(Pxx_spec.max())
    2.0077340678640727
    """
    x = np.asarray(x)

    if x.size == 0:
        return np.empty(x.shape), np.empty(x.shape)

    if axis != -1:
        x = np.rollaxis(x, axis, len(x.shape))

    if x.shape[-1] < nperseg:
        warnings.warn('nperseg = %d, is greater than x.shape[%d] = %d, using '
                      'nperseg = x.shape[%d]'
                      % (nperseg, axis, x.shape[axis], axis))
        nperseg = x.shape[-1]

    if isinstance(window, string_types) or type(window) is tuple:
        win = get_window(window, nperseg)
    else:
        win = np.asarray(window)
        if len(win.shape) != 1:
            raise ValueError('window must be 1-D')
        if win.shape[0] > x.shape[-1]:
            raise ValueError('window is longer than x.')
        nperseg = win.shape[0]

    # numpy 1.5.1 doesn't have result_type.
    outdtype = (np.array([x[0]]) * np.array([1], 'f')).dtype.char.lower()
    if win.dtype != outdtype:
        win = win.astype(outdtype)
 
    if scaling == 'density':
        scale = 1.0 / (fs * (win*win).sum())
    elif scaling == 'spectrum':
        scale = 1.0 / win.sum()**2
    else:
        raise ValueError('Unknown scaling: %r' % scaling)

    if noverlap is None:
        noverlap = nperseg // 2
    elif noverlap >= nperseg:
        raise ValueError('noverlap must be less than nperseg.')

    if nfft is None:
        nfft = nperseg
    elif nfft < nperseg:
        raise ValueError('nfft must be greater than or equal to nperseg.')

    if not detrend:
        detrend_func = lambda seg: seg
    elif not hasattr(detrend, '__call__'):
        detrend_func = lambda seg: signaltools.detrend(seg, type=detrend)
    elif axis != -1:
        # Wrap this function so that it receives a shape that it could
        # reasonably expect to receive.
        def detrend_func(seg):
            seg = np.rollaxis(seg, -1, axis)
            seg = detrend(seg)
            return np.rollaxis(seg, axis, len(seg.shape))
    else:
        detrend_func = detrend

    step = nperseg - noverlap
    indices = np.arange(0, x.shape[-1]-nperseg+1, step)

    if np.isrealobj(x) and return_onesided:
        outshape = list(x.shape)
        if nfft % 2 == 0:  # even
            outshape[-1] = nfft // 2 + 1
            Pxx = np.empty(outshape, outdtype)
            for k, ind in enumerate(indices):
                x_dt = detrend_func(x[..., ind:ind+nperseg])
                xft = my_rfft(x_dt*win, nfft)
                #xft = fftpack.rfft(x_dt*win, nfft)
                # fftpack.rfft returns the positive frequency part of the fft
                # as real values, packed r r i r i r i ...
                # this indexing is to extract the matching real and imaginary
                # parts, while also handling the pure real zero and nyquist
                # frequencies.
                if k == 0:
                    Pxx[..., (0,-1)] = xft[..., (0,-1)]**2
                    Pxx[..., 1:-1] = xft[..., 1:-1:2]**2 + xft[..., 2::2]**2
                else:
                    Pxx *= k/(k+1.0)
                    Pxx[..., (0,-1)] += xft[..., (0,-1)]**2 / (k+1.0)
                    Pxx[..., 1:-1] += (xft[..., 1:-1:2]**2 + xft[..., 2::2]**2) \
                                    / (k+1.0)
        else:  # odd
            outshape[-1] = (nfft+1) // 2
            Pxx = np.empty(outshape, outdtype)
            for k, ind in enumerate(indices):
                x_dt = detrend_func(x[..., ind:ind+nperseg])
                xft = my_rfft(x_dt*win, nfft)
                #xft = fftpack.rfft(x_dt*win, nfft)
                #print (nfft, xft.shape, xft_2.shape)
                if k == 0:
                    Pxx[..., 0] = xft[..., 0]**2
                    Pxx[..., 1:] = xft[..., 1::2]**2 + xft[..., 2::2]**2
                else:
                    Pxx *= k/(k+1.0)
                    Pxx[..., 0] += xft[..., 0]**2 / (k+1)
                    Pxx[..., 1:] += (xft[..., 1::2]**2 + xft[..., 2::2]**2) \
                                  / (k+1.0)

        Pxx[..., 1:-1] *= 2*scale
        Pxx[..., (0,-1)] *= scale
        f = np.arange(Pxx.shape[-1]) * (fs/nfft)
    else:
        for k, ind in enumerate(indices):
            x_dt = detrend_func(x[..., ind:ind+nperseg])
            xft = my_rfft(x_dt*win, nfft)
            #xft = fftpack.rfft(x_dt*win, nfft)
            if k == 0:
                Pxx = (xft * xft.conj()).real
            else:
                Pxx *= k/(k+1.0)
                Pxx += (xft * xft.conj()).real / (k+1.0)
        Pxx *= scale
        f = fftpack.fftfreq(nfft, 1.0/fs)

    if axis != -1:
        Pxx = np.rollaxis(Pxx, -1, axis)

    return f, Pxx
Example #37
0
 def test_kaiser_float(self):
     win1 = windows.get_window(7.2, 64)
     win2 = windows.kaiser(64, 7.2, False)
     assert_allclose(win1, win2)
Example #38
0
#
window_data = {}
figs = {}
figs_response = {}

#
# Generate window data
#

for window in window_names:

    window_name = str(window)

    try:
        # Generate signal data
        window_data[window_name] = windows.get_window(window, Nx)

    except ValueError as e:
        # Call the function itself if it exists
        if window in windows.__all__:
            window_data[window_name] = getattr(windows, window)(Nx)

        elif type(window) is tuple and window[0] in windows.__all__:
            window_data[window_name] = getattr(windows, window[0])(Nx,
                                                                   *window[1:])

        else:
            print(f"{window} failed: {e}")
            continue

    # Generate frequency response
Example #39
0
def _spectral_helper(x, y, fs=1.0, window='hann', nperseg=256,
                    noverlap=None, nfft=None, detrend='constant',
                    return_onesided=True, scaling='spectrum', axis=-1,
                    mode='psd'):
    """
    Calculate various forms of windowed FFTs for PSD, CSD, etc.
    This is a helper function that implements the commonality between the
    psd, csd, and spectrogram functions. It is not designed to be called
    externally. The windows are not averaged over; the result from each window
    is returned.

    Parameters
    ---------
    x : array_like
        Array or sequence containing the data to be analyzed.
    y : array_like
        Array or sequence containing the data to be analyzed. If this is
        the same object in memoery as x (i.e. _spectral_helper(x, x, ...)),
        the extra computations are spared.
    fs : float, optional
        Sampling frequency of the time series. Defaults to 1.0.
    window : str or tuple or array_like, optional
        Desired window to use. See `get_window` for a list of windows and
        required parameters. If `window` is array_like it will be used
        directly as the window and its length will be used for nperseg.
        Defaults to 'hann'.
    nperseg : int, optional
        Length of each segment.  Defaults to 256.
    noverlap : int, optional
        Number of points to overlap between segments. If None,
        ``noverlap = nperseg // 2``.  Defaults to None.
    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.
    detrend : str or function or False, optional
        Specifies how to detrend each segment. If `detrend` is a string,
        it is passed as the ``type`` argument to `detrend`.  If it is a
        function, it takes a segment and returns a detrended segment.
        If `detrend` is False, no detrending is done.  Defaults to 'constant'.
    return_onesided : bool, optional
        If True, return a one-sided spectrum for real data. If False return
        a two-sided spectrum. Note that for complex data, a two-sided
        spectrum is always returned.
    scaling : { 'density', 'spectrum' }, optional
        Selects between computing the cross spectral density ('density')
        where `Pxy` has units of V**2/Hz and computing the cross spectrum
        ('spectrum') where `Pxy` has units of V**2, if `x` and `y` are
        measured in V and fs is measured in Hz.  Defaults to 'density'
    axis : int, optional
        Axis along which the periodogram is computed; the default is over
        the last axis (i.e. ``axis=-1``).
    mode : str, optional
        Defines what kind of return values are expected. Options are ['psd',
        'complex', 'magnitude', 'angle', 'phase'].

    Returns
    -------
    freqs : ndarray
        Array of sample frequencies.
    t : ndarray
        Array of times corresponding to each data segment
    result : ndarray
        Array of output data, contents dependent on *mode* kwarg.

    References
    ----------
    .. [1] Stack Overflow, "Rolling window for 1D arrays in Numpy?",
        http://stackoverflow.com/a/6811241
    .. [2] Stack Overflow, "Using strides for an efficient moving average
        filter", http://stackoverflow.com/a/4947453

    Notes
    -----
    Adapted from matplotlib.mlab
    .. versionadded:: 0.16.0
    """
    from scipy import fftpack
    from scipy.signal import signaltools
    from scipy.signal.windows import get_window

    if mode not in ['psd', 'complex', 'magnitude', 'angle', 'phase']:
        raise ValueError("Unknown value for mode %s, must be one of: "
                         "'default', 'psd', 'complex', "
                         "'magnitude', 'angle', 'phase'" % mode)

    # If x and y are the same object we can save ourselves some computation.
    same_data = y is x

    if not same_data and mode != 'psd':
        raise ValueError("x and y must be equal if mode is not 'psd'")

    axis = int(axis)

    # Ensure we have np.arrays, get outdtype
    x = np.asarray(x)
    if not same_data:
        y = np.asarray(y)
        outdtype = np.result_type(x,y,np.complex64)
    else:
        outdtype = np.result_type(x,np.complex64)

    if not same_data:
        # Check if we can broadcast the outer axes together
        xouter = list(x.shape)
        youter = list(y.shape)
        xouter.pop(axis)
        youter.pop(axis)
        try:
            outershape = np.broadcast(np.empty(xouter), np.empty(youter)).shape
        except ValueError:
            raise ValueError('x and y cannot be broadcast together.')

    if same_data:
        if x.size == 0:
            return np.empty(x.shape), np.empty(x.shape), np.empty(x.shape)
    else:
        if x.size == 0 or y.size == 0:
            outshape = outershape + (min([x.shape[axis], y.shape[axis]]),)
            emptyout = np.rollaxis(np.empty(outshape), -1, axis)
            return emptyout, emptyout, emptyout

    if x.ndim > 1:
        if axis != -1:
            x = np.rollaxis(x, axis, len(x.shape))
            if not same_data and y.ndim > 1:
                y = np.rollaxis(y, axis, len(y.shape))

    # Check if x and y are the same length, zero-pad if necessary
    if not same_data:
        if x.shape[-1] != y.shape[-1]:
            if x.shape[-1] < y.shape[-1]:
                pad_shape = list(x.shape)
                pad_shape[-1] = y.shape[-1] - x.shape[-1]
                x = np.concatenate((x, np.zeros(pad_shape)), -1)
            else:
                pad_shape = list(y.shape)
                pad_shape[-1] = x.shape[-1] - y.shape[-1]
                y = np.concatenate((y, np.zeros(pad_shape)), -1)

    # X and Y are same length now, can test nperseg with either
    if x.shape[-1] < nperseg:
        warnings.warn('nperseg = {0:d}, is greater than input length = {1:d}, '
                      'using nperseg = {1:d}'.format(nperseg, x.shape[-1]))
        nperseg = x.shape[-1]

    nperseg = int(nperseg)
    if nperseg < 1:
        raise ValueError('nperseg must be a positive integer')

    if nfft is None:
        nfft = nperseg
    elif nfft < nperseg:
        raise ValueError('nfft must be greater than or equal to nperseg.')
    else:
        nfft = int(nfft)

    if noverlap is None:
        noverlap = nperseg//2
    elif noverlap >= nperseg:
        raise ValueError('noverlap must be less than nperseg.')
    else:
        noverlap = int(noverlap)

    # Handle detrending and window functions
    if not detrend:
        def detrend_func(d):
            return d
    elif not hasattr(detrend, '__call__'):
        def detrend_func(d):
            return signaltools.detrend(d, type=detrend, axis=-1)
    elif axis != -1:
        # Wrap this function so that it receives a shape that it could
        # reasonably expect to receive.
        def detrend_func(d):
            d = np.rollaxis(d, -1, axis)
            d = detrend(d)
            return np.rollaxis(d, axis, len(d.shape))
    else:
        detrend_func = detrend

    if isinstance(window, string_types) or type(window) is tuple:
        win = get_window(window, nperseg)
    else:
        win = np.asarray(window)
        if len(win.shape) != 1:
            raise ValueError('window must be 1-D')
        if win.shape[0] != nperseg:
            raise ValueError('window must have length of nperseg')

    if np.result_type(win,np.complex64) != outdtype:
        win = win.astype(outdtype)

    if mode == 'psd':
        if scaling == 'density':
            scale = 1.0 / (fs * (win*win).sum())
        elif scaling == 'spectrum':
            scale = 1.0 / win.sum()**2
        else:
            raise ValueError('Unknown scaling: %r' % scaling)
    else:
        scale = 1

    if return_onesided is True:
        if np.iscomplexobj(x):
            sides = 'twosided'
        else:
            sides = 'onesided'
            if not same_data:
                if np.iscomplexobj(y):
                    sides = 'twosided'
    else:
        sides = 'twosided'

    if sides == 'twosided':
        num_freqs = nfft
    elif sides == 'onesided':
        if nfft % 2:
            num_freqs = (nfft + 1)//2
        else:
            num_freqs = nfft//2 + 1

    # Perform the windowed FFTs
    result = _fft_helper(x, win, detrend_func, nperseg, noverlap, nfft)
    result = result[..., :num_freqs]
    freqs = fftpack.fftfreq(nfft, 1/fs)[:num_freqs]

    if not same_data:
        # All the same operations on the y data
        result_y = _fft_helper(y, win, detrend_func, nperseg, noverlap, nfft)
        result_y = result_y[..., :num_freqs]
        result = np.conjugate(result) * result_y
    elif mode == 'psd':
        result = np.conjugate(result) * result
    elif mode == 'magnitude':
        result = np.absolute(result)
    elif mode == 'angle' or mode == 'phase':
        result = np.angle(result)
    elif mode == 'complex':
        pass

    result *= scale
    if sides == 'onesided':
        if nfft % 2:
            result[...,1:] *= 2
        else:
            # Last point is unpaired Nyquist freq point, don't double
            result[...,1:-1] *= 2

    t = np.arange(nperseg/2, x.shape[-1] - nperseg/2 + 1, nperseg - noverlap)/float(fs)

    if sides != 'twosided' and not nfft % 2:
        # get the last value correctly, it is negative otherwise
        freqs[-1] *= -1

    # we unwrap the phase here to handle the onesided vs. twosided case
    if mode == 'phase':
        result = np.unwrap(result, axis=-1)

    result = result.astype(outdtype)

    # All imaginary parts are zero anyways
    if same_data and mode != 'complex':
        result = result.real

    # Output is going to have new last axis for window index
    if axis != -1:
        # Specify as positive axis index
        if axis < 0:
            axis = len(result.shape)-1-axis

        # Roll frequency axis back to axis where the data came from
        result = np.rollaxis(result, -1, axis)
    else:
        # Make sure window/time index is last axis
        result = np.rollaxis(result, -1, -2)

    return freqs, t, result
Example #40
0
    def tocovdata(self, timeseries):
        '''
        Return auto covariance function from data.

        Return
        -------
        R : CovData1D object
            with attributes:
            data : ACF vector length L+1
            args : time lags  length L+1
            sigma : estimated large lag standard deviation of the estimate
                     assuming x is a Gaussian process:
                     if R(k)=0 for all lags k>q then an approximation
                     of the variance for large samples due to Bartlett
                     var(R(k))=1/N*(R(0)^2+2*R(1)^2+2*R(2)^2+ ..+2*R(q)^2)
                     for  k>q and where  N=length(x). Special case is
                     white noise where it equals R(0)^2/N for k>0
            norm : bool
                If false indicating that R is not normalized

         Example:
         --------
         >>> import wafo.data
         >>> import wafo.objects as wo
         >>> x = wafo.data.sea()
         >>> ts = wo.mat2timeseries(x)
         >>> acf = ts.tocovdata(150)
         >>> h = acf.plot()
        '''
        lag = self.lag
        window = self.window
        detrend = self.detrend

        try:
            x = timeseries.data.flatten('F')
            dt = timeseries.sampling_period()
        except Exception:
            x = timeseries[:, 1:].flatten('F')
            dt = sampling_period(timeseries[:, 0])
        if not (self.dt is None):
            dt = self.dt

        if not (self.tr is None):
            x = self.tr.dat2gauss(x)

        n = len(x)
        indnan = np.isnan(x)
        if any(indnan):
            x = x - x[1 - indnan].mean()
            Ncens = n - indnan.sum()
            x[indnan] = 0.
        else:
            Ncens = n
            x = x - x.mean()
        if hasattr(detrend, '__call__'):
            x = detrend(x)

        nfft = 2 ** nextpow2(n)
        Rper = abs(fft(x, nfft)) ** 2 / Ncens  # Raw periodogram
        R = np.real(fft(Rper)) / nfft  # ifft = fft/nfft since Rper is real!

        if self.flag.startswith('unbiased'):
            # unbiased result, i.e. divide by n-abs(lag)
            R = R[:Ncens] * Ncens / np.arange(Ncens, 1, -1)

        if self.norm:
            R = R / R[0]

        if lag is None:
            lag = self._estimate_lag(R, Ncens)
        lag = min(lag, n - 2)
        if isinstance(window, str) or type(window) is tuple:
            win = get_window(window, 2 * lag - 1)
        else:
            win = np.asarray(window)
        R[:lag] = R[:lag] * win[lag - 1::]
        R[lag] = 0
        lags = slice(0, lag + 1)
        t = np.linspace(0, lag * dt, lag + 1)
        acf = CovData1D(R[lags], t)
        acf.sigma = np.sqrt(np.r_[0, R[0] ** 2,
                            R[0] ** 2 + 2 * np.cumsum(R[1:] ** 2)] / Ncens)
        acf.children = [PlotData(-2. * acf.sigma[lags], t),
                        PlotData(2. * acf.sigma[lags], t)]
        acf.plot_args_children = ['r:']
        acf.norm = self.norm
        return acf