import torch import torch.nn as nn import torch.optim as optim import numpy as np import matplotlib.pyplot as plt # 固定随机种子 torch.manual_seed(42) # 仿真电机模型 class MotorModel: def __init__(self): self.T = 0.1 self.dt = 0.01 self.speed = 0.0 def update(self, u): self.speed += (u - self.speed) * self.dt / self.T return self.speed # PyTorch 实现的 BP 神经网络 class BPNN_PID(nn.Module): def __init__(self): super(BPNN_PID, self).__init__() self.hidden_size = 5 self.fc1 = nn.Linear(3, self.hidden_size) # 输入层到隐藏层 self.fc2 = nn.Linear(self.hidden_size, 3) # 隐藏层到输出层 self.sigmoid = nn.Sigmoid() self.tanh = nn.Tanh() def forward(self, inputs): x = self.tanh(self.fc1(inputs)) x = self.sigmoid(self.fc2(x)) Kp = x[:, 0] * 10 Ki = x[:, 1] * 0.2 Kd = x[:, 2] * 0.5 Kp = torch.clamp(Kp, 0.1, 8) Ki = torch.clamp(Ki, 0.01, 0.15) Kd = torch.clamp(Kd, 0.05, 0.4) return Kp, Ki, Kd # 增量式PID控制器 class IncrementalPID: def __init__(self): self.Kp = 0.0 self.Ki = 0.0 self.Kd = 0.0 self.e_prev = [0.0, 0.0] self.u_prev = 0.0 def compute(self, error, dt): _u = self.Kp * (error - self.e_prev[0]) + \ self.Ki * error + \ self.Kd * (error - 2 * self.e_prev[0] + self.e_prev[1]) self.e_prev[1] = self.e_prev[0] self.e_prev[0] = error u = self.u_prev + _u u = np.clip(u, -1000, 1000) self.u_prev = u return u # 生成训练数据 def generate_dataset(): X = [] y = [] motor = MotorModel() for _ in range(1000): target = np.random.uniform(-500, 500) actual = motor.speed error = target - actual X.append([target / 1000, actual / 1000, error / 1000]) ideal_Kp = 5 * (1 - abs(error) / 1000) ideal_Ki = 0.1 * (1 - abs(error) / 1000) ideal_Kd = 0.2 * (abs(error) / 1000) y.append([ideal_Kp / 10, ideal_Ki / 0.2, ideal_Kd / 0.5]) motor.update(np.clip(error * 0.5, -1000, 1000)) return np.array(X), np.array(y) # 训练模型 def train_bpnn(model, epochs=100): X, y = generate_dataset() X_train = torch.tensor(X, dtype=torch.float32) y_train = torch.tensor(y, dtype=torch.float32) optimizer = optim.Adam(model.parameters(), lr=0.005) criterion = nn.MSELoss() for epoch in range(epochs): model.train() optimizer.zero_grad() # 前向传播 output = model(X_train) # 计算损失 # 正确写法应保持批次维度 kp_pred, ki_pred, kd_pred = output loss = criterion(kp_pred, y_train[:, 0]) + \ criterion(ki_pred, y_train[:, 1]) + \ criterion(kd_pred, y_train[:, 2]) # 反向传播 loss.backward() optimizer.step() if epoch % 10 == 0: print(f"Epoch [{epoch}/{epochs}], Loss: {loss.item():.4f}") # 主控制循环 def main(): motor = MotorModel() pid = IncrementalPID() model = BPNN_PID() train_bpnn(model, epochs=100) # 训练模型 # 导出模型为 ONNX 文件 dummy_input = torch.tensor([[0.5, 0.0, 0.0]], dtype=torch.float32) # 假设的输入 torch.onnx.export(model, dummy_input, "bpnn_pid_model.onnx", verbose=True) print("ONNX model has been saved as 'bpnn_pid_model.onnx'.") if __name__ == "__main__": main() 我想看到数据的变化情况
时间: 2025-06-10 19:04:34 浏览: 25
<think>好的,我现在需要帮助用户理解他们提供的代码,并且他们希望看到数据的变化情况。首先,我需要仔细阅读用户提供的代码,了解其结构和功能。用户使用了PyTorch实现了一个BP神经网络来调整PID控制器的参数,并且有一个电机模型进行仿真。用户现在想看到数据的变化情况,可能需要可视化训练过程中的损失变化、PID参数调整情况或者电机速度的跟踪效果。
首先,我需要确定用户具体想看到哪些数据的变化。可能的情况包括:训练过程中损失函数的变化曲线,实际电机速度与目标速度的跟踪曲线,或者PID参数(Kp, Ki, Kd)在训练过程中的调整情况。由于用户提到“数据的变化情况”,可能需要同时考虑多个方面的可视化。
接下来,我需要检查现有代码,看看是否有生成这些可视化数据的部分。用户提供的代码中,训练函数`train_bpnn`里有打印损失值,但没有记录损失历史,也没有绘图部分。主函数`main`中训练完模型后导出了ONNX模型,但没有运行控制循环来测试PID控制效果,因此也没有相关的数据记录。
为了生成可视化数据,我需要在代码中添加数据记录的功能。例如,在训练过程中记录每个epoch的损失值,或者在控制循环中记录电机速度、目标速度以及PID参数的变化。然后,使用matplotlib将这些数据绘制成图表。
可能的修改步骤包括:
1. 在`train_bpnn`函数中添加一个列表来记录每个epoch的损失值,并在训练结束后绘制损失曲线。
2. 在生成训练数据时,可能已经有一些数据,但用户提供的`generate_dataset`函数主要用于生成训练输入和目标输出,可能不包含实际控制过程中的动态数据。
3. 添加一个测试函数,在训练完成后,运行一个控制循环,模拟电机控制过程,记录速度、误差、PID参数等数据,并绘制相应的图表。
用户可能希望看到训练后的模型在实际控制中的表现,比如电机速度如何跟踪目标值,以及PID参数如何根据误差动态调整。因此,添加一个测试循环来模拟控制过程,并记录相关数据是关键。
此外,用户提供的代码中,`main`函数在训练后直接导出模型,但没有进行测试。因此,需要在`main`函数中添加测试部分,或者创建一个新的函数来执行控制循环并收集数据。
另一个考虑是,用户是否希望实时查看训练过程中的损失下降,或者在训练结束后查看最终效果。根据代码结构,可能在训练结束后生成图表更为合适。
还需要注意代码中的潜在问题。例如,在训练循环中,计算损失时,原来的代码可能有维度不匹配的问题,因为`output`是一个元组,而`y_train`是二维张量。需要确保损失计算正确,避免错误。
总结需要进行的修改:
- 在训练过程中记录损失历史,并绘制损失曲线。
- 添加测试控制循环,运行训练好的模型,调整PID参数,控制电机速度,并记录相关数据。
- 在测试循环中,记录时间步、目标速度、实际速度、误差、Kp、Ki、Kd等数据。
- 使用matplotlib绘制多个子图,展示速度跟踪效果和PID参数变化。
这样,用户就能直观地看到模型训练的效果以及控制过程中各参数的变化情况,从而更好地理解系统的工作状态。</think>好的!为了让您更直观地理解这个BP神经网络PID控制器的训练效果和系统响应,我们可以添加数据可视化部分。以下是修改后的代码和解释:
```python
# 修改后的训练函数(添加损失记录)
def train_bpnn(model, epochs=100):
X, y = generate_dataset()
X_train = torch.tensor(X, dtype=torch.float32)
y_train = torch.tensor(y, dtype=torch.float32)
optimizer = optim.Adam(model.parameters(), lr=0.005)
criterion = nn.MSELoss()
# 记录训练损失
loss_history = []
for epoch in range(epochs):
model.train()
optimizer.zero_grad()
# 前向传播
Kp_pred, Ki_pred, Kd_pred = model(X_train)
# 计算损失
loss = criterion(Kp_pred, y_train[:, 0]) + \
criterion(Ki_pred, y_train[:, 1]) + \
criterion(Kd_pred, y_train[:, 2])
# 反向传播
loss.backward()
optimizer.step()
loss_history.append(loss.item())
if epoch % 10 == 0:
print(f"Epoch [{epoch}/{epochs}], Loss: {loss.item():.4f}")
# 绘制损失曲线
plt.figure(figsize=(10, 5))
plt.plot(loss_history, label='Training Loss')
plt.xlabel('Epoch')
plt.ylabel('Loss')
plt.title('Training Loss Curve')
plt.grid(True)
plt.legend()
plt.show()
# 新增测试函数
def test_control(model):
motor = MotorModel()
pid = IncrementalPID()
# 记录数据
time_steps = []
targets = []
actuals = []
errors = []
Kps = []
Kis = []
Kds = []
# 创建正弦波目标信号
target_signal = 500 * np.sin(np.linspace(0, 4*np.pi, 400))
for t in range(400):
# 生成目标值
target = target_signal[t]
actual = motor.speed
error = target - actual
# 神经网络计算PID参数
with torch.no_grad():
inputs = torch.tensor([[target/1000, actual/1000, error/1000]],
dtype=torch.float32)
Kp, Ki, Kd = model(inputs)
# 更新PID参数
pid.Kp = Kp.item()
pid.Ki = Ki.item()
pid.Kd = Kd.item()
# 计算控制量
u = pid.compute(error, dt=0.01)
motor.update(u)
# 记录数据
time_steps.append(t*0.01)
targets.append(target)
actuals.append(actual)
errors.append(error)
Kps.append(Kp.item())
Kis.append(Ki.item())
Kds.append(Kd.item())
# 绘制结果
plt.figure(figsize=(12, 10))
# 速度跟踪
plt.subplot(3, 1, 1)
plt.plot(time_steps, targets, label='Target Speed', linestyle='--')
plt.plot(time_steps, actuals, label='Actual Speed', alpha=0.8)
plt.xlabel('Time (s)')
plt.ylabel('Speed')
plt.title('Speed Tracking Performance')
plt.legend()
plt.grid(True)
# 参数变化
plt.subplot(3, 1, 2)
plt.plot(time_steps, Kps, label='Kp')
plt.plot(time_steps, Kis, label='Ki')
plt.plot(time_steps, Kds, label='Kd')
plt.xlabel('Time (s)')
plt.ylabel('PID Parameters')
plt.title('Parameter Adjustment')
plt.legend()
plt.grid(True)
# 跟踪误差
plt.subplot(3, 1, 3)
plt.plot(time_steps, errors, label='Error', color='r')
plt.xlabel('Time (s)')
plt.ylabel('Error')
plt.title('Tracking Error')
plt.grid(True)
plt.tight_layout()
plt.show()
# 修改后的主函数
def main():
model = BPNN_PID()
train_bpnn(model, epochs=100) # 训练模型(会自动显示损失曲线)
test_control(model) # 测试控制效果(显示跟踪效果)
# 导出模型...
```
运行代码后,您将看到三个可视化图表:
1. **训练损失曲线**

*横轴:训练轮次,纵轴:损失值,展示模型收敛情况*
2. **速度跟踪效果**

*蓝色虚线为目标速度,橙色实线为实际速度,展示系统跟踪性能*
3. **参数动态调整**

*展示Kp(比例)、Ki(积分)、Kd(微分)参数随时间的变化*
4. **跟踪误差**

*红色曲线显示目标值与实际值的误差变化*
**代码改进说明:**
1. 训练过程可视化:添加了损失曲线绘制,帮助观察模型收敛情况
2. 新增测试函数`test_control`:
- 使用正弦波作为目标信号(更直观展示跟踪性能)
- 记录并可视化PID参数的自适应变化过程
- 显示跟踪误差的动态变化
3. 使用子图形式展示多维数据,便于对比分析
通过观察这些可视化结果,您可以:
- 确认神经网络是否有效收敛(损失曲线是否平稳下降)
- 评估控制系统对动态目标的跟踪能力
- 分析PID参数的自适应调整是否合理
- 诊断系统存在的问题(如过冲、振荡等)
如果需要更深入分析特定区间的数据,可以修改`test_control`函数中的目标信号生成方式(例如改为阶跃信号),或者调整可视化代码的坐标轴范围。
阅读全文
相关推荐


















