|
|
import numpy as np |
|
|
from scipy.sparse.linalg import spsolve |
|
|
from beam import neb_beam_matrices, newmark1step_mrhs |
|
|
from noise import generate_noise_temporal |
|
|
|
|
|
def kalman_filter(z, x_est, P, A, B, H, Q, R, u=0): |
|
|
|
|
|
x_pred = A @ x_est + B * u |
|
|
P_pred = A @ P @ A.T + Q |
|
|
|
|
|
|
|
|
K = P_pred @ H.T @ np.linalg.inv(H @ P_pred @ H.T + R) |
|
|
x_est = x_pred + K @ (z - H @ x_pred) |
|
|
P = (np.eye(len(x_est)) - K @ H) @ P_pred |
|
|
|
|
|
return x_est, P |
|
|
|
|
|
def run_simulation(nstep=1000, delta=0.01, q=0.0001, r=0.0001, T=3, Kp=5e-1, Ki=1e-1, Kd=1e-2, mu=1e-1, beta=0.25, gamma=0.5, L=500, a=5, b=5, E=70000, rho=2700e-9, cy=1e-4, nx=10, nA=None, control_type='pid', meas_location='B'): |
|
|
if nA is None: |
|
|
nA = nx |
|
|
|
|
|
S = a * b |
|
|
Ix = a * b**3 / 12 |
|
|
dx = L / nx |
|
|
time = np.arange(delta, (nstep+1)*delta, delta) |
|
|
time0 = np.concatenate([[0], time]) |
|
|
|
|
|
ixe = np.arange(dx, L+dx, dx) |
|
|
|
|
|
is_matlab = True |
|
|
vseed1 = 0 |
|
|
vseed2 = 1 |
|
|
vseed3 = 2 |
|
|
|
|
|
npt = nx + 1 |
|
|
ndof = 2 * npt |
|
|
ndo1 = ndof - 2 |
|
|
induA = 2 * nA - 1 |
|
|
induB = 2 * nx - 1 |
|
|
|
|
|
fpert = generate_noise_temporal(time0, 1, q, vseed1, is_matlab) |
|
|
mpert = generate_noise_temporal(time0, 1, r, vseed2, is_matlab) |
|
|
|
|
|
fA = np.zeros_like(time0) |
|
|
fA[len(fA)//10:] = 1 |
|
|
|
|
|
ffull = np.zeros((ndof, nstep+1)) |
|
|
Kfull, Cfull, Mfull = neb_beam_matrices(nx, dx, E, Ix, rho, S, cy) |
|
|
K = Kfull[2:, 2:] |
|
|
C = Cfull[2:, 2:] |
|
|
M = Mfull[2:, 2:] |
|
|
f = ffull[2:, :] |
|
|
f[induA, :] = fA + fpert |
|
|
|
|
|
u0 = np.zeros(ndo1) |
|
|
v0 = np.zeros(ndo1) |
|
|
|
|
|
u = np.zeros((ndo1, nstep+1)) |
|
|
v = np.zeros((ndo1, nstep+1)) |
|
|
a = np.zeros((ndo1, nstep+1)) |
|
|
a0 = spsolve(M, f[:, 0] - C @ v0 - K @ u0) |
|
|
a[:, 0] = a0 |
|
|
u[:, 0] = u0 |
|
|
v[:, 0] = v0 |
|
|
|
|
|
integ_e = 0 |
|
|
prev_e = 0 |
|
|
t0 = 1.0 |
|
|
u_ref = (time0 >= t0).astype(float) |
|
|
e_set = [0] |
|
|
|
|
|
indu_meas = induA if meas_location == 'A' else induB |
|
|
|
|
|
|
|
|
if control_type in ['kalman', 'pid_kalman']: |
|
|
x_est = np.array([0.0, 0.0]) |
|
|
P = np.eye(2) * 0.1 |
|
|
A = np.array([[1, delta], [0, 1]]) |
|
|
H = np.array([1, 0]) |
|
|
Q = np.eye(2) * q |
|
|
R = r |
|
|
|
|
|
for step in range(1, nstep+1): |
|
|
if control_type == 'pid': |
|
|
u_meas = u[indu_meas, step-1] + mpert[step] |
|
|
e = u_ref[step] - u_meas |
|
|
integ_e += e * delta |
|
|
de = (e - prev_e) / delta |
|
|
Fpid = Kp * e + Ki * integ_e + Kd * de |
|
|
f_k = np.zeros(ndo1) |
|
|
f_k[induA] = Fpid + fpert[step] |
|
|
prev_e = e |
|
|
e_set.append(e) |
|
|
elif control_type == 'kalman': |
|
|
f_k = np.zeros(ndo1) |
|
|
f_k[induA] = fpert[step] |
|
|
e_set.append(0) |
|
|
elif control_type == 'pid_kalman': |
|
|
z = u[indu_meas, step-1] + mpert[step] |
|
|
x_est, P = kalman_filter(z, x_est, P, A, np.zeros(2), H, Q, R) |
|
|
u_est = x_est[0] |
|
|
e = u_ref[step] - u_est |
|
|
integ_e += e * delta |
|
|
de = (e - prev_e) / delta |
|
|
Fpid = Kp * e + Ki * integ_e + Kd * de |
|
|
f_k = np.zeros(ndo1) |
|
|
f_k[induA] = Fpid + fpert[step] |
|
|
prev_e = e |
|
|
e_set.append(e) |
|
|
|
|
|
u[:, step], v[:, step], a[:, step] = newmark1step_mrhs(M, C, K, f_k, u[:, step-1], v[:, step-1], a[:, step-1], delta, beta, gamma) |
|
|
|
|
|
return time0, ixe, u, v, a, e_set, fA |