Included autoregressive prediction on horizontal components

This commit is contained in:
Ludger Küperkoch 2014-11-20 09:05:30 +01:00
parent fbce83293d
commit 03033f57a1

View File

@ -17,6 +17,7 @@ autoregressive prediction: application ot local and regional distances, Geophys.
""" """
import numpy as np import numpy as np
from obspy.core import Stream from obspy.core import Stream
import scipy
class CharacteristicFunction(object): class CharacteristicFunction(object):
''' '''
@ -46,10 +47,10 @@ class CharacteristicFunction(object):
:type: float (optional, only for AR) :type: float (optional, only for AR)
''' '''
assert isinstance(data, Stream), "%s is not a Stream object" % str(data) assert isinstance(data, Stream), "%s is not a stream object" % str(data)
self.orig_data = data[0] self.orig_data = data
self.dt = self.orig_data.stats.delta self.dt = self.orig_data[0].stats.delta
self.setCut(cut) self.setCut(cut)
self.setTime1(t1) self.setTime1(t1)
self.setTime2(t2) self.setTime2(t2)
@ -118,26 +119,33 @@ class CharacteristicFunction(object):
cutting window cutting window
''' '''
if cut is not None: if cut is not None:
if self.cut[0] == 0: if self.cut[0] == 0:
start = 0 start = 0
else: else:
start = self.cut[0] / self.dt start = self.cut[0] / self.dt
stop = self.cut[1] / self.dt stop = self.cut[1] / self.dt
data = self.orig_data.data[start:stop] if len(self.orig_data) == 1:
return data data = self.orig_data[0].data[start:stop]
return data
return self.orig_data.data elif len(self.orig_data) == 2:
hh = self.orig_data.copy()
h1 = hh[0].copy()
h2 = hh[1].copy()
hh[0].data = h1.data[start:stop]
hh[1].data = h2.data[start:stop]
data = hh
return data
else:
if len(self.orig_data) == 1:
data = self.orig_data[0]
return data
elif len(self.orig_data) == 2:
data = self.orig_data
return data
def calcCF(self, data=None): def calcCF(self, data=None):
self.cf = data self.cf = data
def arDet(self, data, order, rind, ldet):
pass
def arPred(self, data, arpara, rind, lpred):
pass
class AICcf(CharacteristicFunction): class AICcf(CharacteristicFunction):
''' '''
@ -150,6 +158,7 @@ class AICcf(CharacteristicFunction):
''' '''
def calcCF(self, data): def calcCF(self, data):
print 'Calculating AIC ...' print 'Calculating AIC ...'
xnp = self.getDataArray() xnp = self.getDataArray()
datlen = len(xnp) datlen = len(xnp)
@ -180,7 +189,6 @@ class HOScf(CharacteristicFunction):
def calcCF(self, data): def calcCF(self, data):
xnp = self.getDataArray(self.getCut()) xnp = self.getDataArray(self.getCut())
if self.getOrder() == 3: # this is skewness if self.getOrder() == 3: # this is skewness
print 'Calculating skewness ...' print 'Calculating skewness ...'
y = np.power(xnp, 3) y = np.power(xnp, 3)
@ -190,22 +198,22 @@ class HOScf(CharacteristicFunction):
y = np.power(xnp, 4) y = np.power(xnp, 4)
y1 = np.power(xnp, 2) y1 = np.power(xnp, 2)
# Initialisation #Initialisation
# t2: long term moving window #t2: long term moving window
ilta = round(self.getTime2() / self.getIncrement()) ilta = round(self.getTime2() / self.getIncrement())
lta = y[0] lta = y[0]
lta1 = y1[0] lta1 = y1[0]
# moving windows #moving windows
LTA = np.zeros(len(xnp)) LTA = np.zeros(len(xnp))
for j in range(3, len(xnp)): for j in range(3, len(xnp)):
if j <= ilta: if j <= ilta:
lta = (y[j] + lta * (j - 1)) / j lta = (y[j] + lta * (j-1)) / j
lta1 = (y1[j] + lta1 * (j - 1)) / j lta1 = (y1[j] + lta1 * (j-1)) / j
else: else:
lta = (y[j] - y[j - ilta]) / ilta + lta lta = (y[j] - y[j - ilta]) / ilta + lta
lta1 = (y1[j] - y1[j - ilta]) / ilta + lta1 lta1 = (y1[j] - y1[j - ilta]) / ilta + lta1
# define LTA #define LTA
if self.getOrder() == 3: if self.getOrder() == 3:
LTA[j] = lta / np.power(lta1, 1.5) LTA[j] = lta / np.power(lta1, 1.5)
elif self.getOrder() == 4: elif self.getOrder() == 4:
@ -222,39 +230,38 @@ class ARZcf(CharacteristicFunction):
print 'Calculating AR-prediction error from single trace ...' print 'Calculating AR-prediction error from single trace ...'
xnp = self.getDataArray(self.getCut()) xnp = self.getDataArray(self.getCut())
#some parameters needed
# some parameters needed #add noise to time series
# add noise to time series
xnoise = xnp + np.random.normal(0.0, 1.0, len(xnp)) * self.getFnoise() * max(abs(xnp)) xnoise = xnp + np.random.normal(0.0, 1.0, len(xnp)) * self.getFnoise() * max(abs(xnp))
tend = len(xnp) tend = len(xnp)
# Time1: length of AR-determination window [sec] #Time1: length of AR-determination window [sec]
# Time2: length of AR-prediction window [sec] #Time2: length of AR-prediction window [sec]
ldet = int(round(self.getTime1() / self.getIncrement())) # length of AR-determination window [samples] ldet = int(round(self.getTime1() / self.getIncrement())) #length of AR-determination window [samples]
lpred = int(np.ceil(self.getTime2() / self.getIncrement())) # length of AR-prediction window [samples] lpred = int(np.ceil(self.getTime2() / self.getIncrement())) #length of AR-prediction window [samples]
cf = [] cf = []
step = ldet + self.getOrder() - 1 step = ldet + self.getOrder() - 1
for i in range(ldet + self.getOrder() - 1, tend - lpred + 1): for i in range(ldet + self.getOrder() - 1, tend - lpred + 1):
if i == step: if i == step:
''' '''
In order to speed up the algorithm AR parameters are kept for time In order to speed up the algorithm AR parameters are kept for time
intervals of length lpred intervals of length ldet
''' '''
# determination of AR coefficients #determination of AR coefficients
self.arDet(xnoise, self.getOrder(), i - ldet, i) self.arDetZ(xnoise, self.getOrder(), i-ldet, i)
step = step + lpred step = step + ldet
# AR prediction of waveform using calculated AR coefficients #AR prediction of waveform using calculated AR coefficients
self.arPred(xnp, self.arpara, i + 1, lpred) self.arPredZ(xnp, self.arpara, i + 1, lpred)
# prediction error = CF #prediction error = CF
err = np.sqrt(np.sum(np.power(self.xpred[i:i + lpred] - xnp[i:i + lpred], 2)) / lpred) err = np.sqrt(np.sum(np.power(self.xpred[i:i + lpred] - xnp[i:i + lpred], 2)) / lpred)
cf.append(err) cf.append(err)
# convert list to numpy array #convert list to numpy array
cf = np.asarray(cf) cf = np.asarray(cf)
self.cf = cf self.cf = cf
def arDet(self, data, order, rind, ldet): def arDetZ(self, data, order, rind, ldet):
''' '''
Function to calculate AR parameters arpara after Thomas Meier (CAU), published Function to calculate AR parameters arpara after Thomas Meier (CAU), published
in Kueperkoch et al. (2012). This function solves SLE using the Moore- in Kueperkoch et al. (2012). This function solves SLE using the Moore-
@ -274,27 +281,27 @@ class ARZcf(CharacteristicFunction):
Output: AR parameters arpara Output: AR parameters arpara
''' '''
# recursive calculation of data vector (right part of eq. 6.5 in Kueperkoch et al. (2012) #recursive calculation of data vector (right part of eq. 6.5 in Kueperkoch et al. (2012)
rhs = np.zeros(self.getOrder()) rhs = np.zeros(self.getOrder())
for k in range(0, self.getOrder()): for k in range(0, self.getOrder()):
for i in range(rind, ldet): for i in range(rind, ldet):
rhs[k] = rhs[k] + data[i] * data[i - k] rhs[k] = rhs[k] + data[i] * data[i - k]
# recursive calculation of data array (second sum at left part of eq. 6.5 in Kueperkoch et al. 2012) #recursive calculation of data array (second sum at left part of eq. 6.5 in Kueperkoch et al. 2012)
A = np.array([[0, 0], [0, 0]]) A = np.zeros((2,2))
for k in range(1, self.getOrder() + 1): for k in range(1, self.getOrder() + 1):
for j in range(1, k + 1): for j in range(1, k + 1):
for i in range(rind, ldet): for i in range(rind, ldet):
ki = k - 1 ki = k - 1
ji = j - 1 ji = j - 1
A[ki, ji] = A[ki, ji] + data[i - ji] * data[i - ki] A[ki,ji] = A[ki,ji] + data[i - ji] * data[i - ki]
A[ji, ki] = A[ki, ji] A[ji,ki] = A[ki,ji]
# apply Moore-Penrose inverse for SVD yielding the AR-parameters #apply Moore-Penrose pseudo inverse for SVD yielding the AR-parameters
self.arpara = np.dot(np.linalg.pinv(A), rhs) self.arpara = np.dot(np.linalg.pinv(A), rhs)
def arPred(self, data, arpara, rind, lpred): def arPredZ(self, data, arpara, rind, lpred):
''' '''
Function to predict waveform, assuming an autoregressive process of order Function to predict waveform, assuming an autoregressive process of order
p (=size(arpara)), with AR parameters arpara calculated in arDet. After p (=size(arpara)), with AR parameters arpara calculated in arDet. After
@ -313,7 +320,7 @@ class ARZcf(CharacteristicFunction):
Output: predicted waveform z Output: predicted waveform z
''' '''
# be sure of the summation indeces #be sure of the summation indeces
if rind < len(arpara) + 1: if rind < len(arpara) + 1:
rind = len(arpara) + 1 rind = len(arpara) + 1
if rind > len(data) - lpred + 1: if rind > len(data) - lpred + 1:
@ -334,8 +341,134 @@ class ARZcf(CharacteristicFunction):
class ARHcf(CharacteristicFunction): class ARHcf(CharacteristicFunction):
pass def calcCF(self, data):
print 'Calculating AR-prediction error from both horizontal traces ...'
xnp = self.getDataArray(self.getCut())
#some parameters needed
#add noise to time series
xenoise = xnp[0].data + np.random.normal(0.0, 1.0, len(xnp[0].data)) * self.getFnoise() * max(abs(xnp[0].data))
xnnoise = xnp[1].data + np.random.normal(0.0, 1.0, len(xnp[1].data)) * self.getFnoise() * max(abs(xnp[1].data))
Xnoise = np.array( [xenoise.tolist(), xnnoise.tolist()] )
tend = len(xnp[0].data)
#Time1: length of AR-determination window [sec]
#Time2: length of AR-prediction window [sec]
ldet = int(round(self.getTime1() / self.getIncrement())) #length of AR-determination window [samples]
lpred = int(np.ceil(self.getTime2() / self.getIncrement())) #length of AR-prediction window [samples]
cf = []
arstep = ldet + self.getOrder() - 3
for i in range(ldet + self.getOrder() - 3, tend - lpred + 1):
if i == arstep:
'''
In order to speed up the algorithm AR parameters are kept for time
intervals of length ldet
'''
#determination of AR coefficients
self.arDetH(Xnoise, self.getOrder(), i-ldet, i)
arstep = arstep + ldet
#AR prediction of waveform using calculated AR coefficients
self.arPredH(xnp, self.arpara, i + 1, lpred)
#prediction error = CF
err = np.sqrt(np.sum(np.power(self.xpred[0][i:i + lpred] - xnp[0][i:i + lpred], 2) \
+ np.power(self.xpred[1][i:i + lpred] - xnp[1][i:i + lpred], 2)) / (2 * lpred))
cf.append(err)
#convert list to numpy array
cf = np.asarray(cf)
self.cf = cf
def arDetH(self, data, order, rind, ldet):
'''
Function to calculate AR parameters arpara after Thomas Meier (CAU), published
in Kueperkoch et al. (2012). This function solves SLE using the Moore-
Penrose inverse, i.e. the least-squares approach. "data" is a structured array.
AR parameters are calculated based on both horizontal components in order
to account for polarization.
:param: data, horizontal component seismograms to calculate AR parameters from
:type: structured array
:param: order, order of AR process
:type: int
:param: rind, first running summation index
:type: int
:param: ldet, length of AR-determination window (=end of summation index)
:type: int
Output: AR parameters arpara
'''
#recursive calculation of data vector (right part of eq. 6.5 in Kueperkoch et al. (2012)
rhs = np.zeros(self.getOrder())
for k in range(0, self.getOrder()):
for i in range(rind, ldet):
rhs[k] = rhs[k] + data[0,i] * data[0,i - k] + data[1,i] * data[1,i - k]
#recursive calculation of data array (second sum at left part of eq. 6.5 in Kueperkoch et al. 2012)
A = np.zeros((4,4))
for k in range(1, self.getOrder() + 1):
for j in range(1, k + 1):
for i in range(rind, ldet):
ki = k - 1
ji = j - 1
A[ki,ji] = A[ki,ji] + data[0,i - ji] * data[0,i - ki] + data[1,i - ji] *data[1,i - ki]
A[ji,ki] = A[ki,ji]
#apply Moore-Penrose pseudo inverse for SVD yielding the AR-parameters
#self.arpara = np.dot(np.linalg.pinv(A), rhs)
#self.arpara = np.linalg.solve(A, rhs)
#arpara = scipy.linalg.lstsq(A, rhs)
#arpara = np.linalg.lstsq(A, rhs)
#self.arpara = arpara[0]
self.arpara = np.dot(scipy.linalg.pinv(A), rhs)
def arPredH(self, data, arpara, rind, lpred):
'''
Function to predict waveform, assuming an autoregressive process of order
p (=size(arpara)), with AR parameters arpara calculated in arDet. After
Thomas Meier (CAU), published in Kueperkoch et al. (2012).
:param: data, horizontal component seismograms to be predicted
:type: structured array
:param: arpara, AR parameters
:type: float
:param: rind, first running summation index
:type: int
:param: lpred, length of prediction window (=end of summation index)
:type: int
Output: predicted waveform z
:type: structured array
'''
#be sure of the summation indeces
if rind < len(arpara) + 1:
rind = len(arpara) + 1
if rind > len(data[0]) - lpred + 1:
rind = len(data[0]) - lpred + 1
if lpred < 1:
lpred = 1
if lpred > len(data[0]) - 1:
lpred = len(data[0]) - 1
z1 = np.append(data[0][0:rind], np.zeros(lpred))
z2 = np.append(data[1][0:rind], np.zeros(lpred))
for i in range(rind, rind + lpred):
for j in range(1, len(arpara) + 1):
ji = j - 1
z1[i] = z1[i] + arpara[ji] * z1[i - ji]
z2[i] = z2[i] + arpara[ji] * z2[i - ji]
z = np.array( [z1.tolist(), z2.tolist()] )
self.xpred = z
class AR3Ccf(CharacteristicFunction): class AR3Ccf(CharacteristicFunction):