127 lines
3.9 KiB
Python
127 lines
3.9 KiB
Python
import numpy as np
|
|||
|
|
from scipy.linalg import solve_discrete_lyapunov
|
||
|
|
import sys
|
||
|
|
import matplotlib.pyplot as plt
|
||
|
|
from generateGroudTruth import generate_ground_truth_system
|
||
|
|
|
||
|
|
|
||
|
|
def simulate_lti_data(A, B, C, D, T, sigma_process, sigma_measurement, rng_seed=None):
|
||
|
|
"""
|
||
|
|
使用 LTI 系统 (A, B, C, D) 仿真生成数据。
|
||
|
|
|
||
|
|
参数:
|
||
|
|
A (np.ndarray): 状态矩阵 (dx x dx)
|
||
|
|
B (np.ndarray): 输入矩阵 (dx x du)
|
||
|
|
C (np.ndarray): 观测矩阵 (dy x dx)
|
||
|
|
D (np.ndarray): 前馈矩阵 (dy x du)
|
||
|
|
T (int): 轨迹长度 (时间步数)
|
||
|
|
sigma_process (float): 过程噪声的标准差 (sigma_Sigma)
|
||
|
|
sigma_measurement (float): 测量噪声的标准差 (sigma_Gamma)
|
||
|
|
rng_seed (int, optional): 用于复现的随机种子
|
||
|
|
|
||
|
|
返回:
|
||
|
|
tuple: (u_data, y_data)
|
||
|
|
u_data (np.ndarray): 输入轨迹 (T x du)
|
||
|
|
y_data (np.ndarray): 输出轨迹 (T x dy)
|
||
|
|
"""
|
||
|
|
|
||
|
|
# 初始化随机数生成器
|
||
|
|
if rng_seed is None:
|
||
|
|
rng = np.random.default_rng()
|
||
|
|
else:
|
||
|
|
rng = np.random.default_rng(rng_seed)
|
||
|
|
|
||
|
|
# 从矩阵形状获取维度
|
||
|
|
dx = A.shape[0]
|
||
|
|
du = B.shape[1]
|
||
|
|
dy = C.shape[0]
|
||
|
|
|
||
|
|
# 初始化状态向量 x_0 = 0
|
||
|
|
x = np.zeros((dx, 1))
|
||
|
|
|
||
|
|
# 初始化用于存储历史数据的列表
|
||
|
|
x_history = []
|
||
|
|
y_history = []
|
||
|
|
u_history = []
|
||
|
|
|
||
|
|
# 生成噪声序列
|
||
|
|
# 输入 u_t ~ N(0, I)
|
||
|
|
u_data_gen = rng.standard_normal(size=(T, du, 1))
|
||
|
|
|
||
|
|
# 过程噪声 w_t ~ N(0, sigma_process^2 * I) [cite: 523]
|
||
|
|
w_data_gen = rng.normal(scale=sigma_process, size=(T, dx, 1))
|
||
|
|
|
||
|
|
# 测量噪声 z_t ~ N(0, sigma_measurement^2 * I) [cite: 523]
|
||
|
|
z_data_gen = rng.normal(scale=sigma_measurement, size=(T, dy, 1))
|
||
|
|
|
||
|
|
print(f"\n--- 开始仿真数据 (T={T}) ---")
|
||
|
|
print(f"过程噪声 (sigma_Sigma): {sigma_process}")
|
||
|
|
print(f"测量噪声 (sigma_Gamma): {sigma_measurement}")
|
||
|
|
|
||
|
|
# 循环 T 个时间步
|
||
|
|
for t in range(T):
|
||
|
|
u = u_data_gen[t]
|
||
|
|
w = w_data_gen[t]
|
||
|
|
z = z_data_gen[t]
|
||
|
|
|
||
|
|
# 1. 计算当前输出 y_t = C*x_t + D*u_t + z_t
|
||
|
|
y = C @ x + D @ u + z
|
||
|
|
|
||
|
|
# 2. 计算下一个状态 x_{t+1} = A*x_t + B*u_t + w_t
|
||
|
|
x_next = A @ x + B @ u + w
|
||
|
|
|
||
|
|
# 存储数据
|
||
|
|
u_history.append(u.squeeze())
|
||
|
|
y_history.append(y.squeeze())
|
||
|
|
x_history.append(x.squeeze())
|
||
|
|
|
||
|
|
# 更新状态
|
||
|
|
x = x_next
|
||
|
|
|
||
|
|
print("仿真完成。")
|
||
|
|
|
||
|
|
# 将列表转换为 numpy 数组
|
||
|
|
# 我们需要 (T, du) 和 (T, dy) 的形状
|
||
|
|
# 使用 .reshape(-1, du) 和 .reshape(-1, dy) 来处理 du/dy=1 的情况
|
||
|
|
u_data = np.array(u_history).reshape(T, du)
|
||
|
|
y_data = np.array(y_history).reshape(T, dy)
|
||
|
|
|
||
|
|
return u_data, y_data
|
||
|
|
|
||
|
|
if __name__ == '__main__':
|
||
|
|
# --- 运行示例 ---
|
||
|
|
|
||
|
|
# 1. 生成 Ground Truth 系统
|
||
|
|
# 使用与第一步相同的种子,确保系统一致
|
||
|
|
A_true, B_true, C_true, D_true = generate_ground_truth_system(rng_seed=42)
|
||
|
|
|
||
|
|
# 2. 仿真数据
|
||
|
|
# 根据 6.3 节的设置
|
||
|
|
T_steps = 400
|
||
|
|
sigma_proc = 0.3
|
||
|
|
sigma_meas = 0.0
|
||
|
|
|
||
|
|
# 使用不同的种子进行仿真,以确保数据和系统生成是独立的
|
||
|
|
u_data, y_data = simulate_lti_data(
|
||
|
|
A_true, B_true, C_true, D_true,
|
||
|
|
T=T_steps,
|
||
|
|
sigma_process=sigma_proc,
|
||
|
|
sigma_measurement=sigma_meas,
|
||
|
|
rng_seed=123
|
||
|
|
)
|
||
|
|
|
||
|
|
# 打印结果形状
|
||
|
|
print(f"\n--- 仿真结果 ---")
|
||
|
|
print(f"输入数据 u_data 形状: {u_data.shape}")
|
||
|
|
print(f"输出数据 y_data 形状: {y_data.shape}")
|
||
|
|
|
||
|
|
# 可视化检查
|
||
|
|
plt.figure(figsize=(12, 4))
|
||
|
|
plt.plot(y_data, label=f'Simulated Output $y_t$ (noise $\sigma_w={sigma_proc}$)')
|
||
|
|
plt.title('Simulated Data Trajectory (First Output Channel)')
|
||
|
|
plt.xlabel('Time Step $t$')
|
||
|
|
plt.ylabel('Output $y_t$')
|
||
|
|
plt.legend()
|
||
|
|
plt.grid(True)
|
||
|
|
plt.show()
|