grame / simulation.py
tiffank1802
Add missing simulation and utility modules
298ea8a
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):
# Prediction
x_pred = A @ x_est + B * u
P_pred = A @ P @ A.T + Q
# Update
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
# Initialize Kalman if needed
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] # open loop
e_set.append(0) # no error for kalman
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