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)
# 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) linmodel.optimize(weight=weight) print(f"Best subspace model, n, r: {linmodel.n}, {linmodel.r}") linmodel_orig = linmodel if False: # dont scan subspace linmodel = Subspace(sig)
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)) print(f'RMS error {rmse(y, yopt)}')