Beispiel #1
0
def crossSpectra(data, frequency=10, notation=None, anti_aliasing=True):
    """
    Calculates the spectrum for a set of data

    Parameters
    ----------
    data: pandas.DataFrame or pandas.Series
        dataframe with one (will return the spectrum) or two (will return to cross-spectrum) columns
    frequency: float
        frequency of measurement of signal to pass to numpy.fft.rfftfreq
    anti_aliasing: bool
        whether or not to apply anti-aliasing according to Gobbi, Chamecki & Dias, 2006 (doi:10.1029/2005WR004374)
    notation: notation object
        notation to be used

    Returns
    --------
    spectrum: pandas.DataFrame
        whose column is the spectrum or coespectrum of the input dataframe
    """
    from . import notation
    from . import algs
    import numpy as np
    import pandas as pd
    from itertools import combinations

    notation=algs.get_notation(notation)

    N = len(data)
    combs = list(combinations(data.columns, 2))
    names = [ notation.cross_spectrum % (a, b) for a, b in combs ]

    specs = pd.DataFrame(columns = names)

    #---------
    # Calculate spectra here
    for (a, b) in combs: 
        spec_name = notation.cross_spectrum % (a, b)
        spec = np.fft.rfft(data.loc[:,a])
        specs.loc[:, spec_name ] = np.conj(spec) * np.fft.rfft(data.loc[:,b])
    #---------

    #---------
    # Anti-aliasing is done here
    if anti_aliasing:
        RA = np.array([ 1. + np.cos(np.pi*k/N) for k in range(N/2+1) ])/2.
        specs = specs.multiply(RA**2., axis='rows')
    #---------

    #---------
    # Now we normalize the spectrum and calculate their frequency
    specs *= 2./(frequency*N)
    freq = np.fft.rfftfreq(len(data), d=1./frequency)
    specs.index = freq
    specs.index.name='Frequency'
    #---------

    return specs
Beispiel #2
0
def rotate2D(data, notation=None):
    """Rotates the coordinates of wind data

    Parameters
    ----------
    data: pandas DataFrame 
        the dataFrame to be rotated
    notation: notation object
        a notation object to know which are the wind variables

    Returns
    -------
    pandas.DataFrame
        the complete data input with the wind components rotated
    """
    from math import atan2, sqrt
    import numpy as np
    import algs

    #-------
    # Getting the names for u, v, w
    defs = algs.get_notation(notation)
    wind_vars = [ defs.u, defs.v, defs.w ]
    #-------

    #-------
    # Definition of the coefficients used to created the rotation matrix
    wind_vec = data[wind_vars].mean().values
    m_u, m_v, m_w = wind_vec
    alpha = atan2(m_v,m_u)
    beta =-atan2(m_w, sqrt((m_u**2.)+(m_v**2.)))
    #-------

    #-------
    # Definition of rotation matrix
    DC= np.zeros((3,3))
    DC[0,0],DC[0,1],DC[0,2] = np.cos(alpha)*np.cos(beta), np.cos(beta)*np.sin(alpha),-np.sin(beta)
    DC[1,0],DC[1,1],DC[1,2] =-np.sin(alpha)          , np.cos(alpha)          , 0.
    DC[2,0],DC[2,1],DC[2,2] = np.cos(alpha)*np.sin(beta), np.sin(alpha)*np.sin(beta), np.cos(beta)
    #-------

    #-------
    # Application of rotation as a matrix product
    data[wind_vars] = np.dot(DC, data[wind_vars].values.T).T
    #-------

    return data
Beispiel #3
0
def spectra(data, frequency=10, notation=None, anti_aliasing=True):
    """
    Calculates the cross-spectra for a set of data

    Parameters
    ----------
    data: pandas.DataFrame or pandas.Series
        dataframe with more than one columns
    frequency: float
        frequency of measurement of signal to pass to numpy.fft.rfftfreq
    anti_aliasing: bool
        whether or not to apply anti-aliasing according to Gobbi, Chamecki & Dias, 2006 (doi:10.1029/2005WR004374)

    Returns
    -------
    spectra: pandas.DataFrame
        whose column is the spectrum or coespectrum of the input dataframe
    """
    from . import notation
    from . import algs
    import numpy as np
    import pandas as pd

    if len(data.columns) < 2:
        raise TypeError('DataFrame has to has more than 1 column.')

    notation = algs.get_notation(notation)

    N = len(data)

    names = [ notation.spectrum % a for a in data.columns ]
    specs = pd.DataFrame(columns = names)

    #---------
    # Calculate cross-spectra here
    for name, col in zip(names, data.columns):
        spec = np.fft.rfft(data.loc[:, col ])
        specs.loc[:, name ] = np.conj(spec) * spec
    #---------

    #---------
    # Since it's the spectra, we can ignore the imaginary part
    specs = specs.apply(np.real)
    #---------

    #---------
    # Anti-aliasing is done here
    if anti_aliasing:
        RA = np.array([ 1. + np.cos(np.pi*k/N) for k in range(N/2+1) ])/2.
        specs = specs.multiply(RA**2., axis='rows')
    #---------

    #---------
    # Now we normalize the spectrum and calculate their frequency
    specs *= 2./(frequency*N)
    freq = np.fft.rfftfreq(len(data), d=1./frequency)
    specs.index = freq
    specs.index.name='Frequency'
    #---------

    return specs
Beispiel #4
0
def detrend(data, how='linear', rule=None, notation=None, suffix=None, units=None, inplace=True, ignore=[], **kwargs):
    """
    Returns the detrended fluctuations of a given dataset

    Parameters
    ----------
    data: pandas.DataFrame, pandas.Series
        dataset to be detrended
    how: string
        how of average to apply. Currently {'movingmean', 'movingmedian', 'block', 'linear', 'poly'}.
    rule: pandas offset string
        the blocks for which the trends should be calculated in the block and linear type
    window: pandas date offset string or int
        if moving mean/median is chosen, this tells us the window size to pass to pandas. If int,
        this is the number of points used in the window. If string we will to guess the number of
        points from the index.
        Small windows (equivalent to 1min approx) work better when using rollingmedian.
    block_func: str, function
        how to resample in block type. Default is mean but it can be any numpy function
        that returns a float. E.g, median.
    degree: int
        degree of polynomial fit (only if how=='linear' or how=='polynomial')

    Returns
    -------
    pandas.DataFrame or pandas.Series
        fluctuations of the input data
    """
    from scipy import signal
    from . import algs
    import pandas as pd

    how=algs.stripDown(how.lower(), args='-_')
    df=data.copy()
    if ignore:
        df = df.drop(ignore, axis=1)
    defs = algs.get_notation(notation)

    #-----------
    # We can only use scipy's detrend function safely if index in not datetime
    if isinstance(df.index, pd.DatetimeIndex):
        df = df - trend(df, how=how, rule=rule, **kwargs)
    else:
        #-----------
        # If possible, try to use scipy's optimized functions
        if how=='linear' and rule==None:
            try:
                df = df.apply(signal.detrend, axis=0, type=how)
            except:
                df = df - trend(df, how=how, rule=rule, **kwargs)

        elif (any(w==how for w in ['block', 'blockaverage', 'blockmean'])) and (rule==None):
            try:
                df = df.apply(signal.detrend, axis=0, type='constant')
            except:
                df=df-trend(df, how=how, rule=rule, **kwargs)
        #-----------

        #-----------
        # If not, use our trending function
        else:
            df = df - trend(df, how=how, rule=rule, **kwargs)
        #-----------
    #-----------

    #-----------
    # We rename the columns names to indicate that they are fluctuations
    if units:
        newunits = { defs.fluctuations % el : units[el] if el in units.keys() else None for el in df.columns }
    #-----------
    
    #-----------
    # Rename the columns
    if suffix != '':
        df = df.rename(columns = lambda x: defs.fluctuations % x)
    #-----------

    #-----------
    # If units are not be changed in place, we copy them
    if units:
        if not inplace:
            units = units.copy()
        units.update(newunits)
    #-----------

    if inplace:
        return df
    else:
        return df, units