You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1454 lines
49 KiB
Python
1454 lines
49 KiB
Python
|
|
#-------------------------------------------------------------------------------
|
|
# Name: module1
|
|
# Purpose:
|
|
#
|
|
# Author: pab
|
|
#
|
|
# Created: 16.09.2008
|
|
# Copyright: (c) pab 2008
|
|
# Licence: <your licence>
|
|
#-------------------------------------------------------------------------------
|
|
#!/usr/bin/env python
|
|
|
|
|
|
from __future__ import division
|
|
import warnings
|
|
import numpy as np
|
|
|
|
from numpy import (inf, pi, zeros, ones, sqrt, where, log, exp, sin, arcsin, mod, #@UnresolvedImport
|
|
newaxis, linspace, arange, sort, all, abs, linspace, vstack, hstack, atleast_1d, #@UnresolvedImport
|
|
polyfit, r_, nonzero, cumsum, ravel, size, isnan, nan, floor, ceil, diff, array) #@UnresolvedImport
|
|
from numpy.fft import fft
|
|
from numpy.random import randn
|
|
from scipy.integrate import trapz
|
|
from pylab import stineman_interp
|
|
from matplotlib.mlab import psd
|
|
import scipy.signal
|
|
|
|
from scipy.special import erf
|
|
|
|
from wafo.misc import (nextpow2, findtp, findtc, findcross, sub_dict_select,
|
|
ecross, JITImport)
|
|
from wafodata import WafoData
|
|
from plotbackend import plotbackend
|
|
import matplotlib
|
|
matplotlib.interactive(True)
|
|
_wafocov = JITImport('wafo.covariance')
|
|
_wafospec = JITImport('wafo.spectrum')
|
|
|
|
__all__ = ['TimeSeries','LevelCrossings','CyclePairs','TurningPoints',
|
|
'sensortypeid','sensortype']
|
|
|
|
|
|
|
|
class LevelCrossings(WafoData):
|
|
'''
|
|
Container class for Level crossing data objects in WAFO
|
|
|
|
Member variables
|
|
----------------
|
|
data : array-like
|
|
number of upcrossings
|
|
args : array-like
|
|
crossing levels
|
|
|
|
'''
|
|
def __init__(self,*args,**kwds):
|
|
super(LevelCrossings, self).__init__(*args,**kwds)
|
|
self.labels.title = 'Level crossing spectrum'
|
|
self.labels.xlab = 'Levels'
|
|
self.labels.ylab = 'Count'
|
|
self.stdev = kwds.get('stdev',None)
|
|
self.mean = kwds.get('mean',None)
|
|
self.setplotter(plotmethod='step')
|
|
|
|
icmax = self.data.argmax()
|
|
if self.data != None:
|
|
if self.stdev is None or self.mean is None:
|
|
logcros = where(self.data==0.0, inf, -log(self.data))
|
|
logcmin = logcros[icmax]
|
|
logcros = sqrt(2*abs(logcros-logcmin))
|
|
logcros[0:icmax+1] = 2*logcros[icmax]-logcros[0:icmax+1]
|
|
p = polyfit(self.args[10:-9], logcros[10:-9],1) #least square fit
|
|
if self.stdev is None:
|
|
self.stdev = 1.0/p[0] #estimated standard deviation of x
|
|
if self.mean is None:
|
|
self.mean = -p[1]/p[0] #self.args[icmax]
|
|
cmax = self.data[icmax]
|
|
x = (self.args-self.mean)/self.stdev
|
|
y = cmax*exp(-x**2/2.0)
|
|
self.children = [WafoData(y,self.args)]
|
|
|
|
def sim(self,ns,alpha):
|
|
"""
|
|
Simulates process with given irregularity factor and crossing spectrum
|
|
|
|
Parameters
|
|
----------
|
|
ns : scalar, integer
|
|
number of sample points.
|
|
alpha : real scalar
|
|
irregularity factor, 0<alpha<1, small alpha gives
|
|
irregular process.
|
|
|
|
Returns
|
|
--------
|
|
ts : timeseries object
|
|
with times and values of the simulated process.
|
|
|
|
Example
|
|
-------
|
|
>>> import wafo.spectrum.models as sm
|
|
>>> Sj = sm.Jonswap(Hm0=7)
|
|
>>> S = Sj.tospecdata() #Make spectrum object from numerical values
|
|
>>> alpha = S.characteristic('alpha')[0]
|
|
>>> n = 10000
|
|
>>> xs = S.sim(ns=n)
|
|
>>> ts = mat2timeseries(xs)
|
|
>>> tp = ts.turning_points()
|
|
>>> mm = tp.cycle_pairs()
|
|
>>> lc = mm.level_crossings()
|
|
|
|
xs2 = lc.sim(n,alpha)
|
|
ts2 = mat2timeseries(xs2)
|
|
Se = ts2.tospecdata()
|
|
|
|
S.plot('b')
|
|
Se.plot('r')
|
|
alpha2 = Se.characteristic('alpha')[0]
|
|
alpha-alpha2
|
|
|
|
spec2char(Se,'alpha')
|
|
lc2 = dat2lc(xs2)
|
|
figure(gcf+1)
|
|
subplot(211)
|
|
lcplot(lc2)
|
|
subplot(212)
|
|
lcplot(lc)
|
|
"""
|
|
|
|
# TODO % add a good example
|
|
f = linspace(0,0.49999,1000)
|
|
rho_st = 2.*sin(f*pi)**2-1.
|
|
tmp = alpha*arcsin(sqrt((1.+rho_st)/2))
|
|
tmp = sin(tmp)**2
|
|
a2 = (tmp-rho_st)/(1-tmp)
|
|
y = vstack((a2+rho_st,1-a2)).min(axis=0)
|
|
maxidx = y.argmax()
|
|
#[maximum,maxidx]=max(y)
|
|
|
|
rho_st = rho_st[maxidx]
|
|
a2 = a2[maxidx]
|
|
a1 = 2.*rho_st+a2-1.
|
|
r0 = 1.
|
|
r1 = -a1/(1.+a2)
|
|
r2 = (a1**2-a2-a2**2)/(1+a2)
|
|
sigma2 = r0+a1*r1+a2*r2
|
|
#randn = np.random.randn
|
|
e = randn(ns)*sqrt(sigma2)
|
|
e[:1] = 0.0
|
|
L0 = randn(1)
|
|
L0 = vstack((L0,r1*L0+sqrt(1-r2**2)*randn(1)))
|
|
#%Simulate the process, starting in L0
|
|
lfilter = scipy.signal.lfilter
|
|
L = lfilter(1,[1, a1, a2],e,lfilter([1, a1, a2],1,L0))
|
|
|
|
epsilon = 1.01
|
|
min_L = min(L)
|
|
max_L = max(L)
|
|
maxi = max(abs(r_[min_L, max_L]))*epsilon
|
|
mini = -maxi
|
|
|
|
u = linspace(mini,maxi,101)
|
|
G = (1+erf(u/sqrt(2)))/2
|
|
G = G*(1-G)
|
|
|
|
x = linspace(0,r1,100)
|
|
factor1 = 1./sqrt(1-x**2)
|
|
factor2 = 1./(1+x)
|
|
integral = zeros(u.shape, dtype=float)
|
|
for i in range(len(integral)):
|
|
y = factor1*exp(-u[i]*u[i]*factor2)
|
|
integral[i] = trapz(x,y)
|
|
#end
|
|
G = G-integral/(2*pi)
|
|
G = G/max(G)
|
|
|
|
Z = ((u>=0)*2-1)*sqrt(-2*log(G))
|
|
|
|
## sumcr = trapz(lc(:,1),lc(:,2))
|
|
## lc(:,2) = lc(:,2)/sumcr
|
|
## mcr = trapz(lc(:,1),lc(:,1).*lc(:,2))
|
|
## scr = trapz(lc(:,1),lc(:,1).^2.*lc(:,2))
|
|
## scr = sqrt(scr-mcr^2)
|
|
## g = lc2tr(lc,mcr,scr)
|
|
##
|
|
## f = [u u]
|
|
## f(:,2) = tranproc(Z,fliplr(g))
|
|
##
|
|
## process = tranproc(L,f)
|
|
## process = [(1:length(process)) process]
|
|
##
|
|
##
|
|
## %Check the result without reference to getrfc:
|
|
## LCe = dat2lc(process)
|
|
## max(lc(:,2))
|
|
## max(LCe(:,2))
|
|
##
|
|
## clf
|
|
## plot(lc(:,1),lc(:,2)/max(lc(:,2)))
|
|
## hold on
|
|
## plot(LCe(:,1),LCe(:,2)/max(LCe(:,2)),'-.')
|
|
## title('Relative crossing intensity')
|
|
##
|
|
## %% Plot made by the function funplot_4, JE 970707
|
|
## %param = [min(process(:,2)) max(process(:,2)) 100]
|
|
## %plot(lc(:,1),lc(:,2)/max(lc(:,2)))
|
|
## %hold on
|
|
## %plot(levels(param),mu/max(mu),'--')
|
|
## %hold off
|
|
## %title('Crossing intensity')
|
|
## %watstamp
|
|
##
|
|
## % Temporarily
|
|
## %funplot_4(lc,param,mu)
|
|
|
|
|
|
def trdata(self, mean=None, sigma=None, **options):
|
|
'''
|
|
Estimate transformation, g, from observed crossing intensity, version2.
|
|
|
|
Assumption: a Gaussian process, Y, is related to the
|
|
non-Gaussian process, X, by Y = g(X).
|
|
|
|
Parameters
|
|
----------
|
|
options = structure with the fields:
|
|
csm, gsm - defines the smoothing of the crossing intensity and the
|
|
transformation g. Valid values must be
|
|
0<=csm,gsm<=1. (default csm = 0.9 gsm=0.05)
|
|
Smaller values gives smoother functions.
|
|
param - vector which defines the region of variation of the data X.
|
|
(default [-5 5 513]).
|
|
|
|
monitor monitor development of estimation
|
|
linextrap - 0 use a regular smoothing spline
|
|
1 use a smoothing spline with a constraint on the ends to
|
|
ensure linear extrapolation outside the range of the data.
|
|
(default)
|
|
cvar - Variances for the crossing intensity. (default 1)
|
|
gvar - Variances for the empirical transformation, g. (default 1)
|
|
ne - Number of extremes (maxima & minima) to remove from the
|
|
estimation of the transformation. This makes the
|
|
estimation more robust against outliers. (default 7)
|
|
Ntr - Maximum length of empirical crossing intensity.
|
|
The empirical crossing intensity is interpolated
|
|
linearly before smoothing if the length exceeds Ntr.
|
|
A reasonable NTR will significantly speed up the
|
|
estimation for long time series without loosing any
|
|
accuracy. NTR should be chosen greater than
|
|
PARAM(3). (default 1000)
|
|
Returns
|
|
-------
|
|
gs, ge : TrData objects
|
|
smoothed and empirical estimate of the transformation g.
|
|
ma,sa = mean and standard deviation of the process
|
|
|
|
Notes
|
|
-----
|
|
The empirical crossing intensity is usually very irregular.
|
|
More than one local maximum of the empirical crossing intensity
|
|
may cause poor fit of the transformation. In such case one
|
|
should use a smaller value of GSM or set a larger variance for GVAR.
|
|
If X(t) is likely to cross levels higher than 5 standard deviations
|
|
then the vector param has to be modified. For example if X(t) is
|
|
unlikely to cross a level of 7 standard deviations one can use
|
|
param = [-7 7 513].
|
|
|
|
Example
|
|
-------
|
|
Hm0 = 7
|
|
S = jonswap([],Hm0); g=ochitr([],[Hm0/4]);
|
|
S.tr = g; S.tr(:,2)=g(:,2)*Hm0/4;
|
|
xs = spec2sdat(S,2^13);
|
|
lc = dat2lc(xs)
|
|
g0 = lc2tr2(lc,0,Hm0/4,'plot','iter'); % Monitor the development
|
|
g1 = lc2tr2(lc,0,Hm0/4,troptset('gvar', .5 )); % Equal weight on all points
|
|
g2 = lc2tr2(lc,0,Hm0/4,'gvar', [3.5 .5 3.5]); % Less weight on the ends
|
|
hold on, trplot(g1,g) % Check the fit
|
|
trplot(g2)
|
|
|
|
See also troptset, dat2tr, trplot, findcross, smooth
|
|
|
|
NB! the transformated data will be N(0,1)
|
|
|
|
Reference
|
|
---------
|
|
Rychlik , I., Johannesson, P., and Leadbetter, M.R. (1997)
|
|
"Modelling and statistical analysis of ocean wavedata
|
|
using a transformed Gaussian process",
|
|
Marine structures, Design, Construction and Safety,
|
|
Vol 10, pp 13--47
|
|
'''
|
|
|
|
|
|
# Tested on: Matlab 5.3, 5.2, 5.1
|
|
# History:
|
|
# by pab 29.12.2000
|
|
# based on lc2tr, but the inversion is faster.
|
|
# by IR and PJ
|
|
pass
|
|
|
|
# opt = troptset('chkder','on','plotflag','off','csm',.9,'gsm',.05,....
|
|
# 'param',[-5 5 513],'delay',2,'linextrap','on','ntr',1000,'ne',7,'cvar',1,'gvar',1);
|
|
# # If just 'defaults' passed in, return the default options in g
|
|
# if nargin==1 && nargout <= 1 && isequal(cross,'defaults')
|
|
# g = opt;
|
|
# return
|
|
# end
|
|
# error(nargchk(3,inf,nargin))
|
|
# if nargin>=4 , opt = troptset(opt,varargin{:}); end
|
|
# csm2 = opt.gsm;
|
|
# param = opt.param;
|
|
# ptime = opt.delay;
|
|
# Ne = opt.ne;
|
|
# switch opt.chkder;
|
|
# case 'off', chkder = 0;
|
|
# case 'on', chkder = 1;
|
|
# otherwise, chkder = opt.chkder;
|
|
# end
|
|
# switch opt.linextrap;
|
|
# case 'off', def = 0;
|
|
# case 'on', def = 1;
|
|
# otherwise, def = opt.linextrap;
|
|
# end
|
|
# switch opt.plotflag
|
|
# case {'none','off'}, plotflag = 0;
|
|
# case 'final', plotflag = 1;
|
|
# case 'iter', plotflag = 2;
|
|
# otherwise, plotflag = opt.plotflag;
|
|
# end
|
|
# ncr = length(cross);
|
|
# if ncr>opt.ntr && opt.ntr>0,
|
|
# x0 = linspace(cross(1+Ne,1),cross(end-Ne,1),opt.ntr)';
|
|
# cros = [ x0,interp1q(cross(:,1),cross(:,2),x0)];
|
|
# Ne = 0;
|
|
# Ner = opt.ne;
|
|
# ncr = opt.ntr;
|
|
# else
|
|
# Ner = 0;
|
|
# cros=cross;
|
|
# end
|
|
#
|
|
# ng = length(opt.gvar);
|
|
# if ng==1
|
|
# gvar = opt.gvar(ones(ncr,1));
|
|
# else
|
|
# gvar = interp1(linspace(0,1,ng)',opt.gvar(:),linspace(0,1,ncr)','*linear');
|
|
# end
|
|
# ng = length(opt.cvar);
|
|
# if ng==1
|
|
# cvar = opt.cvar(ones(ncr,1));
|
|
# else
|
|
# cvar = interp1(linspace(0,1,ng)',opt.cvar(:),linspace(0,1,ncr)','*linear');
|
|
# end
|
|
#
|
|
# g = zeros(param(3),2);
|
|
#
|
|
# uu = levels(param);
|
|
#
|
|
# g(:,1) = sa*uu' + ma;
|
|
#
|
|
# g2 = cros;
|
|
#
|
|
# if Ner>0, # Compute correction factors
|
|
# cor1 = trapz(cross(1:Ner+1,1),cross(1:Ner+1,2));
|
|
# cor2 = trapz(cross(end-Ner-1:end,1),cross(end-Ner-1:end,2));
|
|
# else
|
|
# cor1 = 0;
|
|
# cor2 = 0;
|
|
# end
|
|
# cros(:,2) = cumtrapz(cros(:,1),cros(:,2))+cor1;
|
|
# cros(:,2) = (cros(:,2)+.5)/(cros(end,2) + cor2 +1);
|
|
# cros(:,1) = (cros(:,1)-ma)/sa;
|
|
#
|
|
# # find the mode
|
|
# [tmp,imin]= min(abs(cros(:,2)-.15));
|
|
# [tmp,imax]= min(abs(cros(:,2)-.85));
|
|
# inde = imin:imax;
|
|
# tmp = smooth(cros(inde,1),g2(inde,2),opt.csm,cros(inde,1),def,cvar(inde));
|
|
#
|
|
# [tmp imax] = max(tmp);
|
|
# u0 = cros(inde(imax),1);
|
|
# #u0 = interp1q(cros(:,2),cros(:,1),.5)
|
|
#
|
|
#
|
|
# cros(:,2) = invnorm(cros(:,2),-u0,1);
|
|
#
|
|
# g2(:,2) = cros(:,2);
|
|
# # NB! the smooth function does not always extrapolate well outside the edges
|
|
# # causing poor estimate of g
|
|
# # We may alleviate this problem by: forcing the extrapolation
|
|
# # to be linear outside the edges or choosing a lower value for csm2.
|
|
#
|
|
# inds = 1+Ne:ncr-Ne;# indices to points we are smoothing over
|
|
# scros2 = smooth(cros(inds,1),cros(inds,2),csm2,uu,def,gvar(inds));
|
|
#
|
|
# g(:,2) = scros2';#*sa; #multiply with stdev
|
|
#
|
|
# if chkder~=0
|
|
# for ix = 1:5
|
|
# dy = diff(g(:,2));
|
|
# if any(dy<=0)
|
|
# warning('WAFO:LCTR2','The empirical crossing spectrum is not sufficiently smoothed.')
|
|
# disp(' The estimated transfer function, g, is not ')
|
|
# disp(' a strictly increasing function.')
|
|
# dy(dy>0)=eps;
|
|
# gvar = -([dy;0]+[0;dy])/2+eps;
|
|
# g(:,2) = smooth(g(:,1),g(:,2),1,g(:,1),def,ix*gvar);
|
|
# else
|
|
# break
|
|
# end
|
|
# end
|
|
# end
|
|
# if 0, #either
|
|
# test = sqrt((param(2)-param(1))/(param(3)-1)*sum((uu-scros2).^2));
|
|
# else # or
|
|
# #test=sqrt(simpson(uu,(uu-scros2).^2));
|
|
# # or
|
|
# test=sqrt(trapz(uu,(uu-scros2).^2));
|
|
# end
|
|
#
|
|
#
|
|
# if plotflag>0,
|
|
# trplot(g ,g2,ma,sa)
|
|
# #legend(['Smoothed (T=' num2str(test) ')'],'g(u)=u','Not smoothed',0)
|
|
# #ylabel('Transfer function g(u)')
|
|
# #xlabel('Crossing level u')
|
|
#
|
|
# if plotflag>1,pause(ptime),end
|
|
# end
|
|
|
|
|
|
class CyclePairs(WafoData):
|
|
'''
|
|
Container class for Cycle Pairs data objects in WAFO
|
|
|
|
Member variables
|
|
----------------
|
|
data : array_like
|
|
args : vector for 1D
|
|
|
|
|
|
'''
|
|
def __init__(self, *args, **kwds):
|
|
super(CyclePairs, self).__init__(*args, **kwds)
|
|
self.type_ = kwds.get('type_', 'max2min')
|
|
self.stdev = kwds.get('stdev', None)
|
|
self.mean = kwds.get('mean', None)
|
|
|
|
self.labels.title = self.type_+ ' cycle pairs'
|
|
self.labels.xlab = 'min'
|
|
self.labels.ylab = 'max'
|
|
|
|
def amplitudes(self):
|
|
return (self.data-self.args)/2.
|
|
|
|
def damage(self, beta, K=1):
|
|
"""
|
|
Calculates the total Palmgren-Miner damage of cycle pairs.
|
|
|
|
Parameters
|
|
----------
|
|
beta : array-like, size m
|
|
Beta-values, material parameter.
|
|
K : scalar, optional
|
|
K-value, material parameter.
|
|
|
|
Returns
|
|
-------
|
|
D : ndarray, size m
|
|
Damage.
|
|
|
|
Notes
|
|
-----
|
|
The damage is calculated according to
|
|
D[i] = sum ( K * a**beta[i] ), with a = (max-min)/2
|
|
|
|
Examples
|
|
--------
|
|
>>> import wafo
|
|
>>> from matplotlib import pyplot as plt
|
|
>>> ts = wafo.objects.mat2timeseries(wafo.data.sea())
|
|
>>> tp = ts.turning_points()
|
|
>>> mm = tp.cycle_pairs()
|
|
>>> h = mm.plot('.')
|
|
>>> bv = range(3,9)
|
|
>>> D = mm.damage(beta=bv)
|
|
>>> D
|
|
array([ 138.5238799 , 117.56050788, 108.99265423, 107.86681126,
|
|
112.3791076 , 122.08375071])
|
|
>>> h = plt.plot(bv,D,'x-')
|
|
|
|
See also
|
|
--------
|
|
SurvivalCycleCount
|
|
"""
|
|
amp = abs(self.amplitudes())
|
|
return atleast_1d([K*np.sum(amp**betai) for betai in beta])
|
|
|
|
def level_crossings(self, type_='uM'):
|
|
""" Return number of upcrossings from a cycle count.
|
|
|
|
Parameters
|
|
----------
|
|
type_ : int or string
|
|
defining crossing type, options are
|
|
0,'u' : only upcrossings.
|
|
1,'uM' : upcrossings and maxima (default).
|
|
2,'umM': upcrossings, minima, and maxima.
|
|
3,'um' :upcrossings and minima.
|
|
Return
|
|
------
|
|
lc : level crossing object
|
|
with levels and number of upcrossings.
|
|
|
|
|
|
Calculates the number of upcrossings from a cycle pairs, e.g.
|
|
min2Max cycles or rainflow cycles.
|
|
|
|
Example:
|
|
--------
|
|
>>> import wafo
|
|
>>> ts = wafo.objects.mat2timeseries(wafo.data.sea())
|
|
>>> tp = ts.turning_points()
|
|
>>> mm = tp.cycle_pairs()
|
|
>>> h = mm.plot('.')
|
|
>>> lc = mm.level_crossings()
|
|
>>> h2 = lc.plot()
|
|
|
|
See also
|
|
--------
|
|
TurningPoints
|
|
LevelCrossings
|
|
"""
|
|
|
|
if isinstance(type_, str):
|
|
t = dict(u=0, uM=1, umM=2, um=3)
|
|
defnr = t.get(type_, 1)
|
|
else:
|
|
defnr = type_
|
|
|
|
if ((defnr<0) or (defnr>3)):
|
|
raise ValueError('type_ must be one of (1,2,3,4).')
|
|
|
|
index, = nonzero(self.args <= self.data)
|
|
if index.size == 0:
|
|
index, = nonzero(self.args >= self.data)
|
|
M = self.args[index]
|
|
m = self.data[index]
|
|
else:
|
|
m = self.args[index]
|
|
M = self.data[index]
|
|
|
|
#if isempty(index)
|
|
# error('Error in input cc.')
|
|
#end
|
|
ncc = len(m)
|
|
#ones = np.ones
|
|
#zeros = np.zeros
|
|
#cumsum = np.cumsum
|
|
minima = vstack((m, ones(ncc), zeros(ncc), ones(ncc)))
|
|
maxima = vstack((M, -ones(ncc), ones(ncc), zeros(ncc)))
|
|
|
|
extremes = hstack((maxima, minima))
|
|
index = extremes[0].argsort()
|
|
extremes = extremes[:, index]
|
|
|
|
ii = 0
|
|
n = extremes.shape[1]
|
|
extr = zeros((4, n))
|
|
extr[:, 0] = extremes[:, 0]
|
|
for i in xrange(1, n):
|
|
if extremes[0, i] == extr[0, ii]:
|
|
extr[1:4, ii] = extr[1:4, ii] + extremes[1:4, i]
|
|
else:
|
|
ii += 1
|
|
extr[:, ii] = extremes[:, i]
|
|
|
|
#[xx nx]=max(extr(:,1))
|
|
nx = extr[0].argmax()+1
|
|
levels = extr[0, 0:nx]
|
|
if defnr == 2: ## This are upcrossings + maxima
|
|
dcount = cumsum(extr[1, 0:nx]) + extr[2, 0:nx]-extr[3, 0:nx]
|
|
elif defnr == 4: # # This are upcrossings + minima
|
|
dcount = cumsum(extr[1, 0:nx])
|
|
dcount[nx-1] = dcount[nx-2]
|
|
elif defnr == 1: ## This are only upcrossings
|
|
dcount = cumsum(extr[1, 0:nx]) - extr[3, 0:nx]
|
|
elif defnr == 3: ## This are upcrossings + minima + maxima
|
|
dcount = cumsum(extr[1, 0:nx]) + extr[2, 0:nx]
|
|
return LevelCrossings(dcount, levels, stdev=self.stdev)
|
|
|
|
class TurningPoints(WafoData):
|
|
'''
|
|
Container class for Turning Points data objects in WAFO
|
|
|
|
Member variables
|
|
----------------
|
|
data : array_like
|
|
args : vector for 1D
|
|
|
|
|
|
'''
|
|
def __init__(self, *args, **kwds):
|
|
super(TurningPoints, self).__init__(*args, **kwds)
|
|
self.name='WAFO TurningPoints Object'
|
|
somekeys = ['name']
|
|
self.__dict__.update(sub_dict_select(kwds, somekeys))
|
|
|
|
#self.setlabels()
|
|
if not any(self.args):
|
|
n = len(self.data)
|
|
self.args = range(0, n)
|
|
else:
|
|
self.args = ravel(self.args)
|
|
self.data= ravel(self.data)
|
|
|
|
def cycle_pairs(self, type_='min2max'):
|
|
""" Return min2Max or Max2min cycle pairs from turning points
|
|
|
|
Parameters
|
|
----------
|
|
type_ : string
|
|
type of cycles to return options are 'min2max' or 'max2min'
|
|
|
|
Return
|
|
------
|
|
mm : cycles object
|
|
with min2Max or Max2min cycle pairs.
|
|
|
|
Example
|
|
-------
|
|
>>> import wafo
|
|
>>> x = wafo.data.sea()
|
|
>>> ts = wafo.objects.mat2timeseries(x)
|
|
>>> tp = ts.turning_points()
|
|
>>> mM = tp.cycle_pairs()
|
|
>>> h = mM.plot('.')
|
|
|
|
|
|
See also
|
|
--------
|
|
TurningPoints
|
|
SurvivalCycleCount
|
|
"""
|
|
if self.data[0]>self.data[1]:
|
|
im = 1
|
|
iM = 0
|
|
else:
|
|
im = 0
|
|
iM = 1
|
|
|
|
# Extract min-max and max-min cycle pairs
|
|
#n = len(self.data)
|
|
if type_.lower().startswith('min2max'):
|
|
m = self.data[im:-1:2]
|
|
M = self.data[im+1::2]
|
|
else:
|
|
type_ = 'max2min'
|
|
M = self.data[iM:-1:2]
|
|
m = self.data[iM+1::2]
|
|
|
|
return CyclePairs(M, m, type=type_)
|
|
|
|
def mat2timeseries(x):
|
|
"""
|
|
Convert 2D arrays to TimeSeries object
|
|
assuming 1st column is time and the remaining columns contain data.
|
|
"""
|
|
return TimeSeries(x[:, 1::], x[:, 0].ravel())
|
|
|
|
class TimeSeries(WafoData):
|
|
'''
|
|
Container class for 1D TimeSeries data objects in WAFO
|
|
|
|
Member variables
|
|
----------------
|
|
data : array_like
|
|
args : vector for 1D, list of vectors for 2D, 3D, ...
|
|
|
|
sensortypes : list of integers or strings
|
|
sensor type for time series (default ['n'] : Surface elevation)
|
|
see sensortype for more options
|
|
position : vector of size 3
|
|
instrument position relative to the coordinate system
|
|
|
|
Examples
|
|
--------
|
|
>>> import wafo.data
|
|
>>> x = wafo.data.sea()
|
|
>>> ts = mat2timeseries(x)
|
|
>>> rf = ts.tocovdata(lag=150)
|
|
>>> h = rf.plot()
|
|
|
|
'''
|
|
def __init__(self, *args, **kwds):
|
|
super(TimeSeries, self).__init__(*args, **kwds)
|
|
self.name = 'WAFO TimeSeries Object'
|
|
self.sensortypes = ['n', ]
|
|
self.position = zeros(3)
|
|
somekeys = ['sensortypes', 'position']
|
|
self.__dict__.update(sub_dict_select(kwds, somekeys))
|
|
|
|
#self.setlabels()
|
|
if not any(self.args):
|
|
n = len(self.data)
|
|
self.args = range(0, n)
|
|
|
|
def sampling_period(self):
|
|
'''
|
|
Returns sampling interval
|
|
|
|
Returns
|
|
-------
|
|
dt : scalar
|
|
sampling interval, unit:
|
|
[s] if lagtype=='t'
|
|
[m] otherwise
|
|
|
|
See also
|
|
'''
|
|
dt1 = self.args[1]-self.args[0]
|
|
n = size(self.args)-1
|
|
t = self.args[-1]-self.args[0]
|
|
dt = t/n
|
|
if abs(dt-dt1) > 1e-10:
|
|
warnings.warn('Data is not uniformly sampled!')
|
|
return dt
|
|
|
|
def tocovdata(self, lag=None, flag='biased', norm=False, dt = None):
|
|
'''
|
|
Return auto covariance function from data.
|
|
|
|
Parameters
|
|
----------
|
|
lag : scalar, int
|
|
maximum time-lag for which the ACF is estimated. (Default lag=n-1)
|
|
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).
|
|
|
|
Return
|
|
-------
|
|
R : CovData1D object
|
|
with attributes:
|
|
data : ACF vector length L+1
|
|
args : time lags length L+1
|
|
stdev : 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
|
|
>>> x = wafo.data.sea()
|
|
>>> ts = mat2timeseries(x)
|
|
>>> acf = ts.tocovdata(150)
|
|
>>> h = acf.plot()
|
|
'''
|
|
n = len(self.data)
|
|
if not lag:
|
|
lag = n-1
|
|
|
|
x = self.data.flatten()
|
|
indnan = isnan(x)
|
|
if any(indnan):
|
|
x = x - x[1-indnan].mean() # remove the mean pab 09.10.2000
|
|
#indnan = find(indnan)
|
|
Ncens = n - sum(indnan)
|
|
x[indnan] = 0. # pab 09.10.2000 much faster for censored samples
|
|
else:
|
|
indnan = None
|
|
Ncens = n
|
|
x = x - x.mean()
|
|
|
|
#fft = np.fft.fft
|
|
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!
|
|
lags = range(0,lag+1)
|
|
if flag.startswith('unbiased'):
|
|
# unbiased result, i.e. divide by n-abs(lag)
|
|
R = R[lags]*Ncens/arange(Ncens, Ncens-lag, -1)
|
|
#else % biased result, i.e. divide by n
|
|
# r=r(1:L+1)*Ncens/Ncens
|
|
|
|
c0 = R[0]
|
|
if norm:
|
|
R = R/c0
|
|
if dt is None:
|
|
dt = self.sampling_period()
|
|
t = linspace(0,lag*dt,lag+1)
|
|
#cumsum = np.cumsum
|
|
acf = _wafocov.CovData1D(R[lags],t)
|
|
acf.stdev=sqrt(r_[ 0, 1 ,1+2*cumsum(R[1:]**2)]/Ncens)
|
|
acf.children = [WafoData(-2.*acf.stdev[lags],t),WafoData(2.*acf.stdev[lags],t)]
|
|
acf.norm = norm
|
|
return acf
|
|
|
|
def tospecdata(self,*args,**kwargs):
|
|
"""
|
|
Return power spectral density by Welches average periodogram method.
|
|
|
|
Parameters
|
|
----------
|
|
NFFT : int, scalar
|
|
if len(data) < NFFT, it will be zero padded to `NFFT`
|
|
before estimation. Must be even; a power 2 is most efficient.
|
|
detrend : function
|
|
Fs : real, scalar
|
|
sampling frequency (samples per time unit).
|
|
|
|
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.
|
|
noverlap : scalar int
|
|
gives the length of the overlap between segments.
|
|
|
|
Returns
|
|
-------
|
|
S : SpecData1D
|
|
Power Spectral Density
|
|
|
|
Notes
|
|
-----
|
|
The data vector is divided into NFFT length segments. Each segment
|
|
is detrended by function detrend and windowed by function window.
|
|
noverlap gives the length of the overlap between segments. The
|
|
absolute(fft(segment))**2 of each segment are averaged to compute Pxx,
|
|
with a scaling to correct for power loss due to windowing.
|
|
|
|
Reference
|
|
---------
|
|
Bendat & Piersol (1986) Random Data: Analysis and Measurement
|
|
Procedures, John Wiley & Sons
|
|
"""
|
|
fs = 1./(2*self.sampling_period())
|
|
S, f = psd(self.data.ravel(), Fs=fs, *args, **kwargs)
|
|
fact = 2.0*pi
|
|
w = fact*f
|
|
return _wafospec.SpecData1D(S/fact, w)
|
|
|
|
def turning_points(self,h=0.0,wavetype=None):
|
|
'''
|
|
Return turning points (tp) from data, optionally rainflowfiltered.
|
|
|
|
Parameters
|
|
----------
|
|
h : scalar
|
|
a threshold
|
|
if h<=0, then tp is a sequence of turning points (default)
|
|
if h>0, then all rainflow cycles with height smaller than
|
|
h are removed.
|
|
|
|
wavetype : string
|
|
defines the type of wave. Possible options are
|
|
'mw' 'Mw' or 'none'.
|
|
If None all rainflow filtered min and max
|
|
will be returned, otherwise only the rainflow filtered
|
|
min and max, which define a wave according to the
|
|
wave definition, will be returned.
|
|
|
|
Returns
|
|
-------
|
|
tp : TurningPoints object
|
|
with times and turning points.
|
|
|
|
Example:
|
|
>>> import wafo.data
|
|
>>> x = wafo.data.sea()
|
|
>>> x1 = x[:200,:]
|
|
>>> ts1 = mat2timeseries(x1)
|
|
>>> tp = ts1.turning_points(wavetype='Mw')
|
|
>>> tph = ts1.turning_points(h=0.3,wavetype='Mw')
|
|
>>> hs = ts1.plot()
|
|
>>> hp = tp.plot('ro')
|
|
>>> hph = tph.plot('k.')
|
|
|
|
See also
|
|
---------
|
|
findcross,
|
|
findrfc
|
|
findtp
|
|
'''
|
|
ind = findtp(self.data, max(h,0.0), wavetype)
|
|
try:
|
|
t = self.args[ind]
|
|
except:
|
|
t = ind
|
|
return TurningPoints(self.data[ind],t)
|
|
|
|
def trough_crest(self,v=None,wavetype=None):
|
|
"""
|
|
Return trough and crest turning points
|
|
|
|
Parameters
|
|
-----------
|
|
v : scalar
|
|
reference level (default v = mean of x).
|
|
|
|
wavetype : string
|
|
defines the type of wave. Possible options are
|
|
'dw', 'uw', 'tw', 'cw' or None.
|
|
If None indices to all troughs and crests will be returned,
|
|
otherwise only the paired ones will be returned
|
|
according to the wavedefinition.
|
|
|
|
Returns
|
|
--------
|
|
tc : TurningPoints object
|
|
with trough and crest turningpoints
|
|
"""
|
|
ind = findtc(self.data, v, wavetype)[0]
|
|
try:
|
|
t = self.args[ind]
|
|
except:
|
|
t = ind
|
|
return TurningPoints(self.data[ind], t)
|
|
|
|
def wave_periods(self, vh=None, pdef='d2d', wdef=None, index=None, rate=1):
|
|
"""
|
|
Return sequence of wave periods/lengths from data.
|
|
|
|
Parameters
|
|
----------
|
|
vh : scalar
|
|
reference level ( default v=mean(x(:,2)) ) or
|
|
rainflow filtering height (default h=0)
|
|
pdef : string
|
|
defining type of waveperiod (wavelength) returned:
|
|
Level v separated 't2c', 'c2t', 't2t' or 'c2c' -waveperiod.
|
|
Level v 'd2d', 'u2u', 'd2u' or 'u2d' -waveperiod.
|
|
Rain flow filtered (with height greater than h)
|
|
'm2M', 'M2m', 'm2m' or 'M2M' -waveperiod.
|
|
Explanation to the abbreviations:
|
|
M=Max, m=min, d=down-crossing, u=up-crossing ,
|
|
t=trough and c=crest.
|
|
Thus 'd2d' means period between a down-crossing to the
|
|
next down-crossing and 'u2c' means period between a
|
|
u-crossing to the following crest.
|
|
wdef : string
|
|
defining type of wave. Possible options are
|
|
'mw','Mw','dw', 'uw', 'tw', 'cw' or None.
|
|
If wdef is None all troughs and crests will be used,
|
|
otherwise only the troughs and crests which define a
|
|
wave according to the wavedefinition are used.
|
|
|
|
index : vector
|
|
index sequence of one of the following :
|
|
-level v-crossings (indices to "du" are required to
|
|
calculate 'd2d', 'd2u', 'u2d' or 'u2u' waveperiods)
|
|
-level v separated trough and crest turningpoints
|
|
(indices to 'tc' are required to calculate
|
|
't2t', 't2c', 'c2t' or 'c2c' waveperiods)
|
|
-level v crossings and level v separated trough and
|
|
crest turningpoints (indices to "dutc" are
|
|
required to calculate t2u, u2c, c2d or d2t
|
|
waveperiods)
|
|
-rainflow filtered turningpoints with minimum rfc height h
|
|
(indices to "mMtc" are required to calculate
|
|
'm2m', 'm2M', 'M2m' or 'M2M' waveperiods)
|
|
|
|
rate : scalar
|
|
interpolation rate. If rate larger than one, then x is
|
|
interpolated before extrating T
|
|
|
|
Returns
|
|
--------
|
|
T : vector
|
|
sequence of waveperiods (or wavelengths).
|
|
index : vector
|
|
of indices
|
|
|
|
|
|
Example:
|
|
--------
|
|
>>> import wafo
|
|
>>> x = wafo.data.sea()
|
|
>>> ts = wafo.objects.mat2timeseries(x[0:400,:])
|
|
>>> T = ts.wave_periods(vh=0.0,pdef='c2c')
|
|
|
|
T = dat2wa(x1,0,'c2c') #% Returns crest2crest waveperiods
|
|
subplot(121), waveplot(x1,'-',1,1),subplot(122),histgrm(T)
|
|
|
|
See also:
|
|
--------
|
|
findtp,
|
|
findtc,
|
|
findcross, perioddef
|
|
"""
|
|
|
|
##% This is a more flexible version than the dat2hwa or tp2wa routines.
|
|
##% There is a secret option: if pdef='all' the function returns
|
|
##% all the waveperiods 'd2t', 't2u', 'u2c' and 'c2d' in sequence.
|
|
##% It is up to the user to extract the right waveperiods.
|
|
##% If the first is a down-crossing then the first is a 'd2t' waveperiod.
|
|
##% If the first is a up-crossing then the first is a 'u2c' waveperiod.
|
|
##%
|
|
##% Example:
|
|
##% [T ind]=dat2wa(x,0,'all') %returns all waveperiods
|
|
##% nn = length(T)
|
|
##% % want to extract all t2u waveperiods
|
|
##% if x(ind(1),2)>0 % if first is down-crossing
|
|
##% Tt2u=T(2:4:nn)
|
|
##% else % first is up-crossing
|
|
##% Tt2u=T(4:4:nn)
|
|
##% end
|
|
|
|
if rate>1: #% interpolate with spline
|
|
n = ceil(self.data.size*rate)
|
|
ti = linspace(self.args[0], self.args[-1], n)
|
|
x = stineman_interp(ti, self.args, self.data)
|
|
else:
|
|
x = self.data
|
|
ti = self.args
|
|
|
|
|
|
if vh is None:
|
|
if pdef[0] in ('m','M'):
|
|
vh = 0
|
|
print(' The minimum rfc height, h, is set to: %g' % vh)
|
|
else:
|
|
vh = x.mean()
|
|
print(' The level l is set to: %g' % vh)
|
|
|
|
|
|
if index is None:
|
|
if pdef in ('m2m', 'm2M', 'M2m','M2M'):
|
|
index = findtp(x, vh, wdef)
|
|
elif pdef in ('u2u','u2d','d2u', 'd2d'):
|
|
index = findcross(x, vh, wdef)
|
|
elif pdef in ('t2t','t2c','c2t', 'c2c'):
|
|
index = findtc(x,vh,wdef)[0]
|
|
elif pdef in ('d2t','t2u', 'u2c', 'c2d','all'):
|
|
index, v_ind = findtc(x, vh, wdef)
|
|
index = sort(r_[index, v_ind]) #% sorting crossings and tp in sequence
|
|
else:
|
|
raise ValueError('Unknown pdef option!')
|
|
|
|
if (x[index[0]]>x[index[1]]): #% if first is down-crossing or max
|
|
if pdef in ('d2t', 'M2m', 'c2t', 'd2u' , 'M2M', 'c2c', 'd2d', 'all'):
|
|
start = 1
|
|
elif pdef in ('t2u', 'm2M', 't2c', 'u2d' ,'m2m', 't2t', 'u2u'):
|
|
start = 2
|
|
elif pdef in ('u2c'):
|
|
start = 3
|
|
elif pdef in ('c2d'):
|
|
start = 4
|
|
else:
|
|
raise ValueError('Unknown pdef option!')
|
|
# else first is up-crossing or min
|
|
elif pdef in ('all', 'u2c', 'm2M', 't2c', 'u2d', 'm2m', 't2t', 'u2u'):
|
|
start = 0
|
|
elif pdef in ('c2d', 'M2m', 'c2t', 'd2u', 'M2M', 'c2c', 'd2d'):
|
|
start = 1
|
|
elif pdef in ('d2t'):
|
|
start = 2
|
|
elif pdef in ('t2u'):
|
|
start = 3
|
|
else:
|
|
raise ValueError('Unknown pdef option!')
|
|
|
|
# determine the steps between wanted periods
|
|
if pdef in ('d2t', 't2u', 'u2c', 'c2d' ):
|
|
step = 4
|
|
elif pdef in ('all'):
|
|
step = 1 #% secret option!
|
|
else:
|
|
step = 2
|
|
|
|
#% determine the distance between min2min, t2t etc..
|
|
if pdef in ('m2m', 't2t', 'u2u', 'M2M', 'c2c', 'd2d'):
|
|
dist = 2
|
|
else:
|
|
dist = 1
|
|
|
|
nn = len(index)
|
|
#% New call: (pab 28.06.2001)
|
|
if pdef[0] in ('u', 'd'):
|
|
t0 = ecross(ti, x, index[start:(nn-dist):step], vh)
|
|
else: # % min, Max, trough, crest or all crossings wanted
|
|
t0 = x[index[start:(nn-dist):step]]
|
|
|
|
if pdef[2] in ('u','d'):
|
|
t1 = ecross(ti, x, index[(start+dist):nn:step], vh)
|
|
else: # % min, Max, trough, crest or all crossings wanted
|
|
t1 = x[index[(start+dist):nn:step]]
|
|
|
|
T = t1 - t0
|
|
## if False: #% Secret option: indices to the actual crossings used.
|
|
## index=index.ravel()
|
|
## ind = [index(start:(nn-dist):step) index((start+dist):nn:step)].'
|
|
## ind = ind(:)
|
|
|
|
|
|
return T, index
|
|
|
|
#% Old call: kept just in case
|
|
#%T = x(index((start+dist):step:nn),1)-x(index(start:step:(nn-dist)),1)
|
|
|
|
|
|
|
|
def reconstruct(self):
|
|
pass
|
|
def plot_wave(self, sym1='k.', ts=None, sym2='k+', nfig=None, nsub=None,
|
|
stdev=None, vfact=3):
|
|
'''
|
|
Plots the surface elevation of timeseries.
|
|
|
|
Parameters
|
|
----------
|
|
sym1, sym2 : string
|
|
plot symbol and color for data and ts, respectively
|
|
(see PLOT) (default 'k.' and 'k+')
|
|
ts : TimeSeries or TurningPoints object
|
|
to overplot data. default zero-separated troughs and crests.
|
|
nsub : scalar integer
|
|
Number of subplots in each figure. By default nsub is such that
|
|
there are about 20 mean down crossing waves in each subplot.
|
|
If nfig is not given and nsub is larger than 6 then nsub is
|
|
changed to nsub=min(6,ceil(nsub/nfig))
|
|
nfig : scalar integer
|
|
Number of figures. By default nfig=ceil(Nsub/6).
|
|
stdev : real scalar
|
|
standard deviation of data.
|
|
vfact : real scalar
|
|
how large in stdev the vertical scale should be (default 3)
|
|
|
|
|
|
Example
|
|
-------
|
|
Plot x1 with red lines and mark troughs and crests with blue circles.
|
|
>>> import wafo
|
|
>>> x = wafo.data.sea()
|
|
>>> ts150 = wafo.objects.mat2timeseries(x[:150,:])
|
|
>>> h = ts150.plot_wave('r-', sym2='bo')
|
|
|
|
See also
|
|
--------
|
|
findtc, plot
|
|
'''
|
|
# TODO: finish reconstruct
|
|
nw = 20
|
|
tn = self.args
|
|
xn = self.data.ravel()
|
|
indmiss = isnan(xn) # indices to missing points
|
|
indg = where(1-indmiss)[0]
|
|
if ts is None:
|
|
tc_ix = findtc(xn[indg],0,'tw')[0]
|
|
xn2 = xn[tc_ix]
|
|
tn2 = tn[tc_ix]
|
|
else:
|
|
xn2 = ts.data
|
|
tn2 = ts.args
|
|
|
|
if stdev is None:
|
|
stdev = xn[indg].std()
|
|
|
|
if nsub is None:
|
|
nsub = int(floor(len(xn2)/(2*nw)))+1 # about Nw mdc waves in each plot
|
|
if nfig is None:
|
|
nfig = int(ceil(nsub/6))
|
|
nsub = min(6,int(ceil(nsub/nfig)))
|
|
|
|
n = len(xn)
|
|
Ns = int(floor(n/(nfig*nsub)))
|
|
ind = r_[0:Ns]
|
|
if all(xn>=0):
|
|
vscale = [0, 2*stdev*vfact]
|
|
else:
|
|
vscale = array([-1, 1])*vfact*stdev
|
|
|
|
|
|
XlblTxt = 'Time [sec]'
|
|
dT = 1
|
|
timespan = tn[ind[-1]]-tn[ind[0]]
|
|
if abs(timespan)>18000: # more than 5 hours
|
|
dT = 1/(60*60)
|
|
XlblTxt = 'Time (hours)'
|
|
elif abs(timespan)>300:# more than 5 minutes
|
|
dT = 1/60
|
|
XlblTxt = 'Time (minutes)'
|
|
|
|
if np.max(abs(xn[indg]))>5*stdev:
|
|
XlblTxt = XlblTxt +' (Spurious data since max > 5 std.)'
|
|
|
|
plot = plotbackend.plot
|
|
subplot = plotbackend.subplot
|
|
figs = []
|
|
for iz in xrange(nfig):
|
|
figs.append(plotbackend.figure())
|
|
plotbackend.title('Surface elevation from mean water level (MWL).')
|
|
for ix in xrange(nsub):
|
|
if nsub>1:
|
|
subplot(nsub,1,ix)
|
|
|
|
h_scale = array([tn[ind[0]], tn[ind[-1]]])
|
|
ind2 = where((h_scale[0]<=tn2) & (tn2<=h_scale[1]))[0]
|
|
plot(tn[ind]*dT, xn[ind], sym1)
|
|
if len(ind2)>0:
|
|
plot(tn2[ind2]*dT,xn2[ind2],sym2)
|
|
plot(h_scale*dT, [0, 0], 'k-')
|
|
#plotbackend.axis([h_scale*dT, v_scale])
|
|
|
|
for iy in [-2, 2]:
|
|
plot(h_scale*dT, iy*stdev*ones(2), ':')
|
|
|
|
ind = ind + Ns
|
|
#end
|
|
plotbackend.xlabel(XlblTxt)
|
|
|
|
return figs
|
|
|
|
|
|
def plot_sp_wave(self, wave_idx_, tz_idx=None, *args, **kwds):
|
|
"""
|
|
Plot specified wave(s) from timeseries
|
|
|
|
wave_idx : integer vector
|
|
of indices to waves we want to plot, i.e., wave numbers.
|
|
tz_idx : integer vector
|
|
of indices to the beginning, middle and end of
|
|
defining wave, i.e. for zero-downcrossing waves, indices to
|
|
zerocrossings (default trough2trough wave)
|
|
|
|
Examples
|
|
--------
|
|
Plot waves nr. 6,7,8 and waves nr. 12,13,...,17
|
|
>>> import wafo
|
|
>>> x = wafo.data.sea()
|
|
>>> ts = wafo.objects.mat2timeseries(x[0:500,...])
|
|
>>> h = ts.plot_sp_wave(np.r_[6:9,12:18])
|
|
|
|
|
|
See also
|
|
--------
|
|
plot_wave, findtc
|
|
"""
|
|
wave_idx = atleast_1d(wave_idx_).flatten()
|
|
if tz_idx is None:
|
|
tc_ind, tz_idx = findtc(self.data,0,'tw') # finding trough to trough waves
|
|
|
|
dw = nonzero(abs(diff(wave_idx))>1)[0]
|
|
Nsub = dw.size+1
|
|
Nwp = zeros(Nsub, dtype=int)
|
|
if Nsub>1:
|
|
dw = dw + 1
|
|
Nwp[Nsub-1] = wave_idx[-1]-wave_idx[dw[-1]]+1
|
|
wave_idx[dw[-1]+1:] = -2
|
|
for ix in range(Nsub-2,1,-2):
|
|
Nwp[ix] = wave_idx[dw[ix]-1] - wave_idx[dw[ix-1]]+1 # # of waves pr subplot
|
|
wave_idx[dw[ix-1]+1:dw[ix]] = -2
|
|
|
|
Nwp[0] = wave_idx[dw[0]-1] - wave_idx[0]+1
|
|
wave_idx[1:dw[0]] = -2
|
|
wave_idx = wave_idx[wave_idx>-1]
|
|
else:
|
|
Nwp[0] = wave_idx[-1]-wave_idx[0]+1
|
|
#end
|
|
|
|
Nsub = min(6,Nsub)
|
|
Nfig = int(ceil(Nsub/6))
|
|
Nsub = min(6,int(ceil(Nsub/Nfig)))
|
|
figs = []
|
|
for iy in range(Nfig):
|
|
figs.append(plotbackend.figure())
|
|
for ix in range(Nsub):
|
|
plotbackend.subplot(Nsub,1,mod(ix,Nsub)+1)
|
|
ind = r_[tz_idx[2*wave_idx[ix]-1]:tz_idx[2*wave_idx[ix]+2*Nwp[ix]-1]]
|
|
## indices to wave
|
|
plotbackend.plot(self.args[ind],self.data[ind],*args,**kwds)
|
|
plotbackend.hold('on')
|
|
xi = [self.args[ind[0]],self.args[ind[-1]]]
|
|
plotbackend.plot(xi,[0, 0])
|
|
|
|
if Nwp[ix]==1:
|
|
plotbackend.ylabel('Wave %d' % wave_idx[ix])
|
|
else:
|
|
plotbackend.ylabel('Wave %d - %d' % (wave_idx[ix], wave_idx[ix]+Nwp[ix]-1))
|
|
|
|
plotbackend.xlabel('Time [sec]')
|
|
#wafostamp
|
|
return figs
|
|
|
|
def sensortypeid(*sensortypes):
|
|
''' Return ID for sensortype name
|
|
|
|
Parameter
|
|
---------
|
|
sensortypes : list of strings defining the sensortype
|
|
|
|
Returns
|
|
-------
|
|
sensorids : list of integers defining the sensortype
|
|
|
|
Valid senor-ids and -types for time series are as follows:
|
|
0, 'n' : Surface elevation (n=Eta)
|
|
1, 'n_t' : Vertical surface velocity
|
|
2, 'n_tt' : Vertical surface acceleration
|
|
3, 'n_x' : Surface slope in x-direction
|
|
4, 'n_y' : Surface slope in y-direction
|
|
5, 'n_xx' : Surface curvature in x-direction
|
|
6, 'n_yy' : Surface curvature in y-direction
|
|
7, 'n_xy' : Surface curvature in xy-direction
|
|
8, 'P' : Pressure fluctuation about static MWL pressure
|
|
9, 'U' : Water particle velocity in x-direction
|
|
10, 'V' : Water particle velocity in y-direction
|
|
11, 'W' : Water particle velocity in z-direction
|
|
12, 'U_t' : Water particle acceleration in x-direction
|
|
13, 'V_t' : Water particle acceleration in y-direction
|
|
14, 'W_t' : Water particle acceleration in z-direction
|
|
15, 'X_p' : Water particle displacement in x-direction from its mean position
|
|
16, 'Y_p' : Water particle displacement in y-direction from its mean position
|
|
17, 'Z_p' : Water particle displacement in z-direction from its mean position
|
|
|
|
Example:
|
|
>>> sensortypeid('W','v')
|
|
[11, 10]
|
|
>>> sensortypeid('rubbish')
|
|
[1.#QNAN]
|
|
|
|
See also
|
|
--------
|
|
sensortype
|
|
'''
|
|
|
|
sensorid_table = dict(n=0, n_t=1, n_tt=2, n_x=3, n_y=4, n_xx=5,
|
|
n_yy=6, n_xy=7, p=8, u=9, v=10, w=11, u_t=12,
|
|
v_t=13, w_t=14, x_p=15, y_p=16, z_p=17)
|
|
try:
|
|
return [sensorid_table.get(name.lower(), nan) for name in sensortypes]
|
|
except:
|
|
raise ValueError('Input must be a string!')
|
|
|
|
|
|
|
|
def sensortype(*sensorids):
|
|
'''
|
|
Return sensortype name
|
|
|
|
Parameter
|
|
---------
|
|
sensorids : vector or list of integers defining the sensortype
|
|
|
|
Returns
|
|
-------
|
|
sensornames : tuple of strings defining the sensortype
|
|
Valid senor-ids and -types for time series are as follows:
|
|
0, 'n' : Surface elevation (n=Eta)
|
|
1, 'n_t' : Vertical surface velocity
|
|
2, 'n_tt' : Vertical surface acceleration
|
|
3, 'n_x' : Surface slope in x-direction
|
|
4, 'n_y' : Surface slope in y-direction
|
|
5, 'n_xx' : Surface curvature in x-direction
|
|
6, 'n_yy' : Surface curvature in y-direction
|
|
7, 'n_xy' : Surface curvature in xy-direction
|
|
8, 'P' : Pressure fluctuation about static MWL pressure
|
|
9, 'U' : Water particle velocity in x-direction
|
|
10, 'V' : Water particle velocity in y-direction
|
|
11, 'W' : Water particle velocity in z-direction
|
|
12, 'U_t' : Water particle acceleration in x-direction
|
|
13, 'V_t' : Water particle acceleration in y-direction
|
|
14, 'W_t' : Water particle acceleration in z-direction
|
|
15, 'X_p' : Water particle displacement in x-direction from its mean position
|
|
16, 'Y_p' : Water particle displacement in y-direction from its mean position
|
|
17, 'Z_p' : Water particle displacement in z-direction from its mean position
|
|
|
|
Example:
|
|
>>> sensortype(range(3))
|
|
('n', 'n_t', 'n_tt')
|
|
|
|
See also
|
|
--------
|
|
sensortypeid, tran
|
|
'''
|
|
valid_names = ('n', 'n_t', 'n_tt', 'n_x', 'n_y', 'n_xx', 'n_yy', 'n_xy',
|
|
'p', 'u', 'v', 'w', 'u_t', 'v_t', 'w_t', 'x_p', 'y_p', 'z_p',
|
|
nan)
|
|
ids = atleast_1d(*sensorids)
|
|
if isinstance(ids, list):
|
|
ids = hstack(ids)
|
|
n = len(valid_names) - 1
|
|
ids = where(((ids<0) | (n<ids)), n , ids)
|
|
|
|
#try:
|
|
return tuple(valid_names[i] for i in ids)
|
|
#except:
|
|
# raise ValueError('Input must be an integer!')
|
|
|
|
def main0():
|
|
import wafo
|
|
ts = wafo.objects.mat2timeseries(wafo.data.sea())
|
|
tp = ts.turning_points()
|
|
mm = tp.cycle_pairs()
|
|
lc = mm.level_crossings()
|
|
lc.plot()
|
|
T = ts.wave_periods(vh=0.0,pdef='c2c')
|
|
|
|
|
|
|
|
#main()
|
|
import wafo.spectrum.models as sm
|
|
Sj = sm.Jonswap()
|
|
S = Sj.tospecdata()
|
|
|
|
R = S.tocovdata()
|
|
x = R.sim(ns=1000,dt=0.2)
|
|
S.characteristic(['hm0','tm02'])
|
|
ns = 1000
|
|
dt = .2
|
|
x1 = S.sim(ns,dt=dt)
|
|
|
|
ts = TimeSeries(x1[:,1],x1[:,0])
|
|
tp = ts.turning_points(0.0)
|
|
|
|
x = np.arange(-2,2,0.2)
|
|
|
|
# Plot 2 objects in one call
|
|
d2 = WafoData(np.sin(x),x,xlab='x',ylab='sin',title='sinus')
|
|
|
|
|
|
d0 = d2.copy()
|
|
d0.data = d0.data*0.9
|
|
d1 = d2.copy()
|
|
d1.data = d1.data*1.2
|
|
d1.children = [d0]
|
|
d2.children = [d1]
|
|
|
|
d2.plot()
|
|
print 'Done'
|
|
|
|
def main():
|
|
sensortype(range(21))
|
|
|
|
if __name__ == '__main__':
|
|
if True: #False : #
|
|
import doctest
|
|
doctest.testmod()
|
|
else:
|
|
main()
|
|
|