自适应模糊PID控制,理论+仿真

不太喜欢写理论,模糊PID的相关内容可以参考书籍《模糊控制系统及应用》,《先进PID控制MATLAB仿真》里也简单描述了一下基本理论。
简单来说,自适应模糊PID控制器以误差 e e e 和误差变化 e c ec ec 作为模糊控制器的输入,利用模糊控制规则在线对PID参数进行调整,以满足不同时刻的 e e e e c ec ec 对PID参数自整定的要求。自适应模糊PID控制器系统结构如下图所示:
在这里插入图片描述
控制率和PID一样:
u ( k ) = k p e ( k ) + k i T ∑ k e ( j ) + k d 1 T ( e ( k ) − e ( k − 1 ) ) u(k) = k_p e(k)+k_i T \sum^k e(j)+k_d \frac{1}{T}(e(k)-e(k-1)) u(k)=kpe(k)+kiTke(j)+kdT1(e(k)e(k1))
δ k p , δ k i , δ k d \delta kp, \delta ki, \delta kd δkp,δki,δkd模糊规则如下:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
输入输出的隶属函数如下:
在这里插入图片描述
大致流程如下:

  • e e e e c ec ec 值量化为论域值。
  • 利用该论域值计算PID参数增量 δ k p , δ k i , δ k d \delta kp, \delta ki, \delta kd δkp,δki,δkd的论域值。
  • 将PID参数增量论域值反量化为实际的增量值。
  • 自调整PID参数。

假设控制对象为:
P ( s ) = 133 s 2 + 25 ⋅ s P(s) = \frac{133}{s^2+25\cdot s} P(s)=s2+25s133
代码如下(看懂就都会了):
FuzzyPID.m

% created by hyacinth on 2024/5/31
classdef FuzzyPID < handle
    properties
        e_max       % 模糊集论域
        e_min
        ec_max
        ec_min
        delta_kpmax % pid参数增量最大最小值
        delta_kpmin
        delta_kimax
        delta_kimin
        delta_kdmax
        delta_kdmin
        dt

        kp          % pid参数
        ki
        kd

        qdelta_kp   % pid参数增量论域值
        qdelta_ki
        qdelta_kd

        delta_kp    % pid参数增量值
        delta_ki
        delta_kd

        qerro       % 误差相关论域值
        qerro_c

        pre_err     % 前一时刻误差
        erri        % 积分项

        threshold

        e_gradmembership        % 输入的隶属度,形状(1,2) or (1,1)
        ec_gradmembership
        e_grad_idx              % 隶属度在模糊子集中的位置,形状(1,2) or (1,1)
        ec_grad_idx
        delta_kp_grad_sums      % pid参数增量总隶属度,形状(1,7)
        delta_ki_grad_sums
        delta_kd_grad_sums

        kp_rule_list            % 模糊规则,形状(7,7)
        ki_rule_list
        kd_rule_list

        e_membership_values     % 输入输出的模糊子集,形状(1,7)
        ec_membership_values
        kp_menbership_values
        ki_menbership_values
        kd_menbership_values
    end
    methods
        % 构造函数,初始化模糊系统
        function obj = FuzzyPID(e_max,e_min,ec_max,ec_min,kp0,ki0,kd0, ...
                delta_kpmax,delta_kpmin,delta_kimax,delta_kimin,delta_kdmax,delta_kdmin,threshold,dt)
            obj.e_max = e_max;
            obj.e_min = e_min;
            obj.ec_max = ec_max;
            obj.ec_min = ec_min;
            obj.delta_kpmax = delta_kpmax;
            obj.delta_kpmin = delta_kpmin;
            obj.delta_kimax = delta_kimax;
            obj.delta_kimin = delta_kimin;
            obj.delta_kdmax = delta_kdmax;
            obj.delta_kdmin = delta_kdmin;
            
            obj.kp = kp0;
            obj.ki = ki0;
            obj.kd = kd0;
            obj.qdelta_kp = 0;
            obj.qdelta_ki = 0;
            obj.qdelta_kd = 0;
            obj.pre_err = 0;
            obj.erri = 0;
            obj.threshold = threshold;
            obj.dt = dt;

            NB = -3;
            NM = -2;
            NS = -1;
            ZO = 0;
            PS = 1;
            PM = 2;
            PB = 3;

            obj.e_membership_values = [NB,NM,NS,ZO,PS,PM,PB];
            obj.ec_membership_values = [NB,NM,NS,ZO,PS,PM,PB];
            obj.kp_menbership_values = [NB,NM,NS,ZO,PS,PM,PB];
            obj.ki_menbership_values = [NB,NM,NS,ZO,PS,PM,PB];
            obj.kd_menbership_values = [NB,NM,NS,ZO,PS,PM,PB];

            obj.kp_rule_list = [PB,PB,PM,PM,PS,ZO,ZO;
                                PB,PB,PM,PS,PS,ZO,NS;
                                PM,PM,PM,PS,ZO,NS,NS;
                                PM,PM,PS,ZO,NS,NM,NM;
                                PS,PS,ZO,NS,NS,NM,NM;
                                PS,ZO,NS,NM,NM,NM,NB;
                                ZO,ZO,NM,NM,NM,NB,NB];
            obj.ki_rule_list = [NB,NB,NM,NM,NS,ZO,ZO;
                                NB,NB,NM,NS,NS,ZO,ZO;
                                NB,NM,NS,NS,ZO,PS,PS;
                                NM,NM,NS,ZO,PS,PM,PM;
                                NM,NS,ZO,PS,PS,PM,PB;
                                ZO,ZO,PS,PS,PM,PB,PB;
                                ZO,ZO,PS,PM,PM,PB,PB];
            obj.kd_rule_list = [PS,NS,NB,NB,NB,NM,PS;
                                PS,NS,NB,NM,NM,NS,ZO;
                                ZO,NS,NM,NM,NS,NS,ZO;
                                ZO,NS,NS,NS,NS,NS,ZO;
                                ZO,ZO,ZO,ZO,ZO,ZO,ZO;
                                PB,NS,PS,PS,PS,PS,PB;
                                PB,PM,PM,PM,PS,PS,PB];
        end

        % 计算输入的隶属度及其在模糊子集中的位置
        function get_grad_membership(obj, erro, erro_c)
            if erro > obj.e_membership_values(1) && erro <= obj.e_membership_values(end)
                for i = 1:length(obj.e_membership_values)-1
                    if erro > obj.e_membership_values(i) && erro <= obj.e_membership_values(i+1)
                        obj.e_gradmembership(1) = -(erro-obj.e_membership_values(i+1))/(obj.e_membership_values(i+1)-obj.e_membership_values(i));
                        obj.e_gradmembership(2) = 1+(erro-obj.e_membership_values(i+1))/(obj.e_membership_values(i+1)-obj.e_membership_values(i));
                        obj.e_grad_idx(1) = i;
                        obj.e_grad_idx(2) = i + 1;
                    end
                end
            else
                if erro <= obj.e_membership_values(1)
                    obj.e_gradmembership(1) = 1;
                    obj.e_grad_idx(1) = 1;
                elseif erro > obj.e_membership_values(end)
                    obj.e_gradmembership(1) = 1;
                    obj.e_grad_idx(1) = 7;
                end
            end
            if erro_c > obj.ec_membership_values(1) && erro_c <= obj.ec_membership_values(end)
                for i = 1:length(obj.ec_membership_values)-1
                    if erro_c > obj.ec_membership_values(i) && erro_c <= obj.ec_membership_values(i+1)
                        obj.ec_gradmembership(1) = -(erro_c- obj.ec_membership_values(i+1)) / (obj.ec_membership_values(i+1) - obj.ec_membership_values(i));
                        obj.ec_gradmembership(2) = 1+(erro_c - obj.ec_membership_values(i+1))/(obj.ec_membership_values(i + 1) - obj.ec_membership_values(i));
                        obj.ec_grad_idx(1) = i;
                        obj.ec_grad_idx(2) = i + 1;
                    end
                end
            else
                if erro_c <= obj.ec_membership_values(1)
                    obj.ec_gradmembership(1) = 1;
                    obj.ec_grad_idx(1) = 1;
                elseif erro_c > obj.ec_membership_values(end)
                    obj.ec_gradmembership(1) = 1;
                    obj.ec_grad_idx(1) = 7;
                end
            end
        end

        % 计算pid参数增量总隶属度
        function getsumgrad(obj)
            for i=1:7
                obj.delta_kp_grad_sums(i) = 0;
                obj.delta_ki_grad_sums(i) = 0;
                obj.delta_kd_grad_sums(i) = 0;
            end
            for i=1:length(obj.e_grad_idx)
                for j=1:length(obj.ec_grad_idx)
                    idx_kp = obj.kp_rule_list(obj.e_grad_idx(i),obj.ec_grad_idx(j)) + 4;
                    idx_ki = obj.ki_rule_list(obj.e_grad_idx(i),obj.ec_grad_idx(j)) + 4;
                    idx_kd = obj.kd_rule_list(obj.e_grad_idx(i),obj.ec_grad_idx(j)) + 4;
                    obj.delta_kp_grad_sums(idx_kp) = obj.delta_kp_grad_sums(idx_kp) + obj.e_gradmembership(i)*obj.ec_gradmembership(j);
                    obj.delta_ki_grad_sums(idx_ki) = obj.delta_ki_grad_sums(idx_ki) + obj.e_gradmembership(i)*obj.ec_gradmembership(j);
                    obj.delta_kd_grad_sums(idx_kd) = obj.delta_kd_grad_sums(idx_kd) + obj.e_gradmembership(i)*obj.ec_gradmembership(j);
                end
            end
        end

        % 获取pid参数增量论域值
        function getout(obj)
            obj.qdelta_kp = 0;
            obj.qdelta_ki = 0;
            obj.qdelta_kd = 0;
            for i=1:7
                obj.qdelta_kp = obj.qdelta_kp + obj.kp_menbership_values(i)*obj.delta_kp_grad_sums(i);
                obj.qdelta_ki = obj.qdelta_ki + obj.ki_menbership_values(i)*obj.delta_ki_grad_sums(i);
                obj.qdelta_kd = obj.qdelta_kd + obj.kd_menbership_values(i)*obj.delta_kd_grad_sums(i);
            end
        end

        % 量化函数
        function y = quantization(~,maxvalue,minvalue,x)
            y = 6*(x-maxvalue)/(maxvalue-minvalue) + 3;
        end

        % 反量化函数
        function y = inverse_quantization(~,maxvalue,minvalue,qvalues)
            y = (maxvalue-minvalue)*(qvalues-3)/6 + maxvalue;
        end

        % 模糊pid控制主函数
        function [pidout,kpout,kiout,kdout,erro_c] = fuzzypidcontroller(obj,erro)
            erro_c = erro - obj.pre_err;
            obj.qerro = obj.quantization(obj.e_max,obj.e_min,erro);
            obj.qerro_c = obj.quantization(obj.ec_max,obj.ec_min,erro_c);
            obj.get_grad_membership(obj.qerro,obj.qerro_c)
            obj.getsumgrad()
            obj.getout()

            obj.delta_kp = obj.inverse_quantization(obj.delta_kpmax,obj.delta_kpmin,obj.qdelta_kp);
            obj.delta_ki = obj.inverse_quantization(obj.delta_kimax,obj.delta_kimin,obj.qdelta_ki);
            obj.delta_kd = obj.inverse_quantization(obj.delta_kdmax,obj.delta_kdmin,obj.qdelta_kd);

            obj.kp = obj.kp + obj.delta_kp;
            obj.ki = obj.ki + obj.delta_ki;
            obj.kd = obj.kd + obj.delta_kd;

            if obj.kp < 0
                obj.kp = 0;
            end
            if obj.ki < 0
                obj.ki = 0;
            end
            if obj.kd < 0
                obj.kd = 0;
            end
            kpout = obj.kp;
            kiout = obj.ki;
            kdout = obj.kd;

            pidout = obj.kp*erro + obj.ki*obj.erri + obj.kd*erro_c/obj.dt;
            obj.erri = obj.erri + erro*obj.dt;
            obj.pre_err = erro;

            if abs(pidout) > obj.threshold
                pidout = sign(pidout)*obj.threshold;
            end
        end
    end
end

main.m

% created by hyacinth on 2024/5/31
clc
clear
close all

%%
fs = 2e3;
dt = 1/fs;

pnums = 133;
pdens = [1,25,0];
P = tf(pnums,pdens);
dP = c2d(P,dt,"t");
[pnumz,pdenz] = tfdata(dP,"v");

tend = 5;
N = (tend/dt);
t = (1:N)*dt;
amp = 1000;
yd = amp*sin(2*pi*1*t);
% yd = amp*ones(1,N);

 kp0 = 0;
ki0 = 0;
kd0 = 0;

e_max = 0.05*amp;   % needs to be adjusted, maybe
e_min = -e_max;

ec_max = 1/fs*amp;  % needs to be adjusted, maybe
ec_min = -ec_max;

multi = 5e-4;       % needs to be adjusted, maybe
delta_kpmax = multi*1e3;
delta_kpmin = multi*-1e3;
delta_kimax = multi*1e0;
delta_kimin = multi*-1e0;
delta_kdmax = multi*1e-3;
delta_kdmin = multi*-1e-3;
threshold = 5000;

fuzzypid = FuzzyPID(e_max,e_min,ec_max,ec_min,kp0,ki0,kd0, ...
    delta_kpmax,delta_kpmin,delta_kimax,delta_kimin,delta_kdmax,delta_kdmin,threshold,dt);
zip = zeros(1,length(pdenz)-1);
u0 = 0;
for k = 1:N
    [y(k),zip] = filter(pnumz,pdenz,u0,zip);
    erro(k) = yd(k) - y(k);
    [u(k),kp(k),ki(k),kd(k),erro_c(k)] = fuzzypid.fuzzypidcontroller(erro(k));
    u0 = u(k);
end

figure
subplot(6,3,[1,4,7]);hold on;grid on
plot(t,yd,".-")
plot(t,y,".-")
legend("yd","y")
subplot(6,3,[10,13,16]);plot(t,u,".-");grid on;legend("u");
subplot(6,3,[2,5,8]);plot(t,erro,".-");grid on;legend("erro")
subplot(6,3,[11,14,17]);plot(t(2:end),erro_c(2:end),".-");grid on;legend("erro\_c")
subplot(6,3,[3,6]);plot(t,kp,".-");grid on;legend("kp")
subplot(6,3,[9,12]);plot(t,ki,".-");grid on;legend("ki")
subplot(6,3,[15,18]);plot(t,kd,".-");grid on;legend("kd")
  • 9
    点赞
  • 28
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值