def identify_linear(data, n=6, r=20, subscan=True, info=2, weight=True, optimize=True): lin_errvec = [] linmodel = Subspace(data.sig) #linmodel._cost_normalize = 1 if subscan: linmodel.scan(nvec=[6], maxr=20, optimize=True, weight=weight, info=info, bd_method=bd_method) lin_errvec = linmodel.extract_model(data.yval, data.uval) print( f"Best subspace model on val data, n, r: {linmodel.n}, {linmodel.r}" ) #linmodel.estimate(n=n, r=r, weight=weight) #linmodel.optimize(weight=weight, info=info) else: linmodel.estimate(n=n, r=r, weight=weight, bd_method=bd_method) if optimize: linmodel.optimize(weight=weight, info=info) return linmodel, lin_errvec
def identify_linear(data, n, r, subscan=True, info=2): lin_errvec = [] linmodel = Subspace(data.sig) linmodel._cost_normalize = 1 if subscan: linmodel.scan(nvec=[2, 3, 4, 5, 6, 7, 8], maxr=20, optimize=True, weight=False, info=info) lin_errvec = linmodel.extract_model(data.yval, data.uval) print(f"Best subspace model, n, r: {linmodel.n}, {linmodel.r}") #linmodel.estimate(n=n, r=r, weight=weight) #linmodel.optimize(weight=weight, info=info) else: linmodel.estimate(n=n, r=r, weight=weight) linmodel.optimize(weight=weight, info=info) return linmodel, lin_errvec
# 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) # get best model on validation data models, infodict = linmodel.scan(nvec, maxr, weight=weight) l_errvec = linmodel.extract_model(yval, uval) # or estimate the subspace model directly linmodel.estimate( 2, 5, weight=weight) # best model, when noise weighting is used linmodel.optimize(weight=weight)
linmodel.transient(T1) # linmodel._cost_normalize = 1 linmodel.optimize(weight=weight) fnsi1 = FNSI() fnsi1.set_signal(sig) fnsi1.add_nl(nlx=nlx) fnsi1.estimate(n=2, r=5, weight=weight) fnsi1.transient(T1) #fnsi1.optimize(lamb=100, weight=weight, nmax=25) print(f"Best subspace model, n, r: {linmodel.n}, {linmodel.r}") # linmodel_orig = linmodel if False: # dont scan subspace linmodel = Subspace(sig) # get best model on validation data models, infodict = linmodel.scan(nvec, maxr, weight=weight) l_errvec = linmodel.extract_model(yval, uval) # or estimate the subspace model directly linmodel.estimate( 2, 5, weight=weight) # best model, when noise weighting is used linmodel.optimize(weight=weight) print(f"Best subspace model, n, r: {linmodel.n}, {linmodel.r}") # linmodel = deepcopy(linmodel_orig) # estimate PNLSS # transient: Add one period before the start of each realization. Note that # this is for the signal averaged over periods Rest = yest.shape[2] T1 = np.r_[npp * Ntr, np.r_[0:(Rest - 1) * npp + 1:npp]]
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)
yval = y[:npp, None] # model orders and Subspace dimensioning parameter n = 2 maxr = 20 sig = Signal(uest, yest, fs=fs) sig.lines = lines # estimate bla, total distortion, and noise distortion sig.bla() # average signal over periods. Used for training of PNLSS model # Even if there's only 1 period, pnlss expect this to be run first. It also # reshapes the signal, so um: (npp*m*R) um, ym = sig.average() linmodel = Subspace(sig) # estimate bla, total distortion, and noise distortion linmodel.estimate(n, maxr) linmodel2 = deepcopy(linmodel) linmodel2.optimize(weight=True) # estimate PNLSS # transient: Add two periods before the start of each realization. Note that # this for the signal averaged over periods T1 = np.r_[2 * npp, np.r_[0:(R - 1) * npp + 1:npp]] pnlss1 = PNLSS(linmodel2) pnlss1.nlterms('x', [2, 3], 'full') # pnlss1.nlterms('y', [2,3], 'empty') pnlss1.transient(T1)
# 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]]) # subspace model lin1 = Subspace(sig2) # models, infodict = linmodel.scan(n, maxr, weight=False) # ensure we use same dimension as for the fnsi model lin1.estimate(n, maxr) lin2 = deepcopy(lin1) lin2.optimize(weight=False) # Linear model fnsi1 = FNSI(sig) fnsi1.estimate(n, maxr) fnsi1.nl_coeff(iu) # initial nonlinear model fnsi2 = FNSI(sig) fnsi2.nlterms('state', xpowers) fnsi2.estimate(n, maxr)
# noise estimate over estimation periods covY = covariance(yest) Pest = yest.shape[-1] # model orders and Subspace dimensioning parameter nvec = [2, 3, 4] maxr = 7 sig = Signal(uest, yest, fs=fs) sig.lines = lines sig.bla() # average signal over periods. Used for estimation of PNLSS model um, ym = sig.average() linmodel = Subspace(sig) models, infodict = linmodel.scan(nvec, maxr, nmax=50, weight=True) # set model manual, as in matlab program # linmodel.extract_model() linmodel.estimate(n=3, r=4) print(f'linear model: n,r:{linmodel.n},{linmodel.r}.') print(f'Weighted Cost/nfreq: {linmodel.cost(weight=True)/nfreq}') ## estimate PNLSS ## # transient: Add one period before the start of each realization of the # averaged signal used for estimation T1 = np.r_[npp, np.r_[0:(R - 1) * npp + 1:npp]] # set common properties for PNLSS pnlss = PNLSS(linmodel) pnlss.transient(T1)
utest = uval_raw[:, :, 1, -1] ytest = yval_raw[:, :, 1, -1] Rval = uval_raw.shape[2] sig = Signal(uest, yest, fs=fs) sig.lines = lines # estimate bla, total distortion, and noise distortion sig.bla() um, ym = sig.average() # model orders and Subspace dimension parameter n = 2 maxr = 20 # subspace model linmodel = Subspace(sig) # models, infodict = linmodel.scan(n, maxr, weight=False) # ensure we use same dimension as for the fnsi model linmodel.estimate(n, maxr) linmodel2 = deepcopy(linmodel) linmodel2.optimize(weight=False) pnlss1 = PNLSS(linmodel) pnlss1.nlterms('x', [2, 3], 'statesonly') pnlss1.transient(T1=npp) pnlss2 = deepcopy(pnlss1) pnlss1.optimize(weight=False, nmax=50) pnlss2.optimize(weight=True, nmax=50) models = [linmodel, linmodel2, pnlss1, pnlss2]