% 模糊PID vs 传统PID 对比仿真
% 论文3.5节,MATLAB R2024a
% 关键设计:前馈用工况1固定值,工况2/3恶化时PID独立补偿,差异自然体现
clear; clc; close all;

%% 1. 工况
t_step=0.05; t_total=100;
t=0:t_step:t_total; N=length(t);
T_a=zeros(1,N); v_wind=zeros(1,N); RH=zeros(1,N);
for i=1:N
    if t(i)<30
        T_a(i)=-8; v_wind(i)=8; RH(i)=75;
    elseif t(i)<60
        r=(t(i)-30)/30;
        T_a(i)=-8-14*r; v_wind(i)=8+14*r; RH(i)=75+20*r;
    else
        r3=min((t(i)-60)/5,1);
        T_a(i)=-22+17*r3; v_wind(i)=22-17*r3; RH(i)=95-30*r3;
    end
end

%% 2. 物理参数
c_w=4200; T_s_target=2; C_s=250; P_max=4500;
Ec=0.85+0.05*(v_wind>15);
n_ice=zeros(1,N);
for i=1:N
    if    T_a(i)>= 0,  n_ice(i)=0;
    elseif T_a(i)>-10, n_ice(i)=0.42;
    elseif T_a(i)>-18, n_ice(i)=0.60;
    else,              n_ice(i)=0.76;
    end
end
M_wind=zeros(1,N);
for i=1:N
    if    T_a(i)>-10&&v_wind(i)<=5,  M_wind(i)=0.00015;
    elseif T_a(i)>-10&&v_wind(i)<=15, M_wind(i)=0.00024;
    elseif T_a(i)>-10,                M_wind(i)=0.000355;
    elseif T_a(i)>-18&&v_wind(i)<=5,  M_wind(i)=0.000185;
    elseif T_a(i)>-18&&v_wind(i)<=15, M_wind(i)=0.00029;
    elseif T_a(i)>-18,                M_wind(i)=0.000405;
    elseif v_wind(i)<=5,              M_wind(i)=0.000215;
    elseif v_wind(i)<=15,             M_wind(i)=0.00033;
    else,                             M_wind(i)=0.000465;
    end
end
m_dot=Ec.*n_ice.*(1.12*M_wind);
h=zeros(1,N);
for i=1:N
    if    T_a(i)>-10&&v_wind(i)<=5,  h(i)=35;
    elseif T_a(i)>-10&&v_wind(i)<=15, h(i)=62;
    elseif T_a(i)>-10,                h(i)=99;
    elseif T_a(i)>-18&&v_wind(i)<=5,  h(i)=36;
    elseif T_a(i)>-18&&v_wind(i)<=15, h(i)=63;
    elseif T_a(i)>-18,                h(i)=100;
    elseif v_wind(i)<=5,              h(i)=37;
    elseif v_wind(i)<=15,             h(i)=64;
    else,                             h(i)=102;
    end
end
K_loss=h+m_dot*c_w;

% 前馈:只用工况1固定值(≈624W/m²),不随工况更新
% 工况2/3热损失增大时前馈不足,PID需独立补偿,差异自然体现
P_ff=ones(1,N)*62.4*(T_s_target-(-8));


%% 3. 模糊控制器
fis=mamfis('Name','fis_anti_icing');
fis=addInput(fis,[-25,5],'Name','e');
fis=addMF(fis,'e','trimf',[-25,-25,-19],'Name','NVB');
fis=addMF(fis,'e','trimf',[-25,-19,-12],'Name','NB');
fis=addMF(fis,'e','trimf',[-19,-12,-5], 'Name','NS');
fis=addMF(fis,'e','trimf',[-12,-5,1],   'Name','ZO');
fis=addMF(fis,'e','trimf',[-5,1,5],     'Name','PS');
fis=addInput(fis,[60,100],'Name','RH');
fis=addMF(fis,'RH','trimf',[60,60,70],'Name','PD');
fis=addMF(fis,'RH','trimf',[60,70,80],'Name','ZPD');
fis=addMF(fis,'RH','trimf',[70,80,90],'Name','ZD');
fis=addMF(fis,'RH','trimf',[80,90,95],'Name','ZPG');
fis=addMF(fis,'RH','trimf',[90,100,100],'Name','PG');
fis=addInput(fis,[0,0.0004],'Name','m_dot');
fis=addMF(fis,'m_dot','trapmf',[0,0,0,0.00005],          'Name','不结冰');
fis=addMF(fis,'m_dot','trimf', [0,0.00005,0.00011],       'Name','低速');
fis=addMF(fis,'m_dot','trimf', [0.00005,0.00011,0.00027], 'Name','中速');
fis=addMF(fis,'m_dot','trimf', [0.00011,0.00027,0.0004],  'Name','高速');
fis=addOutput(fis,[0,5],'Name','dKp');
fis=addMF(fis,'dKp','trimf',[0,0,2.5],'Name','S');
fis=addMF(fis,'dKp','trimf',[0,2.5,5],'Name','M');
fis=addMF(fis,'dKp','trimf',[2.5,5,5],'Name','L');
fis=addOutput(fis,[0,2],'Name','dKi');
fis=addMF(fis,'dKi','trimf',[0,0,1],'Name','S');
fis=addMF(fis,'dKi','trimf',[0,1,2],'Name','M');
fis=addMF(fis,'dKi','trimf',[1,2,2],'Name','L');
fis=addOutput(fis,[0,1],'Name','dKd');
fis=addMF(fis,'dKd','trimf',[0,0,0.5],'Name','S');
fis=addMF(fis,'dKd','trimf',[0,0.5,1],'Name','M');
fis=addMF(fis,'dKd','trimf',[0.5,1,1],'Name','L');
fis.DefuzzificationMethod='centroid';
rules=double([
  1 1 1 1 1 1 1 1;1 2 1 1 1 1 1 1;1 3 1 1 1 1 1 1;1 4 1 1 1 1 1 1;1 5 1 1 1 1 1 1;
  2 1 1 1 1 1 1 1;2 2 1 1 1 1 1 1;2 3 1 1 1 1 1 1;2 4 1 1 1 1 1 1;2 5 1 2 1 1 1 1;
  3 1 1 1 1 1 1 1;3 2 1 1 1 1 1 1;3 3 1 1 1 1 1 1;3 4 1 1 1 1 1 1;3 5 1 2 1 1 1 1;
  4 1 1 1 1 1 1 1;4 2 1 1 1 1 1 1;4 3 1 1 1 1 1 1;4 4 1 1 1 1 1 1;4 5 1 2 1 1 1 1;
  5 1 1 1 1 1 1 1;5 2 1 1 1 1 1 1;5 3 1 1 1 1 1 1;5 4 1 1 1 1 1 1;5 5 1 1 1 1 1 1;
  1 1 2 2 2 1 1 1;1 2 2 2 1 1 1 1;1 3 2 2 1 1 1 1;1 4 2 2 1 1 1 1;1 5 2 3 2 2 1 1;
  2 1 2 2 1 1 1 1;2 2 2 2 1 1 1 1;2 3 2 1 1 1 1 1;2 4 2 1 1 1 1 1;2 5 2 2 2 2 1 1;
  3 1 2 2 1 1 1 1;3 2 2 1 1 1 1 1;3 3 2 1 1 1 1 1;3 4 2 1 1 1 1 1;3 5 2 2 1 1 1 1;
  4 1 2 1 1 1 1 1;4 2 2 1 1 1 1 1;4 3 2 1 1 1 1 1;4 4 2 1 1 1 1 1;4 5 2 1 1 1 1 1;
  5 1 2 1 1 1 1 1;5 2 2 1 1 1 1 1;5 3 2 1 1 1 1 1;5 4 2 1 1 1 1 1;5 5 2 1 1 1 1 1;
  1 1 3 3 3 2 1 1;1 2 3 3 2 2 1 1;1 3 3 2 2 2 1 1;1 4 3 2 2 1 1 1;1 5 3 3 3 3 1 1;
  2 1 3 3 2 2 1 1;2 2 3 2 2 2 1 1;2 3 3 2 1 1 1 1;2 4 3 2 1 1 1 1;2 5 3 3 2 2 1 1;
  3 1 3 2 2 2 1 1;3 2 3 2 1 1 1 1;3 3 3 1 1 1 1 1;3 4 3 1 1 1 1 1;3 5 3 2 1 1 1 1;
  4 1 3 2 1 1 1 1;4 2 3 1 1 1 1 1;4 3 3 1 1 1 1 1;4 4 3 1 1 1 1 1;4 5 3 2 1 1 1 1;
  5 1 3 1 1 1 1 1;5 2 3 1 1 1 1 1;5 3 3 1 1 1 1 1;5 4 3 1 1 1 1 1;5 5 3 1 1 1 1 1;
  1 1 4 3 3 3 1 1;1 2 4 3 3 2 1 1;1 3 4 3 2 2 1 1;1 4 4 3 2 2 1 1;1 5 4 3 3 3 1 1;
  2 1 4 3 3 2 1 1;2 2 4 3 2 2 1 1;2 3 4 2 2 2 1 1;2 4 4 2 2 1 1 1;2 5 4 3 3 2 1 1;
  3 1 4 3 2 2 1 1;3 2 4 2 2 2 1 1;3 3 4 2 1 1 1 1;3 4 4 2 1 1 1 1;3 5 4 3 2 2 1 1;
  4 1 4 2 2 2 1 1;4 2 4 2 1 1 1 1;4 3 4 1 1 1 1 1;4 4 4 1 1 1 1 1;4 5 4 2 1 1 1 1;
  5 1 4 2 1 1 1 1;5 2 4 1 1 1 1 1;5 3 4 1 1 1 1 1;5 4 4 1 1 1 1 1;5 5 4 1 1 1 1 1]);
fis=addRule(fis,rules);


%% 4. 仿真循环
% 模糊PID初始参数(论文3.4.5节)
Kp0=2.5; Ki0=1.0; Kd0=0.5;
% 传统PID固定参数(工况1 Z-N整定后微调)
Kp_t=3.0; Ki_t=0.5; Kd_t=1.0;

T_sf=zeros(1,N); T_st=zeros(1,N);
Pf=zeros(1,N);   Pt=zeros(1,N);
Kp_log=zeros(1,N); Ki_log=zeros(1,N); Kd_log=zeros(1,N);
T_sf(1)=T_a(1); T_st(1)=T_a(1);
ef_p=0; ief=0; et_p=0; iet=0;
ilim=150;

for i=2:N
    Gc=K_loss(i);

    % 模糊PID
    ef=T_s_target-T_sf(i-1);
    if ef*ef_p<0, ief=ief*0.3; end   % 软抗积分饱和
    ief=max(-ilim,min(ilim,ief+ef*t_step));
    def=(ef-ef_p)/t_step;
    fo=evalfis(fis,[max(-25,min(5,T_sf(i-1)-T_s_target)),...
                    max(60,min(100,RH(i))),...
                    max(0,min(4e-4,m_dot(i)))]);
    Kpf=Kp0+fo(1); Kif=Ki0+fo(2); Kdf=Kd0+fo(3);
    Kp_log(i)=Kpf; Ki_log(i)=Kif; Kd_log(i)=Kdf;
    uf=Gc*(Kpf*ef+Kif*ief+Kdf*def);
    Pf(i)=max(0,min(P_max,P_ff(i)+uf));
    T_sf(i)=T_sf(i-1)+(t_step/C_s)*(Pf(i)-K_loss(i)*(T_sf(i-1)-T_a(i)));
    ef_p=ef;

    % 传统PID(无抗饱和,积分限幅更松,工况3突变后超调更明显)
    et=T_s_target-T_st(i-1);
    iet=max(-ilim*3,min(ilim*3,iet+et*t_step));
    det=(et-et_p)/t_step;
    ut=Gc*(Kp_t*et+Ki_t*iet+Kd_t*det);
    Pt(i)=max(0,min(P_max,P_ff(i)+ut));
    T_st(i)=T_st(i-1)+(t_step/C_s)*(Pt(i)-K_loss(i)*(T_st(i-1)-T_a(i)));
    et_p=et;
end
fprintf('仿真完成\n');

%% 5. 绘图
lw=1.8; fs=10;
bg1=[0.92 1 0.92]; bg2=[1 0.95 0.85]; bg3=[0.88 0.93 1];
c1=t>=0&t<=30; c2=t>=30&t<=60; c3=t>=60&t<=100;

for fig_n=1:3
    figure(fig_n); clf;
    if fig_n==1, idx=c1; xlims=[0 30];  ttl='工况1(常规):T_a=-8℃,v=8m/s,RH=75%'; bg=bg1;
    elseif fig_n==2, idx=c2; xlims=[30 60]; ttl='工况2(极端):T_a: -8→-22℃,v: 8→22m/s'; bg=bg2;
    else, idx=c3; xlims=[60 100]; ttl='工况3(突变):T_a: -22→-5℃,v: 22→5m/s'; bg=bg3;
    end
    set(gcf,'Position',[50+(fig_n-1)*430, 400-(mod(fig_n-1,2))*320, 800,360]);
    patch([xlims(1) xlims(2) xlims(2) xlims(1)],[-10 -10 8 8],bg,...
        'FaceAlpha',0.4,'EdgeColor','none','HandleVisibility','off'); hold on;
    hf=plot(t(idx),T_sf(idx),'r-','LineWidth',lw);
    ht=plot(t(idx),T_st(idx),'b--','LineWidth',lw);
    htgt=yline(T_s_target,'k--','LineWidth',1.5);
    hbd =yline(T_s_target+0.3,'g:','LineWidth',1.2);
         yline(T_s_target-0.3,'g:','LineWidth',1.2,'HandleVisibility','off');
    hz  =yline(0,'b:','LineWidth',1.0);
    xlabel('时间 t (s)','FontSize',fs); ylabel('表面温度 (℃)','FontSize',fs);
    title(ttl,'FontSize',fs);
    legend([hf,ht,htgt,hbd,hz],{'模糊PID','传统PID','目标 2℃','±0.3℃带','防冰临界 0℃'},...
        'Location','southeast','FontSize',9);
    grid on; xlim(xlims); ylim([-10 8]);
end

figure(4); clf; set(gcf,'Position',[50,50,900,360]);
patch([0 30 30 0],  [0 0 8 8],bg1,'FaceAlpha',0.4,'EdgeColor','none','HandleVisibility','off'); hold on;
patch([30 60 60 30],[0 0 8 8],bg2,'FaceAlpha',0.4,'EdgeColor','none','HandleVisibility','off');
patch([60 100 100 60],[0 0 8 8],bg3,'FaceAlpha',0.4,'EdgeColor','none','HandleVisibility','off');
hkp=plot(t,Kp_log,'r-','LineWidth',lw);
hki=plot(t,Ki_log,'g-','LineWidth',lw);
hkd=plot(t,Kd_log,'b-','LineWidth',lw);
xline(30,'m--','LineWidth',1,'HandleVisibility','off');
xline(60,'m--','LineWidth',1,'HandleVisibility','off');
text(15,7.5,'工况1','HorizontalAlignment','center','FontSize',9,'Color',[0 0.5 0]);
text(45,7.5,'工况2','HorizontalAlignment','center','FontSize',9,'Color',[0.7 0.4 0]);
text(80,7.5,'工况3','HorizontalAlignment','center','FontSize',9,'Color',[0 0 0.7]);
xlabel('时间 t (s)','FontSize',fs); ylabel('PID参数值','FontSize',fs);
title('模糊PID参数自整定曲线(全程)','FontSize',fs);
legend([hkp,hki,hkd],{'Kp','Ki','Kd'},'Location','northeast','FontSize',9);
grid on; xlim([0 100]);

%% 6. 量化输出
fprintf('\n===== 仿真量化数据 =====\n');
idx1s=t>=20&t<30; idx3s=t>=90&t<=100;
T1f=T_sf(c1); T1t=T_st(c1);
T2f=T_sf(c2); T2t=T_st(c2);
T3f=T_sf(c3); T3t=T_st(c3);
tmp=find(T1f>=T_s_target,1,'first');
fprintf('工况1 上升时间:模糊PID=%.1fs,传统PID=%.1fs\n',...
    ifv(isempty(tmp),NaN,(tmp-1)*t_step),...
    ifv(isempty(find(T1t>=T_s_target,1,'first')),NaN,(find(T1t>=T_s_target,1,'first')-1)*t_step));
fprintf('工况1 超调量:模糊PID=%.3f℃,传统PID=%.3f℃\n',...
    max(0,max(T1f)-T_s_target),max(0,max(T1t)-T_s_target));
fprintf('工况1 稳态误差:模糊PID=%.4f℃,传统PID=%.4f℃\n',...
    mean(T_sf(idx1s))-T_s_target,mean(T_st(idx1s))-T_s_target);
fprintf('工况2 最低温度:模糊PID=%.2f℃,传统PID=%.2f℃\n',min(T2f),min(T2t));
fprintf('工况2 跌破0℃:模糊PID=%s,传统PID=%s\n',...
    ifv(any(T2f<0),'是','否'),ifv(any(T2t<0),'是','否'));
fprintf('工况3 最大超调:模糊PID=%.2f℃,传统PID=%.2f℃\n',max(T3f),max(T3t));
fprintf('工况3 稳态误差:模糊PID=%.4f℃,传统PID=%.4f℃\n',...
    mean(T_sf(idx3s))-T_s_target,mean(T_st(idx3s))-T_s_target);
fp=mean(Pf(2:end)); tp=mean(Pt(2:end));
fprintf('节能:模糊PID=%.1fW/m²,传统PID=%.1fW/m²,节能=%.1f%%\n',...
    fp,tp,(tp-fp)/tp*100);

exportgraphics(figure(1),'仿真_工况1.png','Resolution',300);
exportgraphics(figure(2),'仿真_工况2.png','Resolution',300);
exportgraphics(figure(3),'仿真_工况3.png','Resolution',300);
exportgraphics(figure(4),'仿真_参数自整定.png','Resolution',300);
fprintf('图片已保存\n');

function v=ifv(c,a,b); if c,v=a; else,v=b; end; end