Files
RL_Engine_Control/test_pid.py
T

189 lines
5.9 KiB
Python
Raw Normal View History

2025-12-30 19:10:49 +08:00
import numpy as np
import matplotlib.pyplot as plt
from engine_env.engine_env import AeroEngineGymEnv
# ==========================================
# 1. 增量式 PID 类 (保持不变)
# ==========================================
class IncrementalPIDController:
def __init__(self, kp, ki, kd, output_min=-1.0, output_max=1.0):
self.kp = kp
self.ki = ki
self.kd = kd
self.min_val = output_min
self.max_val = output_max
self.error_prev = 0.0
self.error_prev2 = 0.0
self.current_output = 0.0
def set_current_output(self, value):
self.current_output = np.clip(value, self.min_val, self.max_val)
self.error_prev = 0.0
self.error_prev2 = 0.0
def update(self, error, dt):
delta_p = self.kp * (error - self.error_prev)
delta_i = self.ki * error * dt
delta_d = self.kd * (error - 2*self.error_prev + self.error_prev2) / dt
delta_u = delta_p + delta_i + delta_d
self.current_output += delta_u
self.current_output = np.clip(self.current_output, self.min_val, self.max_val)
self.error_prev2 = self.error_prev
self.error_prev = error
return self.current_output
# ==========================================
# 2. 主测试逻辑
# ==========================================
def run_pid_test():
env = AeroEngineGymEnv()
# -----------------------------------------------------
# 【关键修改】定义正确的 PID 配对
# -----------------------------------------------------
# Loop 1: 目标 NH -> 控制 Wf (燃油)
# 逻辑: NH 低 -> 加油 (正反馈)
pid_nh_wf = IncrementalPIDController(kp=10.0, ki=6.0, kd=0.1)
# Loop 2: 目标 NL -> 控制 A8 (喷管)
pid_nl_a8 = IncrementalPIDController(kp=-4.0, ki=3.0, kd=0.05)
total_steps = 3000 # 60秒
obs, info = env.reset(options={'pla': 0.0})
# 状态标志位
pid_initialized = False
history = {
'time': [], 'PLA': [], 'NH': [], 'Target_NH': [], 'NL': [], 'Target_NL': [],
'Wf_Action': [], 'A8_Action': [], 'Reward': []
}
print("开始修正后的 PID 仿真 (NH->Wf, NL->A8)...")
for step in range(total_steps):
t = step * env.dt
# --- A. 任务剖面 ---
if t < 2.0: current_pla = 0.0
elif t < 20.0: current_pla = 15.0
else: current_pla = 60.0
env.set_pla(current_pla)
# --- B. 获取状态 ---
real_nh, real_nl = obs[0], obs[1]
target_nh, target_nl = obs[4], obs[5]
# 计算误差
error_nh = target_nh - real_nh
error_nl = target_nl - real_nl
action = np.zeros(5)
# =========================================================
# C. 分阶段控制
# =========================================================
# --- 阶段 1: 起动 (Open Loop) ---
if current_pla >= 15.0 and real_nh < 0.60:
action[2] = 0.8 # 起动机
action[3] = -0.6 # 点火油量
action[4] = 1.0 # 喷管全开
pid_initialized = False
# --- 阶段 2: 闭环控制 (Closed Loop) ---
elif current_pla >= 15.0 and real_nh >= 0.60:
# 无扰切换
if not pid_initialized:
print(f"[Switch] t={t:.2f}s, 切入闭环。PID1: NH->Fuel(-0.6), PID2: NL->A8(1.0)")
# NH控制燃油,继承 -0.6
pid_nh_wf.set_current_output(-0.6)
# NL控制喷管,继承 1.0
pid_nl_a8.set_current_output(1.0)
pid_initialized = True
action[2] = -1.0
# 【核心修正】 PID 计算
# Loop 1: 用 NH 的误差算 Wf
wf_out = pid_nh_wf.update(error_nh, env.dt)
# Loop 2: 用 NL 的误差算 A8
a8_out = pid_nl_a8.update(error_nl, env.dt)
action[3] = wf_out
action[4] = a8_out
# --- 阶段 3: 停机 ---
else:
action = np.array([0,0,-1,-1,1])
pid_initialized = False
# --- D. 执行 ---
obs, reward, terminated, truncated, info = env.step(action)
# 记录
history['time'].append(t)
history['PLA'].append(current_pla)
history['NH'].append(real_nh)
history['Target_NH'].append(target_nh)
history['NL'].append(real_nl)
history['Target_NL'].append(target_nl)
history['Wf_Action'].append(action[3])
history['A8_Action'].append(action[4])
history['Reward'].append(reward)
if terminated:
print(f"Terminated at {t:.2f}s")
break
env.close()
plot_results(history)
def plot_results(history):
t = history['time']
plt.figure(figsize=(12, 8))
# 1. Speed
plt.subplot(2, 2, 1)
plt.plot(t, history['Target_NH'], 'r--', alpha=0.6)
plt.plot(t, history['NH'], 'r', label='NH (Controlled by Fuel)')
plt.plot(t, history['Target_NL'], 'b--', alpha=0.6)
plt.plot(t, history['NL'], 'b', label='NL (Controlled by A8)')
plt.legend()
plt.title('Rotor Speeds')
plt.grid(True)
# 2. Action
plt.subplot(2, 2, 2)
plt.plot(t, history['Wf_Action'], 'orange', label='Fuel (Wf)')
plt.plot(t, history['A8_Action'], 'green', label='Nozzle (A8)')
plt.legend()
plt.title('Control Actions')
plt.ylim(-1.1, 1.1)
plt.grid(True)
# 3. PLA
plt.subplot(2, 2, 3)
plt.plot(t, history['PLA'], 'k')
plt.title('PLA')
plt.grid(True)
# 4. Reward
plt.subplot(2, 2, 4)
plt.plot(t, history['Reward'])
plt.title('Reward')
plt.grid(True)
plt.tight_layout()
plt.show()
if __name__ == "__main__":
run_pid_test()