def partion_data(data, Rest=2, Ntr=1, Ntr_steady=1): y = data['y'] u = data['u'] lines = data['lines'] fs = data['fs'] npp, p, R, P = y.shape freq = np.arange(npp) / npp * fs # partitioning the data. Use last period of two last realizations. # test for performance testing and val for model selection utest = u[:, :, -1, -1] ytest = y[:, :, -1, -1] uval = u[:, :, -1, -1] yval = y[:, :, -1, -1] # all other realizations are used for estimation uest = u[..., :Rest, Ntr_steady:] yest = y[..., :Rest, Ntr_steady:] # noise estimate over periods. This sets the performace limit for the # estimated model covY = covariance(yest) # create signal object sig = Signal(uest, yest, fs=fs) sig.lines = lines # plot periodicity for one realization to verify data is steady state # sig.periodicity() # Calculate BLA, total- and noise distortion. Used for subspace # identification sig.bla() # average signal over periods. Used for training of PNLSS model um, ym = sig.average() return Data(sig, uest, yest, uval, yval, utest, ytest, um, ym, covY, freq, lines, npp, Ntr)
def simulate(true_model, npp=1024, Ntr=1, Rest=2, add_noise=False): print() print(f'Nonlinear parameters:', f'{len(true_model.nlx.active) + len(true_model.nly.active)}') print(f'Parameters to estimate: {true_model.npar}') # set non-active coefficients to zero. Note order of input matters idx = np.setdiff1d(np.arange(true_model.E.size), true_model.nlx.active) idy = np.setdiff1d(np.arange(true_model.F.size), true_model.nly.active) true_model.E.flat[idx] = 0 true_model.F.flat[idy] = 0 # get predictable random numbers. https://dilbert.com/strip/2001-10-25 np.random.seed(10) # shape of u from multisine: (R,P*npp) u, lines, freq = multisine(N=npp, P=P, R=R, lines=kind, rms=RMSu) # Transient: Add Ntr periods before the start of each realization. To # generate steady state data. T1 = np.r_[npp * Ntr, np.r_[0:(R - 1) * P * npp + 1:P * npp]] _, yorig, _ = true_model.simulate(u.ravel(), T1=T1) u = u.reshape((R, P, npp)).transpose((2, 0, 1))[:, None] # (npp,m,R,P) y = yorig.reshape((R, P, npp, p)).transpose((2, 3, 0, 1)) # Add colored noise to the output. randn generate white noise if add_noise: np.random.seed(10) noise = 1e-3 * np.std(y[:, -1, -1]) * np.random.randn(*y.shape) # Do some filtering to get colored noise noise[1:-2] += noise[2:-1] y += noise ## START of Identification ## # partitioning the data. Use last period of two last realizations. # test for performance testing and val for model selection utest = u[:, :, -1, -1] ytest = y[:, :, -1, -1] uval = u[:, :, -2, -1] yval = y[:, :, -2, -1] # all other realizations are used for estimation uest = u[..., :Rest, :] yest = y[..., :Rest, :] # noise estimate over periods. This sets the performace limit for the # estimated model covY = covariance(yest) # create signal object sig = Signal(uest, yest, fs=fs) sig.lines = lines # plot periodicity for one realization to verify data is steady state # sig.periodicity() # Calculate BLA, total- and noise distortion. Used for subspace # identification sig.bla() # average signal over periods. Used for training of PNLSS model um, ym = sig.average() return Data(sig, uest, yest, uval, yval, utest, ytest, um, ym, covY, freq, lines, npp, Ntr)
utest = u[:, :, -1, -1] ytest = y[:, :, -1, -1] uval = u[:, :, -2, -1] yval = y[:, :, -2, -1] # all other realizations are used for estimation uest = u[..., :-2, :] yest = y[..., :-2, :] # noise estimate over periods. This sets the performace limit for the estimated # model covY = covariance(yest) npp, p, Rest, Pest = yest.shape npp, m, Rest, Pest = uest.shape Ptr = 5 # number of periods to use for transient handling during simulation # create signal object sig = Signal(uest, yest, fs=fs) sig.lines = lines # plot periodicity for one realization to verify data is steady state # sig.periodicity() # Calculate BLA, total- and noise distortion. Used for subspace identification sig.bla() # average signal over periods. Used for training of PNLSS model um, ym = sig.average() # model orders and Subspace dimensioning parameter nvec = [3] maxr = 10 if 'linmodel' not in locals() or True: linmodel = Subspace(sig) linmodel.estimate(2, maxr, weight=weight)
import numpy as np import matplotlib.pyplot as plt import pickle from collections import namedtuple from pyvib.signal import Signal from pyvib.rfs import RFS path = 'data/' filename = 'pyds_sweepvrms' Nm = namedtuple('Nm', 'y yd ydd u t finst fs ns') #sweep_l = pickle.load(open(path + filename + '0.01' + '.pkl', 'rb')) sweep_h = pickle.load(open(path + filename + '2' + '.pkl', 'rb')) signal = Signal(sweep_h.u, sweep_h.fs, sweep_h.ydd) signal.set_signal(y=sweep_h.y, yd=sweep_h.yd, ydd=sweep_h.ydd) rfs = RFS(signal, dof=0) rfs.plot() # extract force slice/subplot for saving # ax2 = rfs.plot.ax2d # fig2 = plt.figure() # ax2.figure=fig2 # fig2.axes.append(ax2) # fig2.add_axes(ax2) # dummy = fig2.add_subplot(111) # ax2.set_position(dummy.get_position()) # dummy.remove()
descrip.insert(0, 'linmodel') # load data data = sio.loadmat('data/BoucWenData.mat') # partition the data uval = data['uval_multisine'].T yval = data['yval_multisine'].T utest = data['uval_sinesweep'].T ytest = data['yval_sinesweep'].T uest = data['u'] yest = data['y'] lines = data['lines'].squeeze() # lines already are 0-indexed fs = data['fs'].item() nfreq = len(lines) npp, m, R, P = uest.shape sig = Signal(uest,yest,fs=fs) um, ym = sig.average() # noise estimate over estimation periods covY = covariance(yest) Pest = yest.shape[-1] print(f'linear model: n,r:{linmodel.n},{linmodel.r}.') print(f'Weighted Cost/nfreq: {linmodel.cost(weight=True)/nfreq}') # transient for estimate data T1 = np.r_[npp, np.r_[0:(R-1)*npp+1:npp]] Ptr2 = 1 # simulation error # estimation simulation is done on final model, not model extracted on val data
# partitioning the data # test for performance testing and val for model selection utest = u[:, :, -1, -1] ytest = y[:, :, -1, -1] uval = u[:, :, -2, -1] yval = y[:, :, -2, -1] # all other realizations are used for estimation u = u[..., :-2, :] y = y[..., :-2, :] # model orders and Subspace dimensioning parameter nvec = [2, 3] maxr = 5 # create signal object sig = Signal(u, y) sig.lines(lines) # average signal over periods. Used for training of PNLSS model um, ym = sig.average() npp, F = sig.npp, sig.F R, P = sig.R, sig.P linmodel = linss() # estimate bla, total distortion, and noise distortion linmodel.bla(sig) # get best model on validation data models, infodict = linmodel.scan(nvec, maxr) l_errvec = linmodel.extract_model(yval, uval) # estimate PNLSS # transient: Add one period before the start of each realization. Note that
# differentiate using total variation regularization # https://github.com/pawsen/tvregdiff # import sys # sys.path.append('/home/paw/src/tvregdiff') # from tvregdiff import TVRegDiff # yd = TVRegDiff(y, itern=200, alph=0.1, dx=1/fs, ep=1e-2, # scale='large', plotflag=0) # ydd = TVRegDiff(yd, itern=200, alph=1e-1, dx=1/fs, ep=1e-2, # scale='large', plotflag=0) except Exception as err: import traceback traceback.print_exc() print(err) signal = Signal(sweep1.u, sweep1.fs, sweep1.ydd) signal.set_signal(y=y, yd=yd, ydd=ydd) rfs = RFS(signal,dof=0) rfs.plot() ## Extract subplot frfs = rfs.plot.fig b = 0.1745 ax2 = rfs.plot.ax2d ax2.axvline(-b,c='k', ls='--') ax2.axvline(b,c='k', ls='--') fig2 = plt.figure() ax2.figure=fig2 fig2.axes.append(ax2) fig2.add_axes(ax2)
from pyvib.signal import Signal2 as Signal path = 'data/' filename = 'pyds_sweepvrms' Nm = namedtuple('Nm', 'y yd ydd u t finst fs ns') sweep_l = pickle.load(open(path + filename + '0.01' + '.pkl', 'rb')) sweep_h = pickle.load(open(path + filename + '2' + '.pkl', 'rb')) f1 = 1e-3 f2 = 10 / 2 / np.pi nf = 50 f00 = 5 dof = 0 sca = 2 * np.pi lin = Signal(sweep_l.u, sweep_l.fs, sweep_l.ydd) wtlin = WT(lin) wtlin.morlet(f1, f2, nf, f00, dof=0) nlin = Signal(sweep_h.u, sweep_h.fs, sweep_h.ydd) wtnlin = WT(nlin) wtnlin.morlet(f1, f2, nf, f00, dof=0) dof = 0 plt.figure() plt.plot(sweep_h.finst * sca, sweep_h.y[dof]) plt.title('Sweep') plt.xlabel('Frequency') plt.ylabel('Amplitude (m)') fwlin, ax = wtlin.plot(fss=sweep_l.finst, sca=sca)
import matplotlib.pyplot as plt import numpy as np import pickle from collections import namedtuple from pyvib.morletWT import WT from pyvib.signal import Signal2 as Signal path = 'data/' filename = 'pyds_sweepvrms0.03' Nm = namedtuple('Nm', 'y yd ydd u t finst fs') sweep1 = pickle.load(open(path + filename + '.pkl', 'rb')) #sweep2 = pickle.load(open(path + 'sweep2.pkl', 'rb')) nlin = Signal(sweep1.u, sweep1.fs, sweep1.ydd) nlin.set_signal(y=sweep1.y, yd=sweep1.yd, ydd=sweep1.ydd) f1 = 1e-3 f2 = 10 / 2 / np.pi nf = 100 f00 = 7 dof = 0 sca = 2 * np.pi wtnlin = WT(nlin) wtnlin.morlet(f1, f2, nf, f00, dof=0) fwnlin, ax = wtnlin.plot(sweep1.finst, sca) plt.show()
sca = 2*np.pi ftype = 'multisine' filename = 'data/' + 'pyds_' + ftype + 'vrms0.2' Nm = namedtuple('Nm', 'y yd ydd u t finst fs ns') msine = pickle.load(open(filename + '.pkl', 'rb')) # which dof to get H1 estimate from/show periodicity for dof = 0 fmin = 0 fmax = 10/2/np.pi nlin = Signal(msine.u, msine.fs, y=msine.y) fper, ax = nlin.periodicity(msine.ns, dof, offset=0) per = [7,9] nlin.cut(msine.ns, per) isnoise = False inl = np.array([[0,-1]]) nl_spline = NL_spline(inl, nspl=15) nl = NL_force() nl.add(nl_spline) iu = 0 idof = [0] nldof = []
import numpy as np import matplotlib.pyplot as plt import pickle from collections import namedtuple from pyvib.signal import Signal2 as Signal from pyvib.rfs import RFS path = 'data/' filename = 'pyds_sweepvrms' Nm = namedtuple('Nm', 'y yd ydd u t finst fs ns') #sweep_l = pickle.load(open(path + filename + '0.01' + '.pkl', 'rb')) sweep_h = pickle.load(open(path + filename + '2' + '.pkl', 'rb')) signal = Signal(sweep_h.u, sweep_h.fs, sweep_h.ydd) signal.set_signal(y=sweep_h.y, yd=sweep_h.yd, ydd=sweep_h.ydd) rfs = RFS(signal, dof=0) rfs.plot() plt.show() # extract force slice/subplot for saving # ax2 = rfs.plot.ax2d # fig2 = plt.figure() # ax2.figure=fig2 # fig2.axes.append(ax2) # fig2.add_axes(ax2) # dummy = fig2.add_subplot(111) # ax2.set_position(dummy.get_position())
# noise estimate over Pest periods covY = covariance(yest[:, :, None]) # Validation data. 50 different realizations of 3 periods. Use the last # realization and last period uval_raw, _, _, Pval = load('u', 100, fnsi=False) yval_raw = load('y', 100, fnsi=False) uval_raw = uval_raw.reshape(npp, Pval, 50, order='F').swapaxes(1, 2)[:, None] yval_raw = yval_raw.reshape(npp, Pval, 50, order='F').swapaxes(1, 2)[:, None] uval = uval_raw[:, :, -1, -1] yval = yval_raw[:, :, -1, -1] utest = uval_raw[:, :, 1, -1] ytest = yval_raw[:, :, 1, -1] Rval = uval_raw.shape[2] sig = Signal(uest, yest, fs=fs) sig.lines = lines um, ym = sig.average() # sig.periodicity() # for subspace model (from BLA) sig2 = Signal(uest[:, :, None], yest[:, :, None], fs=fs) sig2.lines = lines sig2.bla() # model orders and Subspace dimensioning parameter n = 2 maxr = 20 dof = 0 iu = 0 xpowers = np.array([[2], [3]])
fmin = mat_u['fmin'].item() # 5 fmax = mat_u['fmax'].item() # 500 iu = mat_u['iu'].item() # 2 location of force nper = mat_u['P'].item() nsper = mat_u['N'].item() u = mat_u['u'].squeeze() y = mat_y['y'] # zero-based numbering of dof # iu are dofs of force sig = namedtuple('sig', 'u y fs fmin fmax iu nper nsper') return sig(u, y, fs, fmin, fmax, iu - 1, nper, nsper) lin = load(nonlin=False) slin = Signal(lin.u, lin.fs, lin.y) per = [4, 5, 6, 7, 8, 9] slin.cut(lin.nsper, per) # idof are selected dofs, ie. all dofs here idof = np.arange(7) # dof where nonlinearity is nldof = 6 # method to estimate BD bd_method = 'explicit' #bd_method = 'nr' # ims: matrix block order. At least n+1 # nmax: max model order for stabilisation diagram # ncur: model order for erstimation ims = 40
# load data path = 'data/' filename = 'pyds_multisinevrms' Nm = namedtuple('Nm', 'y yd ydd u t finst fs ns') lin = pickle.load(open(path + filename + '0.01' + '.pkl', 'rb')) nlin = pickle.load(open(path + filename + '2' + '.pkl', 'rb')) # which dof to get H1 estimate from/show periodicity dof = 0 # Frequency interval of interest fmin = 0 fmax = 5 / 2 / np.pi # Setup the signal/extract periods slin = Signal(lin.u, lin.fs, lin.y) snlin = Signal(nlin.u, nlin.fs, nlin.y) # show periodicity, to select periods from if show_periodicity: slin.periodicity(lin.ns, dof, offset=0) snlin.periodicity(nlin.ns, dof, offset=0) per = [7, 8] slin.cut(lin.ns, per) snlin.cut(lin.ns, per) # inl: connection. -1 is ground. enl: exponent. knl: coefficient. Always 1. inl = np.array([[0, -1], [1, -1]]) enl = np.array([3, 3]) knl = np.array([1, 1])
# reshape, we need the format (N,p,R,P) m, cu = u.shape; u = u.T if m > cu else u p, cy = y.shape; y = y.T if p > cy else y # (p, P*N) p = y.shape[0] m = u.shape[0] # For FNSI we always have R = 1 u.shape = (m,P,N) y.shape = (p,P,N) u = u.transpose(2,0,1)[:,:,None,Ptr:] y = y.transpose(2,0,1)[:,:,None,Ptr:] # start ID sig = Signal(u,y,fs=fs) um, ym = sig.average() sig.lines = lines nlx = [Polynomial(exponent=ex, w=w) for ex in exponent] # nlx = None #n = 4 bd_method = 'nr' bd_method = 'opt' # bd_method = 'explicit' fnsi1 = FNSI() fnsi1.set_signal(sig) fnsi1.add_nl(nlx=nlx) fnsi1.estimate(n=n, r=r, bd_method=bd_method, weight=False) fnsi1.transient(T1=N)
N = int(2e3) # Number of samples u = np.random.randn(N) def f_NL(x): return x + 0.2*x**2 + 0.1*x**3 b, a = signal.cheby1(2, 5, 2*0.3, 'low', analog=False) x = f_NL(u) # Intermediate signal y = signal.lfilter(b, a, x) # output scale = np.linalg.lstsq(u[:, None], x)[0].item() # Initial linear model = scale factor times underlying dynamics sys = signal.tf2ss(scale*b, a) T1 = 0 # No periodic transient T2 = 200 # number of transient samples to discard sig = Signal(u[:, None, None, None], y[:, None, None, None]) sig.average() model = PNLSS(sys, sig) # Hammerstein system only has nonlinear terms in the input. # Quadratic and cubic terms in state- and output equation model.nlterms('x', [2, 3], 'inputsonly') model.nlterms('y', [2, 3], 'inputsonly') model.transient(T1=T1, T2=T2) model.optimize(weight=False, nmax=50) yopt = model.simulate(u)[1] def rmse(y, yhat): return np.sqrt(np.mean((y-yhat.T)**2))