# theta = tightenconstraints(Z, A, B, K, W, N)## Tightens state and input constraints for a box W.## Z should be a struct with fields G, H, and psi to define the feasible set Z as## Gx + Hu <= psi## A, B, and K should be the system model and controller gain. W should be a# vector defining the maximum absolute values for w. The system evolves as## x^+ = Ax + Bu + w, u = v + Kx, -W <= w <= W## This means that W must be a symmetric box in R^n (we make this restriction# because optimization becomes particularly easy).## Returns theta such that the tighter constraints## Gx + H(v + Kx) <= psi - theta## are satisfied for any N realizations of W.importnumpyasnpdeftightenconstraints(Z,A,B,K,W,N):""" Tightens state and input constraints for a box W. Z should be a struct with fields G, H, and psi to define the feasible set Z as Gx + Hu <= psi A, B, and K should be the system model and controller gain. W should be a vector defining the maximum absolute values for w. The system evolves as x^+ = Ax + Bu + w, u = v + Kx, -W <= w <= W This means that W must be a symmetric box in R^n (we make this restriction because optimization becomes particularly easy). Returns theta such that the tighter constraints Gx + H(v + Kx) <= psi - theta are satisfied for any N realizations of W. """ifnotisinstance(Z,dict)ornotall(fieldinZforfieldin['G','H']):raiseValueError('Invalid input for Z!')C=Z['G']+Z['H']@KA=A+B@Ktheta=np.zeros(C.shape[0])Ak=np.eye(A.shape[0])W=np.abs(W).flatten()foriinrange(N+1):theta=theta+np.abs(C@Ak)@WAk=A@Akreturntheta
# [depends] functions/tightenconstraints.py# [makes] calcalpha.mat# Example Constraint tightening for a linear system.importnumpyasnpimportscipy.ioimportmatplotlib.pyplotaspltimportosimportsyssys.path.append('functions/')fromhyperrectangleimporthyperrectanglefromtightenconstraintsimporttightenconstraints# State space matricesA=np.array([[1,1],[0,1]])B=np.array([[0],[1]])K=np.array([[-0.4,-1.2]])# State constraints. u is unconstrained.xmax=1umax=1Z={}GH,Z['psi']=hyperrectangle(np.array([[-xmax],[-xmax],[-umax]]),np.array([[xmax],[xmax],[umax]]))Z['G']=GH[:,:2]Z['H']=GH[:,2:3]# Make H 2D array# Disturbance setdefinfnorm(x):returnnp.max(np.abs(x))wmax=0.1W=np.array([[wmax,wmax,-wmax,-wmax],[wmax,-wmax,-wmax,wmax]])normW=infnorm(W)KW=K@WnormKW=infnorm(KW)# For each value of N, see how far you need to squeeze.Nmax=25AkW=[None]*(Nmax+1)alphaW=[None]*(Nmax+1)normZbars=np.full((3,Nmax+1),np.nan)Nkeep=[2,3,4,5,6,7,8,10,15]Ak=np.eye(A.shape[0])alphas=np.full(Nmax+1,np.nan)thetas=[None]*(Nmax+1)forninrange(Nmax+1):AkW[n]=Ak@WnormAkW=infnorm(AkW[n])normKAkW=infnorm(K@AkW[n])alphas[n]=max(normAkW/normW,normKAkW/normKW)alphaW[n]=alphas[n]*Wifalphas[n]<1:thetas[n]=tightenconstraints(Z,A,B,K,wmax*np.array([[1],[1]]),n+1)else:thetas[n]=np.full_like(Z['psi'],np.nan)psibar=Z['psi']-thetas[n]/(1-alphas[n]+np.finfo(float).eps)normZbars[:,n]=psibar.flatten()[[0,2,4]]Ak=(A+B@K)@Akifnotos.getenv('OMIT_PLOTS')=='true':plt.figure()plt.semilogy(range(Nmax+1),alphas,'-ok')plt.plot([1,Nmax],[1,1],'--r')plt.xlabel('N')plt.ylabel('Minimum \\alpha')plt.figure()Nplots=int(np.ceil(np.sqrt(len(Nkeep))))fori,nkeepinenumerate(Nkeep):plt.subplot(Nplots,Nplots,i+1)n=nkeep+1Vin=AkW[n]Vout=alphaW[n]plt.plot(np.append(Vin[0,:],Vin[0,0]),np.append(Vin[1,:],Vin[1,0]),'-or')plt.plot(np.append(Vout[0,:],Vout[0,0]),np.append(Vout[1,:],Vout[1,0]),'-sb')plt.title(f'N = {n}: \\alpha = {alphas[n]:.3g}')plt.figure()N=np.arange(Nmax+1)plt.plot(N,normZbars[0,:],'-or',N,normZbars[1,:],'-og',N,normZbars[2,:],'-ob')plt.xlabel('N')plt.ylabel('Bound')plt.legend(['x_1','x_2','u'])# Save datadata={'N':np.arange(Nmax+1),'alpha':alphas,'normZbar':normZbars}scipy.io.savemat('calcalpha.mat',data)