|
| 1 | +#control cvxpymatcore |
| 2 | +import concore |
| 3 | +import numpy as np |
| 4 | +import scipy.io as sio |
| 5 | +from scipy import optimize |
| 6 | +from numpy.linalg import inv |
| 7 | +import matplotlib.pyplot as plt |
| 8 | +import cvxopt |
| 9 | +from cvxopt import solvers |
| 10 | +import time |
| 11 | + |
| 12 | +GENERATE_PLOT = 1 |
| 13 | + |
| 14 | +def Get_MPC_Constants(): |
| 15 | + MPC_data = sio.loadmat('MPC_data.mat', struct_as_record = False, squeeze_me = True) |
| 16 | + Data = MPC_data['Data'] |
| 17 | + A = np.array(Data.op1.A) |
| 18 | + B = np.array(Data.op1.B) |
| 19 | + C = np.array(Data.op1.C) |
| 20 | + D = np.array(Data.op1.D) |
| 21 | + x0 = np.array(Data.op1.x0) |
| 22 | + x0 = x0.reshape(x0.size, 1) |
| 23 | + xs = np.array(Data.op1.xs) |
| 24 | + xs = xs.reshape(xs.size, 1) |
| 25 | + us = np.array(Data.op1.us) |
| 26 | + us = us.reshape(us.size, 1) |
| 27 | + ysp = np.array(Data.op1.ysp) |
| 28 | + ysp = ysp.reshape(ysp.size, 1) |
| 29 | + Us = np.array(Data.op1.Us) |
| 30 | + Us = Us.reshape(Us.size, 1) |
| 31 | + Ys = np.array(Data.op1.Ys) |
| 32 | + Ys = Ys.reshape(Ys.size, 1) |
| 33 | + alpha = np.array(Data.op1.alpha) |
| 34 | + beta = np.array(Data.op1.beta) |
| 35 | + gamma = np.array(Data.op1.gamma) |
| 36 | + V = np.array(Data.op1.V) |
| 37 | + G = np.array(Data.op1.G) |
| 38 | + W = np.array(Data.op1.W) |
| 39 | + Z = np.array(Data.op1.Z) |
| 40 | + J = np.array(Data.op1.J) |
| 41 | + Nu = np.array(Data.input.Nu) |
| 42 | + Nx = np.array(Data.input.Nx) |
| 43 | + Ny = np.array(Data.input.Ny) |
| 44 | + Umax = np.array(Data.input.Umax) |
| 45 | + Umax = Umax.reshape(Umax.size, 1) |
| 46 | + Umin = np.array(Data.input.Umin) |
| 47 | + Umin = Umin.reshape(Umin.size, 1) |
| 48 | + Ymax = np.array(Data.output.Ymax) |
| 49 | + Ymax = Ymax.reshape(Ymax.size, 1) |
| 50 | + Ymin = np.array(Data.output.Ymin) |
| 51 | + Ymin = Ymin.reshape(Ymin.size, 1) |
| 52 | + Np = np.array(Data.input.Np) |
| 53 | + Pd = np.array(Data.input.Pd) |
| 54 | + Rd = np.array(Data.input.Rd) |
| 55 | + Qd = np.array(Data.input.Qd) |
| 56 | + |
| 57 | + X = {'A': A, 'B': B, 'C': C, 'D': D, \ |
| 58 | + 'Nu': Nu, 'Nx': Nx, 'Ny': Ny, 'Np': Np, \ |
| 59 | + 'x0': x0, 'us': us, 'xs': xs, 'ysp': ysp, 'Us': Us, 'Ys': Ys, \ |
| 60 | + 'Pd': Pd, 'Rd': Rd, 'Qd': Qd, \ |
| 61 | + 'alpha': alpha, 'beta': beta, 'gamma': gamma, 'W': W, 'V': V, 'G': G, 'Z': Z, 'J': J,\ |
| 62 | + 'Umax': Umax, 'Umin': Umin, 'Ymax': Ymax, 'Ymin': Ymin} |
| 63 | + return X |
| 64 | + |
| 65 | +def MPC(x0, u, y, Pd, X): |
| 66 | + # Substract steady state values of inputs and outputs |
| 67 | + yp = y - X['ysp'] |
| 68 | + up = u - X['us'] |
| 69 | + # Time-varying Kalman filter |
| 70 | + M = np.dot(np.dot(Pd, X['C'].T), inv(np.dot(np.dot(X['C'], Pd), X['C'].T) + X['Rd'])) |
| 71 | + x_0 = x0 + np.dot(M, yp - np.dot(X['C'], x0) - np.dot(X['D'], u)) |
| 72 | + Pd = np.dot(np.dot(X['A'], Pd - np.dot(np.dot(M, X['C']), Pd)), X['A'].T) + X['Qd'] |
| 73 | + # Construct QP matrices |
| 74 | + H = np.dot(np.dot(X['W'].T, X['alpha']), X['W']) + X['beta'] + np.dot(np.dot(X['Z'].T, X['gamma']), X['Z']) |
| 75 | + H = (H + H.T)/2 |
| 76 | + H = cvxopt.matrix(H) |
| 77 | + f = np.dot(np.dot(np.dot(X['W'].T, X['alpha'].T), X['V']), x_0) |
| 78 | + f = cvxopt.matrix(f) |
| 79 | + A = np.concatenate((np.eye(X['Nu']*(X['Np'] - 1)), -np.eye(X['Nu']*(X['Np'] - 1)), \ |
| 80 | + np.dot(X['G'], X['W']) + X['J'], -np.dot(X['G'], X['W']) - X['J']), axis = 0) |
| 81 | + A = cvxopt.matrix(A) |
| 82 | + b = np.concatenate((X['Umax'] - X['Us'],-(X['Umin'] - X['Us']), \ |
| 83 | + X['Ymax'] - X['Ys']- np.dot(np.dot(X['G'], X['V']), x_0), \ |
| 84 | + -(X['Ymin'] - X['Ys']- np.dot(np.dot(X['G'], X['V']), x_0))), axis = 0) |
| 85 | + b = cvxopt.matrix(b) |
| 86 | + # Solve quadratic program |
| 87 | + solvers.options['show_progress'] = False |
| 88 | + # Apply solution if QP solved successful |
| 89 | + sol = solvers.qp(H, f, A, b) |
| 90 | + if sol['status'] == 'optimal': |
| 91 | + U = sol['x'] |
| 92 | + u = np.array(U[0:X['Nu']]).reshape(X['Nu'], 1) + X['us'] |
| 93 | + else: |
| 94 | + u = u |
| 95 | + x0 = np.dot(X['A'], x_0) + np.dot(X['B'], up) |
| 96 | + # Return outputs |
| 97 | + return u, x0, Pd |
| 98 | + |
| 99 | +X = Get_MPC_Constants() # model and controller constants |
| 100 | +try: |
| 101 | + MAPsp = concore.params['MAPsp'] |
| 102 | +except: |
| 103 | + MAPsp = X['ysp'][0] |
| 104 | +try: |
| 105 | + HRsp = concore.params['HRsp'] |
| 106 | +except: |
| 107 | + HRsp = X['ysp'][1] |
| 108 | +print("MAPsp="+str(MAPsp)+ " HRsp="+str(HRsp)) |
| 109 | +X['ysp'][0] = MAPsp |
| 110 | +X['ysp'][1] = HRsp |
| 111 | + |
| 112 | +print(X['A']) |
| 113 | +# convert data from matlab to python |
| 114 | +# initialize model constant and variables |
| 115 | +#xm = X['x0'] # initial condition of plant |
| 116 | +u = X['us'] # initial input |
| 117 | +print("initial input") |
| 118 | +print(X['us']) |
| 119 | +# initialize controller constant and variables |
| 120 | +#Nsim = 150 # number of simulation cycles |
| 121 | +concore.default_maxtime(150) |
| 122 | +xc = np.zeros((X['Nx'], 1)) # initial conditon of state in MPC |
| 123 | +Pd = X['Pd'] # variance of initial state |
| 124 | +# set list to record inputs and outputs |
| 125 | +ut = [] |
| 126 | +ymt = [] |
| 127 | + |
| 128 | + |
| 129 | +concore.delay = 0.02 |
| 130 | +init_simtime_u = "[0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]" |
| 131 | +init_simtime_ym = "[0.0, 0.0, 0.0]" |
| 132 | +u = np.array([concore.initval(init_simtime_u)]).T |
| 133 | +wallclock1 = time.perf_counter() |
| 134 | +while(concore.simtime<concore.maxtime): |
| 135 | + while concore.unchanged(): |
| 136 | + ym = concore.read(1,"ym",init_simtime_ym) |
| 137 | + ym = np.array([ym]).T |
| 138 | + ################# |
| 139 | + ut.append(u) |
| 140 | + ymt.append(ym) |
| 141 | + u, xc, Pd = MPC(xc, u, ym, Pd, X) |
| 142 | + ################# |
| 143 | + print("ym="+str(ym)+" u="+str(u)); |
| 144 | + concore.write(1,"u",list(u.T[0])); |
| 145 | +wallclock2 = time.perf_counter() |
| 146 | +#concore.write(1,"u",init_simtime_u) |
| 147 | +print("retry="+str(concore.retrycount)) |
| 148 | +print("time/iter="+str((wallclock2-wallclock1)/concore.maxtime)) |
| 149 | + |
| 150 | +if GENERATE_PLOT == 0: |
| 151 | + quit() |
| 152 | + |
| 153 | +# plot inputs and outputs |
| 154 | +ym1 = [x[0].item() for x in ymt] |
| 155 | +ym2 = [x[1].item() for x in ymt] |
| 156 | +u1 = [x[0].item() for x in ut] |
| 157 | +u2 = [x[1].item() for x in ut] |
| 158 | +u3 = [x[2].item() for x in ut] |
| 159 | +u4 = [x[3].item() for x in ut] |
| 160 | +u5 = [x[4].item() for x in ut] |
| 161 | +u6 = [x[5].item() for x in ut] |
| 162 | + |
| 163 | +Nsim = len(ym1) |
| 164 | +plt.figure() |
| 165 | +plt.subplot(211) |
| 166 | +plt.plot(range(Nsim), ym1) |
| 167 | +plt.plot(range(Nsim), np.tile(X['ysp'][0], Nsim)) |
| 168 | +plt.ylabel('MAP (mmHg)') |
| 169 | +plt.legend(['MAPm', 'MAPsp'], loc=0) |
| 170 | +plt.subplot(212) |
| 171 | +plt.plot(range(Nsim), ym2) |
| 172 | +plt.plot(range(Nsim), np.tile(X['ysp'][1], Nsim)) |
| 173 | +plt.xlabel('Cycles') |
| 174 | +plt.ylabel('HR (bpm)') |
| 175 | +plt.legend(['HRm', 'HRsp'], loc=0) |
| 176 | +plt.savefig("hrmap.pdf") |
| 177 | +#plt.tight_layout() |
| 178 | + |
| 179 | +plt.figure() |
| 180 | +plt.subplot(321) |
| 181 | +plt.plot(range(Nsim), u1) |
| 182 | +plt.ylabel('Pw1 (s)') |
| 183 | +plt.subplot(322) |
| 184 | +plt.plot(range(Nsim), u2) |
| 185 | +plt.ylabel('Pf1 (Hz)') |
| 186 | +plt.subplot(323) |
| 187 | +plt.plot(range(Nsim), u3) |
| 188 | +plt.xlabel('Cycles') |
| 189 | +plt.ylabel('Pw2 (s)') |
| 190 | +plt.subplot(324) |
| 191 | +plt.plot(range(Nsim), u4) |
| 192 | +plt.ylabel('Pf2 (Hz)') |
| 193 | +plt.subplot(325) |
| 194 | +plt.plot(range(Nsim), u5) |
| 195 | +plt.ylabel('Pw3 (s)') |
| 196 | +plt.subplot(326) |
| 197 | +plt.plot(range(Nsim), u6) |
| 198 | +plt.xlabel('Cycles') |
| 199 | +plt.ylabel('Pf3 (Hz)') |
| 200 | +plt.savefig("stim.pdf") |
| 201 | +plt.tight_layout() |
| 202 | +plt.show() |
| 203 | + |
| 204 | + |
0 commit comments