|
|
|
"""
|
|
|
|
Created on 10. mai 2014
|
|
|
|
|
|
|
|
@author: pab
|
|
|
|
"""
|
|
|
|
import numpy as np
|
|
|
|
from numpy.fft import fft
|
|
|
|
from wafo.misc import nextpow2
|
|
|
|
from scipy.signal.windows import get_window
|
|
|
|
from wafo.containers import PlotData
|
|
|
|
from wafo.covariance import CovData1D
|
|
|
|
import warnings
|
|
|
|
|
|
|
|
|
|
|
|
def sampling_period(t_vec):
|
|
|
|
"""
|
|
|
|
Returns sampling interval
|
|
|
|
|
|
|
|
Returns
|
|
|
|
-------
|
|
|
|
dt : scalar
|
|
|
|
sampling interval, unit:
|
|
|
|
[s] if lagtype=='t'
|
|
|
|
[m] otherwise
|
|
|
|
|
|
|
|
See also
|
|
|
|
"""
|
|
|
|
dt1 = t_vec[1] - t_vec[0]
|
|
|
|
n = len(t_vec) - 1
|
|
|
|
t = t_vec[-1] - t_vec[0]
|
|
|
|
dt = t / n
|
|
|
|
if abs(dt - dt1) > 1e-10:
|
|
|
|
warnings.warn('Data is not uniformly sampled!')
|
|
|
|
return dt
|
|
|
|
|
|
|
|
|
|
|
|
class CovarianceEstimator(object):
|
|
|
|
"""
|
|
|
|
Class for estimating AutoCovariance from timeseries
|
|
|
|
|
|
|
|
Parameters
|
|
|
|
----------
|
|
|
|
lag : scalar, int
|
|
|
|
maximum time-lag for which the ACF is estimated.
|
|
|
|
(Default lag where ACF is zero)
|
|
|
|
tr : transformation object
|
|
|
|
the transformation assuming that x is a sample of a transformed
|
|
|
|
Gaussian process. If g is None then x is a sample of a Gaussian
|
|
|
|
process (Default)
|
|
|
|
detrend : function
|
|
|
|
defining detrending performed on the signal before estimation.
|
|
|
|
(default detrend_mean)
|
|
|
|
window : vector of length NFFT or function
|
|
|
|
To create window vectors see numpy.blackman, numpy.hamming,
|
|
|
|
numpy.bartlett, scipy.signal, scipy.signal.get_window etc.
|
|
|
|
flag : string, 'biased' or 'unbiased'
|
|
|
|
If 'unbiased' scales the raw correlation by 1/(n-abs(k)),
|
|
|
|
where k is the index into the result, otherwise scales the raw
|
|
|
|
cross-correlation by 1/n. (default)
|
|
|
|
norm : bool
|
|
|
|
True if normalize output to one
|
|
|
|
dt : scalar
|
|
|
|
time-step between data points (default see sampling_period).
|
|
|
|
"""
|
|
|
|
def __init__(self, lag=None, tr=None, detrend=None, window='boxcar',
|
|
|
|
flag='biased', norm=False, dt=None):
|
|
|
|
self.lag = lag
|
|
|
|
self.tr = tr
|
|
|
|
self.detrend = detrend
|
|
|
|
self.window = window
|
|
|
|
self.flag = flag
|
|
|
|
self.norm = norm
|
|
|
|
self.dt = dt
|
|
|
|
|
|
|
|
def _estimate_lag(self, R, Ncens):
|
|
|
|
Lmax = min(300, len(R) - 1) # maximum lag if L is undetermined
|
|
|
|
# finding where ACF is less than 2 st. deviations.
|
|
|
|
sigma = np.sqrt(np.r_[0, R[0] ** 2,
|
|
|
|
R[0] ** 2 + 2 * np.cumsum(R[1:] ** 2)] / Ncens)
|
|
|
|
lag = Lmax + 2 - (np.abs(R[Lmax::-1]) > 2 * sigma[Lmax::-1]).argmax()
|
|
|
|
if self.window == 'parzen':
|
|
|
|
lag = int(4 * lag / 3)
|
|
|
|
# print('The default L is set to %d' % L)
|
|
|
|
return lag
|
|
|
|
|
|
|
|
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
|
|
|
|
auto_cov = np.real(fft(raw_periodogram)) / nfft # ifft = fft/nfft since raw_periodogram is real!
|
|
|
|
|
|
|
|
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
|
|
|
|
|
|
|
|
__call__ = tocovdata
|