SignalFilters/Code_Python/synthetic.py

191 wiersze
5.5 KiB
Python

"""
Utility functions for ????.
Copyright (c) 2020 Gabriele Gilardi
"""
import numpy as np
def normalize_data(X, param=(), ddof=0):
"""
If mu and sigma are not defined, returns a column-normalized version of
X with zero mean and standard deviation equal to one. If mu and sigma are
defined returns a column-normalized version of X using mu and sigma.
X Input dataset
Xn Column-normalized input dataset
param Tuple with mu and sigma
mu Mean
sigma Standard deviation
ddof Delta degrees of freedom (if ddof = 0 then divide by m, if
ddof = 1 then divide by m-1, with m the number of data in X)
"""
# Column-normalize using mu and sigma
if (len(param) > 0):
Xn = (X - param[0]) / param[1]
return Xn
# Column-normalize using mu=0 and sigma=1
else:
mu = X.mean(axis=0)
sigma = X.std(axis=0, ddof=ddof)
Xn = (X - mu) / sigma
param = (mu, sigma)
return Xn, param
def scale_data(X, param=()):
"""
If X_min and X_max are not defined, returns a column-scaled version of
X in the interval (-1,+1). If X_min and X_max are defined returns a
column-scaled version of X using X_min and X_max.
X Input dataset
Xs Column-scaled input dataset
param Tuple with X_min and X_max
X_min Min. value along the columns (features) of the input dataset
X_max Max. value along the columns (features) of the input dataset
"""
# Column-scale using X_min and X_max
if (len(param) > 0):
Xs = -1.0 + 2.0 * (X - param[0]) / (param[1] - param[0])
return Xs
# Column-scale using X_min=-1 and X_max=+1
else:
X_min = np.amin(X, axis=0)
X_max = np.amax(X, axis=0)
Xs = -1.0 + 2.0 * (X - X_min) / (X_max - X_min)
param = (X_min, X_max)
return Xs, param
def value2diff(X, mode=None):
"""
from value to difference in abs or %
diff in value first element is zero
diff in % first element is one
"""
# Difference in value
if (mode == 'V'):
dX = np.zeros_like(X)
dX[1:, :] = X[1:, :] - X[:-1, :]
# Difference in percent
else:
dX = np.ones_like(X)
dX[1:, :] = X[1:, :] / X[:-1, :] - 1.0
return dX
def diff2value(dX, mode=None):
"""
from difference in abs or % to value (first row should be all zeros but
will be over-written
Reference X[0,:] is assumed to be zero. If X0[0,:] is the desired
reference, the actual vector X can be determined as X0+X
Reference X[0,:] is assumed to be one. If X0[0,:] is the desired
reference, the actual vector X can be determined as X0*X
"""
# Value from the difference (first row equal to zero)
# X[0, :] = 0
# X[1, :] = X[0, :] + dX[1, :] = dX[1, :]
# X[2, :] = X[0, :] + dX[1, :] + dX[2, :] = dX[1, :] + dX[2, :]
# ....
if (mode == 'V'):
X = np.zeros_like(dX)
X[1:, :] = np.cumsum(dX[1:, :], axis=0)
# Value from percent (first row equal to 1)
# X[0, :] = 1
# X[1, :] = X[0, :] * (1 + dX[1, :]) = (1 + dX[1, :])
# X[2, :] = X[1, :] * (1 + dX[2, :])
# = X[0, :] * (1 + dX[1, :]) * (1 + dX[2, :])
# = (1 + dX[1, :]) * (1 + dX[2, :])
# ....
else:
X = np.ones_like(dX)
X[1:, :] = np.cumprod((1.0 + dX), axis=0)
return X
def synthetic_wave(per, amp=None, pha=None, num=1000):
"""
Generates a multi-sinewave.
P = [ P1 P2 ... Pn ] Periods
A = [ A1 A2 ... An ] Amplitudes
PH = [PH1 PH2 ... PHn] Phases (rad)
Default amplitudes are ones
Default phases are zeros
Time is from 0 to largest period (default 1000 steps)
"""
n_waves = len(per)
per = np.asarray(per)
# Define amplitudes and phases
if (amp is None):
amp = np.ones(n_waves)
else:
amp = np.asarray(amp)
if (pha is None):
pha = np.zeros(n_waves)
else:
pha = np.asarray(pha)
# Add all the waves
t = np.linspace(0.0, np.amax(per), num=num)
f = np.zeros(len(t))
for i in range(n_waves):
f = f + amp[i] * np.sin(2.0 * np.pi * t / per[i] + pha[i])
return t, f
def synthetic_series(X, multiv=False):
"""
"""
n_samples, n_series = data.shape
# The number of samples must be odd (if the number is even drop the last value)
if ((n_samples % 2) == 0):
print("Warning: data reduced by one (even number of samples)")
n_samples = n_samples - 1
X = X[0:n_samples, :]
# FFT of the original data
X_fft = np.fft.fft(X, axis=0)
# Parameters
half_len = (n_samples - 1) // 2
idx1 = np.arange(1, half_len+1, dtype=int)
idx2 = np.arange(half_len+1, n_samples, dtype=int)
# If multivariate the random phases is the same
if (multiv):
phases = np.random.rand(half_len, 1)
phases1 = np.tile(np.exp(2.0 * np.pi * 1j * phases), (1, n_series))
phases2 = np.conj(np.flipud(phases1))
# If univariate the random phases is different
else:
phases = np.random.rand(half_len, n_series)
phases1 = np.exp(2.0 * np.pi * 1j * phases)
phases2 = np.conj(np.flipud(phases1))
# FFT of the synthetic data
synt_fft = X_fft.copy()
synt_fft[idx1, :] = X_fft[idx1, :] * phases1
synt_fft[idx2, :] = X_fft[idx2, :] * phases2
# Inverse FFT of the synthetic data
X_synt = np.real(np.fft.ifft(synt_fft, axis=0))
return X_synt