|
| 1 | +import time |
| 2 | +import numpy as np |
| 3 | +import matplotlib.pyplot as plt |
| 4 | +from scipy_dae.integrate import solve_dae, consistent_initial_conditions |
| 5 | + |
| 6 | + |
| 7 | +"""This example investigates a flexible multibody system called Andrews' |
| 8 | +squeezer mechanism as outlined in [1]_ and [2]_. Since this is a system of |
| 9 | +differential algebraic equatons of index 3, we implement a stabilized index 1 |
| 10 | +formulation as proposed by [3]_. |
| 11 | +
|
| 12 | +References: |
| 13 | +----------- |
| 14 | +.. [1] E. Hairer, G. Wanner, "Solving Ordinary Differential Equations II: |
| 15 | + Stiff and Differential-Algebraic Problems", p. 377. |
| 16 | +.. [2] https://archimede.uniba.it/~testset/problems/andrews.php |
| 17 | +.. [3] https://doi.org/10.1002/nme.1620320803 |
| 18 | +""" |
| 19 | + |
| 20 | +# parameters |
| 21 | +nq = 7 |
| 22 | +nla = 6 |
| 23 | + |
| 24 | +m1 = 0.04325 |
| 25 | +m2 = 0.00365 |
| 26 | +m3 = 0.02373 |
| 27 | +m4 = 0.00706 |
| 28 | +m5 = 0.07050 |
| 29 | +m6 = 0.00706 |
| 30 | +m7 = 0.05498 |
| 31 | + |
| 32 | +I1 = 2.194e-6 |
| 33 | +I2 = 4.410e-7 |
| 34 | +I3 = 5.255e-6 |
| 35 | +I4 = 5.667e-7 |
| 36 | +I5 = 1.169e-5 |
| 37 | +I6 = 5.667e-7 |
| 38 | +I7 = 1.912e-5 |
| 39 | + |
| 40 | +xa = -0.06934 |
| 41 | +ya = -0.00227 |
| 42 | + |
| 43 | +xb = -0.03635 |
| 44 | +yb = 0.03273 |
| 45 | + |
| 46 | +xc = 0.014 |
| 47 | +yc = 0.072 |
| 48 | + |
| 49 | +d = 0.028 |
| 50 | +da = 0.0115 |
| 51 | +e = 0.02 |
| 52 | + |
| 53 | +ea = 0.01421 |
| 54 | +zf = 0.02 |
| 55 | +fa = 0.01421 |
| 56 | + |
| 57 | +rr = 0.007 |
| 58 | +ra = 0.00092 |
| 59 | +ss = 0.035 |
| 60 | + |
| 61 | +sa = 0.01874 |
| 62 | +sb = 0.01043 |
| 63 | +sc = 0.018 |
| 64 | + |
| 65 | +sd = 0.02 |
| 66 | +zt = 0.04 |
| 67 | +ta = 0.02308 |
| 68 | + |
| 69 | +tb = 0.00916 |
| 70 | +u = 0.04 |
| 71 | +ua = 0.01228 |
| 72 | + |
| 73 | +ub = 0.00449 |
| 74 | +c0 = 4530 |
| 75 | +l0 = 0.07785 |
| 76 | + |
| 77 | +mom = 0.033 |
| 78 | + |
| 79 | +def F(t, y, yp): |
| 80 | + |
| 81 | + def M(t, vq): |
| 82 | + M = np.zeros((nq, nq)) |
| 83 | + |
| 84 | + # beta, Theta, gamma, Phi, delta, Omega, epsilon |
| 85 | + q1, q2, q3, q4, q5, q6, q7 = vq |
| 86 | + |
| 87 | + cos_Th = np.cos(q2) |
| 88 | + sin_Phi = np.sin(q4) |
| 89 | + sin_Om = np.sin(q6) |
| 90 | + |
| 91 | + M[0, 0] = m1 * ra**2 + m2 * (rr**2 - 2 * da * rr * cos_Th + da**2) + I1 + I2 |
| 92 | + M[1, 0] = M[0, 1] = m2 * (da**2 - da * rr * cos_Th) + I2 |
| 93 | + M[1, 1] = m2 * da**2 + I2 |
| 94 | + M[2, 2] = m3 * (sa**2 + sb**2) + I3 |
| 95 | + M[3, 3] = m4 * (e - ea)**2 + I4 |
| 96 | + M[4, 3] = M[3, 4] = m4 * ((e - ea)**2 + zt * (e - ea) * sin_Phi) + I4 |
| 97 | + M[4, 4] = m4 * (zt**2 + 2 * zt * (e - ea) * sin_Phi + (e - ea)**2) + m5 * (ta**2 + tb**2) + I4 + I5 |
| 98 | + M[5, 5] = m6 * (zf - fa)**2 + I6 |
| 99 | + M[6, 5] = M[5, 6] = m6 * ((zf - fa)**2 - u * (zf - fa) * sin_Om) + I6 |
| 100 | + M[6, 6] = m6 * ((zf - fa)**2 - 2 * u * (zf - fa) * sin_Om + u**2) + m7 * (ua**2 + ub**2) + I6 + I7 |
| 101 | + |
| 102 | + return M |
| 103 | + |
| 104 | + def h(t, vq, vu): |
| 105 | + # beta, Theta, gamma, Phi, delta, Omega, epsilon |
| 106 | + q1, q2, q3, q4, q5, q6, q7 = vq |
| 107 | + u1, u2, u3, u4, u5, u6, u7 = vu |
| 108 | + |
| 109 | + sin_Th = np.sin(q2) |
| 110 | + sin_ga = np.sin(q3) |
| 111 | + cos_ga = np.cos(q3) |
| 112 | + cos_Phi = np.cos(q4) |
| 113 | + cos_Om = np.cos(q6) |
| 114 | + |
| 115 | + xd = sd * cos_ga + sc * sin_ga + xb |
| 116 | + yd = sd * sin_ga - sc * cos_ga + yb |
| 117 | + L = np.sqrt((xd - xc)**2 + (yd - yc)**2) |
| 118 | + F = -c0 * (L - l0) / L |
| 119 | + Fx = F * (xd - xc) |
| 120 | + Fy = F * (yd - yc) |
| 121 | + |
| 122 | + h = np.zeros(nq) |
| 123 | + h[0] = mom - m2 * da * rr * u2 * (u2 + 2 * u1) * sin_Th |
| 124 | + h[1] = m2 * da * rr * u1**2 * sin_Th |
| 125 | + h[2] = Fx * (sc * cos_ga - sd * sin_ga) + Fy * (sd * cos_ga + sc * sin_ga) |
| 126 | + h[3] = m4 * zt * (e - ea) * u5**2 * cos_Phi |
| 127 | + h[4] = -m4 * zt * (e - ea) * u4 * (u4 + 2 * u5) * cos_Phi |
| 128 | + h[5] = -m6 * u * (zf - fa) * u7**2 * cos_Om |
| 129 | + h[6] = m6 * u * (zf - fa) * u6 * (u6 + 2 * u7) * cos_Om |
| 130 | + |
| 131 | + return h |
| 132 | + |
| 133 | + def g(t, vq): |
| 134 | + # beta, Theta, gamma, Phi, delta, Omega, epsilon |
| 135 | + q1, q2, q3, q4, q5, q6, q7 = vq |
| 136 | + |
| 137 | + sin_be = np.sin(q1) |
| 138 | + cos_be = np.cos(q1) |
| 139 | + sin_ga = np.sin(q3) |
| 140 | + cos_ga = np.cos(q3) |
| 141 | + |
| 142 | + sin_be_Th = np.sin(q1 + q2) |
| 143 | + cos_be_Th = np.cos(q1 + q2) |
| 144 | + sin_Ph_de = np.sin(q4 + q5) |
| 145 | + cos_Ph_de = np.cos(q4 + q5) |
| 146 | + sin_Om_ep = np.sin(q6 + q7) |
| 147 | + cos_Om_ep = np.cos(q6 + q7) |
| 148 | + |
| 149 | + g = np.zeros(nla) |
| 150 | + g[0] = rr * cos_be - d * cos_be_Th - ss * sin_ga - xb |
| 151 | + g[1] = rr * sin_be - d * sin_be_Th + ss * cos_ga - yb |
| 152 | + g[2] = rr * cos_be - d * cos_be_Th - e * sin_Ph_de - zt * np.cos(q5) - xa |
| 153 | + g[3] = rr * sin_be - d * sin_be_Th + e * cos_Ph_de - zt * np.sin(q5) - ya |
| 154 | + g[4] = rr * cos_be - d * cos_be_Th - zf * cos_Om_ep - u * np.sin(q7) - xa |
| 155 | + g[5] = rr * sin_be - d * sin_be_Th - zf * sin_Om_ep + u * np.cos(q7) - ya |
| 156 | + return g |
| 157 | + |
| 158 | + def g_q(t, vq): |
| 159 | + # beta, Theta, gamma, Phi, delta, Omega, epsilon |
| 160 | + q1, q2, q3, q4, q5, q6, q7 = vq |
| 161 | + |
| 162 | + sin_be = np.sin(q1) |
| 163 | + cos_be = np.cos(q1) |
| 164 | + sin_ga = np.sin(q3) |
| 165 | + cos_ga = np.cos(q3) |
| 166 | + |
| 167 | + sin_be_Th = np.sin(q1 + q2) |
| 168 | + cos_be_Th = np.cos(q1 + q2) |
| 169 | + sin_Ph_de = np.sin(q4 + q5) |
| 170 | + cos_Ph_de = np.cos(q4 + q5) |
| 171 | + sin_Om_ep = np.sin(q6 + q7) |
| 172 | + cos_Om_ep = np.cos(q6 + q7) |
| 173 | + |
| 174 | + g_q = np.zeros((nla, nq)) |
| 175 | + |
| 176 | + g_q[0, 0] = -rr * sin_be + d * sin_be_Th |
| 177 | + g_q[0, 1] = d * sin_be_Th |
| 178 | + g_q[0, 2] = -ss * cos_ga |
| 179 | + |
| 180 | + g_q[1, 0] = rr * cos_be - d * cos_be_Th |
| 181 | + g_q[1, 1] = - d * cos_be_Th |
| 182 | + g_q[1, 2] = -ss * sin_ga |
| 183 | + |
| 184 | + g_q[2, 0] = -rr * sin_be + d * sin_be_Th |
| 185 | + g_q[2, 1] = d * sin_be_Th |
| 186 | + g_q[2, 3] = -e * cos_Ph_de |
| 187 | + g_q[2, 4] = -e * cos_Ph_de + zt * np.sin(q5) |
| 188 | + |
| 189 | + g_q[3, 0] = rr * cos_be - d * cos_be_Th |
| 190 | + g_q[3, 1] = - d * cos_be_Th |
| 191 | + g_q[3, 3] = -e * sin_Ph_de |
| 192 | + g_q[3, 4] = -e * sin_Ph_de - zt * np.cos(q5) |
| 193 | + |
| 194 | + g_q[4, 0] = -rr * sin_be + d * sin_be_Th |
| 195 | + g_q[4, 1] = d * sin_be_Th |
| 196 | + g_q[4, 5] = zf * sin_Om_ep |
| 197 | + g_q[4, 6] = zf * sin_Om_ep - u * np.cos(q7) |
| 198 | + |
| 199 | + g_q[5, 0] = rr * cos_be - d * cos_be_Th |
| 200 | + g_q[5, 1] = -d * cos_be_Th |
| 201 | + g_q[5, 5] = -zf * cos_Om_ep |
| 202 | + g_q[5, 6] = -zf * cos_Om_ep - u * np.sin(q7) |
| 203 | + |
| 204 | + return g_q |
| 205 | + |
| 206 | + vq, vu, _, _ = np.split(y, [nq, 2 * nq, 2 * nq + nla]) |
| 207 | + vq_dot, vu_dot, vla, vmu = np.split(yp, [nq, 2 * nq, 2 * nq + nla]) |
| 208 | + |
| 209 | + g_q = g_q(t, vq) |
| 210 | + |
| 211 | + # # index 1 |
| 212 | + # return np.concatenate([ |
| 213 | + # vq_dot - vu, |
| 214 | + # M(t, vq) @ vu_dot - h(t, vq, vu) - g_q.T @ vla, |
| 215 | + # g_q @ vu, |
| 216 | + # vmu, |
| 217 | + # ]) |
| 218 | + |
| 219 | + # stabilized index 1 |
| 220 | + return np.concatenate([ |
| 221 | + vq_dot - vu + g_q.T @ vmu, |
| 222 | + M(t, vq) @ vu_dot - h(t, vq, vu) - g_q.T @ vla, |
| 223 | + g_q @ vu, |
| 224 | + g(t, vq), |
| 225 | + ]) |
| 226 | + |
| 227 | + |
| 228 | +if __name__ == "__main__": |
| 229 | + # time span |
| 230 | + t0 = 0 |
| 231 | + t1 = 0.03 |
| 232 | + t_span = (t0, t1) |
| 233 | + t_eval = np.linspace(t0, t1, num=int(1e3)) |
| 234 | + |
| 235 | + # tolerances |
| 236 | + rtol = atol = 1e-4 |
| 237 | + |
| 238 | + # initial conditions |
| 239 | + q0 = np.array([ |
| 240 | + -0.0617138900142764496358948458001, |
| 241 | + 0, |
| 242 | + 0.455279819163070380255912382449, |
| 243 | + 0.222668390165885884674473185609, |
| 244 | + 0.487364979543842550225598953530, |
| 245 | + -0.222668390165885884674473185609, |
| 246 | + 1.23054744454982119249735015568, |
| 247 | + ]) |
| 248 | + u0 = np.zeros(nq) |
| 249 | + la0 = np.zeros(nla) |
| 250 | + mu0 = np.zeros(nla) |
| 251 | + |
| 252 | + qp0 = u0.copy() |
| 253 | + up0 = np.array([ |
| 254 | + 14222.4439199541138705911625887, |
| 255 | + -10666.8329399655854029433719415, |
| 256 | + 0, |
| 257 | + 0, |
| 258 | + 0, |
| 259 | + 0, |
| 260 | + 0, |
| 261 | + ]) |
| 262 | + lap0 = np.array([ |
| 263 | + -98.5668703962410896057654982170, |
| 264 | + 6.12268834425566265503114393122, |
| 265 | + 0, |
| 266 | + 0, |
| 267 | + 0, |
| 268 | + 0, |
| 269 | + ]) |
| 270 | + mup0 = np.zeros(nla) |
| 271 | + |
| 272 | + y0 = np.concatenate([q0, u0, la0, mu0]) |
| 273 | + yp0 = np.concatenate([qp0, up0, lap0, mup0]) |
| 274 | + F0 = F(t0, y0, yp0) |
| 275 | + print(f"y0: {y0}") |
| 276 | + print(f"yp0: {yp0}") |
| 277 | + # print(f"F0 = {F0}") |
| 278 | + print(f"||F0|| = {np.linalg.norm(F0)}") |
| 279 | + # exit() |
| 280 | + # y0, yp0, fnorm = consistent_initial_conditions(F, t0, y0, yp0) |
| 281 | + # print(f"y0: {y0}") |
| 282 | + # print(f"yp0: {yp0}") |
| 283 | + # print(f"fnorm: {fnorm}") |
| 284 | + # # exit() |
| 285 | + |
| 286 | + ############## |
| 287 | + # dae solution |
| 288 | + ############## |
| 289 | + start = time.time() |
| 290 | + # method = "BDF" |
| 291 | + method = "Radau" |
| 292 | + sol = solve_dae(F, t_span, y0, yp0, atol=atol, rtol=rtol, method=method, t_eval=t_eval, stages=3) |
| 293 | + end = time.time() |
| 294 | + print(f"elapsed time: {end - start}") |
| 295 | + t = sol.t |
| 296 | + y = sol.y |
| 297 | + tp = t |
| 298 | + yp = sol.yp |
| 299 | + success = sol.success |
| 300 | + status = sol.status |
| 301 | + message = sol.message |
| 302 | + print(f"success: {success}") |
| 303 | + print(f"status: {status}") |
| 304 | + print(f"message: {message}") |
| 305 | + print(f"nfev: {sol.nfev}") |
| 306 | + print(f"njev: {sol.njev}") |
| 307 | + print(f"nlu: {sol.nlu}") |
| 308 | + |
| 309 | + # visualization |
| 310 | + rows = 4 |
| 311 | + cols = 2 |
| 312 | + fig, ax = plt.subplots(rows, cols) |
| 313 | + |
| 314 | + for i in range(7): |
| 315 | + ii = i // cols # Row index |
| 316 | + jj = i % cols # Column index |
| 317 | + |
| 318 | + yi = y[i] |
| 319 | + yi = (yi + np.pi) % (2 * np.pi) - np.pi |
| 320 | + ax[ii, jj].plot(t, yi, label=f"y{i} mod(2π)") |
| 321 | + ax[ii, jj].grid() |
| 322 | + ax[ii, jj].legend() |
| 323 | + |
| 324 | + plt.show() |
0 commit comments