#raise SystemExit(0) # get best model on validation data. Change Transient settings, as there is # only one realization nl_errvec = model.extract_model(yval, uval, T1=npp) models = [linmodel, model] descrip = [type(mod).__name__ for mod in models] descrip = tuple(descrip) # convert to tuple for legend concatenation in figs # simulation error val = np.empty((*yval.shape, len(models))) est = np.empty((*ym.shape, len(models))) test = np.empty((*ytest.shape, len(models))) for i, model in enumerate(models): test[..., i] = model.simulate(utest, T1=npp * Ptr)[1] val[..., i] = model.simulate(uval, T1=npp * Ptr)[1] est[..., i] = model.simulate(um, T1=T1)[1] # convenience inline functions stack = lambda ydata, ymodel: \ np.concatenate((ydata[...,None], (ydata[...,None] - ymodel)),axis=2) rms = lambda y: np.sqrt(np.mean(y**2, axis=0)) est_err = stack(ym, est) # (npp*R,p,nmodels) val_err = stack(yval, val) test_err = stack(ytest, test) noise = np.abs(np.sqrt(Pest * covY.squeeze())) print(f"### err for models {descrip} ###") print(f'rms error noise: \n{rms(noise)} \ndb: \n{db(rms(noise))} ') print(f'rms error est: \n{rms(est_err)} \ndb: \n{db(rms(est_err))}') print(f'rms error val: \n{rms(val_err)} \ndb: \n{db(rms(val_err))}')
kind = 'Odd' # 'Full','Odd','SpecialOdd', or 'RandomOdd': kind of multisine m = D.shape[1] # number of inputs p = C.shape[0] # number of outputs fs = 1 # normalized sampling rate Ntr = 5 if True: # 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) # if multiple input is required, this will copy u m times # Transient: Add one period 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) print(norm(yorig)) u = u.reshape((R, P, npp)).transpose((2, 0, 1))[:, None] # (npp,m,R,P) y = yorig.reshape((R, P, npp, p), order='C').transpose((2, 3, 0, 1)) #y = yorig.reshape((R,P,npp)).transpose((2,0,1))[:,None] # or in F order: # y2 = yorig.reshape((npp,P,R,p),order='F').transpose((0,3,2,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
def identify(data, nlx, nly, nmax=25, info=2, fnsi=False): # transient: Add one period before the start of each realization. Note that # this is for the signal averaged over periods Rest = data.yest.shape[2] T1 = np.r_[data.npp * data.Ntr, np.r_[0:(Rest - 1) * data.npp + 1:data.npp]] linmodel = Subspace(data.sig) linmodel._cost_normalize = 1 linmodel.estimate(2, 5, weight=weight) linmodel.optimize(weight=weight, info=info) # estimate NLSS model = NLSS(linmodel) # model._cost_normalize = 1 model.add_nl(nlx=nlx, nly=nly) model.set_signal(data.sig) model.transient(T1) model.optimize(lamb=100, weight=weight, nmax=nmax, info=info) # get best model on validation data. Change Transient settings, as there is # only one realization nl_errvec = model.extract_model(data.yval, data.uval, T1=data.npp * data.Ntr, info=info) models = [linmodel, model] descrip = [type(mod).__name__ for mod in models] if fnsi: # FNSI can only use 1 realization sig = deepcopy(data.sig) # This is stupid, but unfortunately nessecary sig.y = sig.y[:, :, 0][:, :, None] sig.u = sig.u[:, :, 0][:, :, None] sig.R = 1 sig.average() fnsi1 = FNSI() fnsi1.set_signal(sig) fnsi1.add_nl(nlx=nlx) fnsi1.estimate(n=2, r=5, weight=weight) fnsi1.transient(T1) fnsi2 = deepcopy(fnsi1) fnsi2.optimize(lamb=100, weight=weight, nmax=nmax, info=info) models = models + [fnsi1, fnsi2] descrip = descrip + ['FNSI', 'FNSI optimized'] descrip = tuple(descrip) # convert to tuple for legend concatenation # simulation error val = np.empty((*data.yval.shape, len(models))) est = np.empty((*data.ym.shape, len(models))) test = np.empty((*data.ytest.shape, len(models))) for i, model in enumerate(models): test[..., i] = model.simulate(data.utest, T1=data.npp * data.Ntr)[1] val[..., i] = model.simulate(data.uval, T1=data.npp * data.Ntr)[1] est[..., i] = model.simulate(data.um, T1=T1)[1] Pest = data.yest.shape[3] # convenience inline functions def stack(ydata, ymodel): return \ np.concatenate((ydata[..., None], (ydata[..., None] - ymodel)), axis=2) def rms(y): return np.sqrt(np.mean(y**2, axis=0)) est_err = stack(data.ym, est) # (npp*R,p,nmodels) val_err = stack(data.yval, val) test_err = stack(data.ytest, test) noise = np.abs(np.sqrt(Pest * data.covY.squeeze())) print() print(f"err for models: signal, {descrip}") # print(f'rms error noise:\n{rms(noise)} \ndb: \n{db(rms(noise))} ') # only print error for p = 0. Almost equal to p = 1 print(f'rms error est (db): \n{db(rms(est_err[:,0]))}') print(f'rms error val (db): \n{db(rms(val_err[:,0]))}') # print(f'rms error test: \n{rms(test_err)} \ndb: \n{db(rms(test_err))}') return Result(est_err, val_err, test_err, noise, nl_errvec, descrip)
# nls = None sys = Newmark(M, C, K, nls) nm = False np.random.seed(0) ud, linesd, freqd = multisine(f1, f2, N=nppint, fs=fsint, R=R, P=P) fext = np.zeros((nsint, ndof)) for A in Avec: print(f'Discrete started with ns: {nsint}, A: {A}, R: {R}, P: {P}, ' f'upsamp: {upsamp}, eps:{eps}') # Transient: Add periods before the start of each realization. To generate # steady state data. T1 = np.r_[npp * Ntr, np.r_[0:(R - 1) * P * nppint + 1:P * nppint]] fext[:, fdof] = A * ud.ravel() _, yd, xd = dmodel.simulate(fext, T1=T1) yc, xc, uc, linesc = simulate_cont(cmodel, A, tc) try: ynm, ydnm, yddnm = sys.integrate(fext, dt, x0=None, v0=None, sensitivity=False) Ynm = np.fft.fft(ynm[-nppint:, [fdof, nldof]], axis=0) nm = True except ValueError as e: print(f'Discrete stepping failed with error {e}. For A: {A}') #if scan: # plot frf for forcing and tanh node