当前位置: 首页 > article >正文

基于 BP 神经网络整定的 PID 控制

基于 BP 神经网络整定的 PID 控制 是一种结合了经典 PID 控制和 BP(反向传播)神经网络的自适应控制方法。在这种方法中,神经网络用于在线调整 PID 控制器的参数(比例增益 KpK_pKp​,积分增益 KiK_iKi​ 和微分增益 KdK_dKd​)。神经网络通过学习系统的误差信号,自动调节 PID 参数,从而优化控制性能,尤其是在面对非线性、时变或复杂系统时。

1. 基本原理

(1) PID 控制器概述

PID 控制器是根据误差和误差的变化量调整控制信号,以实现系统的稳定和快速响应。PID 控制器的控制信号计算公式为:

(2) BP 神经网络概述

BP 神经网络是一种常见的前馈神经网络,通过反向传播算法进行训练,逐步调整网络的权重。BP 神经网络通常包括输入层、隐层和输出层。网络的目标是通过最小化误差函数,学习输入和输出之间的映射关系。

在基于 BP 神经网络整定的 PID 控制中,神经网络的输入是系统的误差信号和误差变化量,输出是 PID 控制器的三个增益(KpK_pKp​,KiK_iKi​,KdK_dKd​)的调整量。神经网络通过优化这些增益,使得控制系统的误差最小化。

3. C++实现基于 BP 神经网络整定的 PID 控制

以下是一个简化版的基于 BP 神经网络整定的 PID 控制的 C++ 实现:

#include <iostream>
#include <vector>
#include <cmath>

class BPNeuralNetwork {
private:
    int input_size, hidden_size, output_size;
    double learning_rate;
    std::vector<std::vector<double>> input_to_hidden_weights;  // 输入到隐藏层的权重
    std::vector<std::vector<double>> hidden_to_output_weights; // 隐藏层到输出层的权重
    std::vector<double> hidden_bias, output_bias;
    std::vector<double> hidden_output, network_output;

public:
    BPNeuralNetwork(int input_size, int hidden_size, int output_size, double learning_rate = 0.1)
        : input_size(input_size), hidden_size(hidden_size), output_size(output_size), learning_rate(learning_rate) {
        // 初始化权重和偏置
        input_to_hidden_weights = std::vector<std::vector<double>>(input_size, std::vector<double>(hidden_size));
        hidden_to_output_weights = std::vector<std::vector<double>>(hidden_size, std::vector<double>(output_size));
        hidden_bias = std::vector<double>(hidden_size, 0.0);
        output_bias = std::vector<double>(output_size, 0.0);
        hidden_output = std::vector<double>(hidden_size, 0.0);
        network_output = std::vector<double>(output_size, 0.0);

        // 随机初始化权重
        for (int i = 0; i < input_size; ++i)
            for (int j = 0; j < hidden_size; ++j)
                input_to_hidden_weights[i][j] = (rand() % 1000) / 1000.0;  // 初始化为 [0, 1] 区间的随机数
        for (int i = 0; i < hidden_size; ++i)
            for (int j = 0; j < output_size; ++j)
                hidden_to_output_weights[i][j] = (rand() % 1000) / 1000.0;  // 初始化为 [0, 1] 区间的随机数
    }

    // 激活函数(sigmoid)
    double sigmoid(double x) {
        return 1.0 / (1.0 + exp(-x));
    }

    // 激活函数的导数(sigmoid的导数)
    double sigmoid_derivative(double x) {
        return x * (1.0 - x);
    }

    // 前向传播
    std::vector<double> forward(const std::vector<double>& input) {
        // 输入到隐藏层
        for (int i = 0; i < hidden_size; ++i) {
            hidden_output[i] = 0.0;
            for (int j = 0; j < input_size; ++j)
                hidden_output[i] += input[j] * input_to_hidden_weights[j][i];
            hidden_output[i] += hidden_bias[i];
            hidden_output[i] = sigmoid(hidden_output[i]);
        }

        // 隐藏层到输出层
        for (int i = 0; i < output_size; ++i) {
            network_output[i] = 0.0;
            for (int j = 0; j < hidden_size; ++j)
                network_output[i] += hidden_output[j] * hidden_to_output_weights[j][i];
            network_output[i] += output_bias[i];
            network_output[i] = sigmoid(network_output[i]);
        }

        return network_output;
    }

    // 反向传播
    void backward(const std::vector<double>& input, const std::vector<double>& target) {
        // 输出层误差
        std::vector<double> output_errors(output_size);
        for (int i = 0; i < output_size; ++i)
            output_errors[i] = target[i] - network_output[i];

        // 隐藏层误差
        std::vector<double> hidden_errors(hidden_size);
        for (int i = 0; i < hidden_size; ++i) {
            hidden_errors[i] = 0.0;
            for (int j = 0; j < output_size; ++j)
                hidden_errors[i] += output_errors[j] * hidden_to_output_weights[i][j];
            hidden_errors[i] *= sigmoid_derivative(hidden_output[i]);
        }

        // 更新输出层权重
        for (int i = 0; i < output_size; ++i) {
            for (int j = 0; j < hidden_size; ++j) {
                hidden_to_output_weights[j][i] += learning_rate * output_errors[i] * hidden_output[j];
            }
            output_bias[i] += learning_rate * output_errors[i];
        }

        // 更新隐藏层权重
        for (int i = 0; i < hidden_size; ++i) {
            for (int j = 0; j < input_size; ++j) {
                input_to_hidden_weights[j][i] += learning_rate * hidden_errors[i] * input[j];
            }
            hidden_bias[i] += learning_rate * hidden_errors[i];
        }
    }
};

class BPNeuralNetworkPIDController {
private:
    double Kp, Ki, Kd;
    BPNeuralNetwork nn;

public:
    BPNeuralNetworkPIDController(double Kp_init, double Ki_init, double Kd_init)
        : Kp(Kp_init), Ki(Ki_init), Kd(Kd_init), nn(3, 5, 3) {}

    double compute(double setpoint, double actual) {
        double error = setpoint - actual;
        double delta_error = error;  // 假设每次误差变化为当前误差

        // 神经网络的输入为误差和误差变化量
        std::vector<double> input = { error, delta_error, Ki };
        std::vector<double> output = nn.forward(input);

        // 使用神经网络输出调整PID增益
        Kp += output[0];
        Ki += output[1];
        Kd += output[2];

        // 计算控制信号
        double control_signal = Kp * error + Ki * error + Kd * delta_error;

        return control_signal;
    }
};

int main() {
    BPNeuralNetworkPIDController pid_controller(1.0, 0.1, 0.01);
    double setpoint = 10.0;
    double actual = 0.0;

    for (int step = 0; step < 50; ++step) {
        double control_signal = pid_controller.compute(setpoint, actual);
        actual += control_signal * 0.1;  // 假设控制信号对系统的影响
        std::cout << "Step: " << step << ", Control Signal: " << control_signal << ", Actual Output: " << actual << std::endl;
    }

    return 0;
}

4. 解释代码

  • BPNeuralNetwork 类:该类实现了一个简单的三层BP神经网络。输入层有3个输入节点(误差、误差变化量和Ki),输出层有3个节点(分别对应 KpK_pKp​、KiK_iKi​ 和 KdK_dKd​ 的调整量)。网络使用反向传播算法更新权重和偏置。
  • BPNeuralNetworkPIDController 类:这个类实现了基于 BP 神经网络整定的 PID 控制。它根据误差和误差变化量通过神经网络计算 PID 控制器的增益,并计算控制信号。

5. 总结

基于 BP 神经网络整定的 PID 控制方法,通过神经网络自适应地调整 PID 参数,从而优化控制性能。这种方法尤其适用于动态和非线性系统,在系统的特性发生变化时,神经网络能够自我调整 PID 参数,保持系统的稳定性和快速响应。


http://www.kler.cn/a/409341.html

相关文章:

  • 探索 Vue的nextTick :原理剖析、使用场景及代码实践详解
  • 【通俗理解】边际化技巧在概率论中的应用——从公式到实例
  • C语言蓝桥杯组题目
  • android bindService打开失败
  • 论文阅读——Intrusion detection systems using longshort‑term memory (LSTM)
  • 3D Gaussian Splatting在鱼眼相机中的应用与投影变换
  • 根据气候变化自动制定鲜花存储策略(BabyAGI)
  • MCSA --- make coding simple again
  • C#里怎么样实现多播委托?
  • AIGC-------AIGC与创意写作:威胁还是机遇?
  • [webgis 0基础到找工作]------JavaScript进阶--作用域,解构,函数 day14
  • [webgis 0基础到找工作]------JavaScript--Bom day12
  • 地平线 bev_cft_efficientnetb3 参考算法-v1.2.1
  • 如何进行高级红队测试:OpenAI的实践与方法
  • HTTPSOK ---助力阿里云免费 SSL 证书自动续期
  • 废品买卖回收管理系统|Java|SSM|Vue| 前后端分离
  • Jmeter中的定时器
  • 基于STM32F103的FreeRTOS系列(十四)·软件定时器
  • 【Excel】拆分多个sheet,为单一表格
  • 微调Helsinki-NLP-en-zh模型
  • Python爬虫:如何从1688阿里巴巴获取公司信息
  • RTVS视频服务应用
  • [Golang]传递一个切片(slice)和使用变参(...)语法传递多个参数之间的区别
  • 力扣第 62 题(Unique Paths)两种递归实现
  • 40分钟学 Go 语言高并发:原子操作与CAS
  • nature communications论文 解读