% 极地船舶新风口模糊PID防冰控制系统仿真
% 物理模型说明:
%   热平衡:C_s * dT_s/dt = P_input - K_loss*(T_s - T_a)
%   K_loss = h + m_dot*c_w  (对流换热 + 过冷水滴升温热损失)
%   P_input = P_ff + P_pid  (前馈稳态功率 + PID动态修正)
%   P_ff = K_loss*(T_target - T_a)  (精确补偿稳态热损失)
%
% 传统PID参数整定(Z-N临界比例度法):
%   工况1稳态:K_loss≈62.5,C_s=250,时间常数τ=C_s/K_loss=4s
%   一阶系统临界增益Ku→∞,改用经验法:
%   取τ=4s,纯比例控制稳态误差5%时 Kp_u = 1/(K_loss*0.05/C_s) ≈ 20
%   Z-N推荐:Kp=0.6*Ku=12,Ti=0.5*Tu,Td=0.125*Tu
%   简化取:Kp_t=8, Ki_t=0.8, Kd_t=2.0(对应τ=4s系统的合理整定值)
%
% 模糊PID初始参数(论文3.4.5节):Kp0=2.5, Ki0=1.0, Kd0=0.5
%   注意:这里参数是归一化值,通过Gc=K_loss放大到功率量纲
%   等效实际Kp = Kp0*K_loss ≈ 2.5*62.5 = 156,与传统PID量级一致
clear; clc; close all;

%% 1. 工况设置(论文3.5.2节,3种动态工况)
t_step  = 0.05;
t_total = 150;   % 工况3延长至150s,有足够稳定时间
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
        % 工况1:常规(-8℃,8m/s,75%)
        T_a(i)=-8; v_wind(i)=8; RH(i)=75;
    elseif t(i) < 60
        % 工况2:极端低温高速(线性恶化)
        r = (t(i)-30)/30;
        T_a(i)=-8-14*r; v_wind(i)=8+14*r; RH(i)=75+20*r;
    else
        % 工况3:突变后稳定
        T_a(i)=-5; v_wind(i)=5; RH(i)=65;
    end
end

%% 2. 结冰速率(论文式3-2:m_dot = Ec × n × M_total,M_total=1.12×M_wind)
% 碰撞效率(论文3.1.1节)
Ec = 0.85 + 0.05*(v_wind > 15);

% 结冰系数(论文表2.2,取各区间中点值)
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;   % -5~-10℃中点
    elseif T_a(i) > -18,  n_ice(i) = 0.60;   % -11~-18℃中点
    else,                 n_ice(i) = 0.76;   % -19~-25℃中点
    end
end

% 风飞沫量(论文表2-1,取各区间中点值)
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
% 式3-2:M_total = 1.12*M_wind(含12%海浪飞沫折算)
m_dot = Ec .* n_ice .* (1.12 * M_wind);

%% 3. 对流换热系数h(论文表2.3,取各区间中点值)
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

%% 4. 热力学参数
T_s_target = 2;    % 控制目标:2℃(0℃以上2℃安全裕量,论文2.4.1节)
c_w = 4200;        % 水的定压比热容(J/(kg·℃))
r   = 335000;      % 水的熔解热(J/kg)

% 综合热损失系数(W/(m²·℃))
K_loss = h + m_dot * c_w;

% 前馈稳态功率(精确补偿稳态热损失,使系统能到达目标温度)
% 式3-3修正版:以T_s_target=2℃为目标
P_ff = K_loss .* (T_s_target - T_a);

% 论文式3-4参考值(用于结果对比展示)
P_dyn_ref = h.*(0-T_a) + m_dot.*c_w.*(0-T_a) + m_dot.*r;

% 等效热容:C_s * dT/dt = P_input - K_loss*(T_s-T_a)
% 取C_s=250,工况1时间常数τ=250/62≈4s,响应合理
C_s   = 250;
P_max = 4500;   % 最大功率限制(W/m²)


%% 5. 模糊控制器(论文3.4节)
fis = mamfis('Name','fuzzy_pid_anti_icing');

% 输入1:温度偏差 e = T_s - T_target(℃),论域[-25,5]
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');

% 输入2:湿度RH(%),论域[60,100]
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');

% 输入3:结冰速率(kg/(m²·s)),论域[0,0.0004]
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','高速');

% 输出:ΔKp∈[0,5],ΔKi∈[0,2],ΔKd∈[0,1]
fis = addOutput(fis,[0,5],'Name','delta_Kp');
fis = addMF(fis,'delta_Kp','trimf',[0,0,2.5],'Name','S');
fis = addMF(fis,'delta_Kp','trimf',[0,2.5,5],'Name','M');
fis = addMF(fis,'delta_Kp','trimf',[2.5,5,5],'Name','L');

fis = addOutput(fis,[0,2],'Name','delta_Ki');
fis = addMF(fis,'delta_Ki','trimf',[0,0,1],'Name','S');
fis = addMF(fis,'delta_Ki','trimf',[0,1,2],'Name','M');
fis = addMF(fis,'delta_Ki','trimf',[1,2,2],'Name','L');

fis = addOutput(fis,[0,1],'Name','delta_Kd');
fis = addMF(fis,'delta_Kd','trimf',[0,0,0.5],'Name','S');
fis = addMF(fis,'delta_Kd','trimf',[0,0.5,1],'Name','M');
fis = addMF(fis,'delta_Kd','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);
writefis(fis,'fuzzy_pid_anti_icing.fis');


%% 6. 仿真循环
% ---------------------------------------------------------------
% PID参数说明:
%   控制律:P_pid = Gc*(Kp*e + Ki*∫e + Kd*de/dt)
%   其中 Gc = K_loss(控制增益,使Kp/Ki/Kd保持论文量级)
%
%   传统PID(Z-N经验整定,工况1稳态模型):
%     系统:一阶 G(s) = 1/(C_s*s + K_loss),τ=C_s/K_loss≈4s,K=1/K_loss
%     Z-N推荐PID:Kp=1.2*τ/K/Td,取Td=τ/4=1s
%     简化:Kp_t=8, Ki_t=1.5, Kd_t=2.5(工况1整定,工况2/3参数固定→劣势)
%
%   模糊PID(论文3.4.5节初始参数):
%     Kp0=2.5, Ki0=1.0, Kd0=0.5(归一化基础值)
%     实际等效:Kp_eff=Kp0*Gc≈156,与传统PID量级一致
%     工况恶化时模糊推理增大ΔKp/ΔKi/ΔKd,自适应响应
% ---------------------------------------------------------------

% 模糊PID基础参数(论文3.4.5节)
Kp0=2.5; Ki0=1.0; Kd0=0.5;

% 传统PID(工况1整定,固定参数)
Kp_t=8.0; Ki_t=1.5; Kd_t=2.5;

% 初始化
T_s_f=zeros(1,N); T_s_t=zeros(1,N);
P_f=zeros(1,N);   P_t=zeros(1,N);
Kp_log=zeros(1,N); Ki_log=zeros(1,N); Kd_log=zeros(1,N);
T_s_f(1)=T_a(1); T_s_t(1)=T_a(1);

ef_prev=0; int_ef=0;
et_prev=0; int_et=0;
int_lim=150;   % 积分限幅(归一化,对应功率修正约±300W)

fprintf('仿真运行中...\n');
for i = 2:N
    Gc = K_loss(i);   % 控制增益

    %--- 模糊PID ---
    ef = T_s_target - T_s_f(i-1);   % 误差(正=需加热)

    % 软抗积分饱和:过零时积分衰减
    if ef * ef_prev < 0, int_ef = int_ef * 0.2; end
    int_ef = int_ef + ef*t_step;
    int_ef = max(-int_lim, min(int_lim, int_ef));
    def = (ef - ef_prev)/t_step;

    % 模糊推理(输入:e=T_s-T_target,RH,m_dot)
    e_in  = max(-25, min(5,   T_s_f(i-1)-T_s_target));
    rh_in = max(60,  min(100, RH(i)));
    md_in = max(0,   min(4e-4, m_dot(i)));
    fo = evalfis(fis,[e_in,rh_in,md_in]);

    Kp_f = Kp0 + fo(1);
    Ki_f = Ki0 + fo(2);
    Kd_f = Kd0 + fo(3);
    Kp_log(i)=Kp_f; Ki_log(i)=Ki_f; Kd_log(i)=Kd_f;

    u_f = Gc * (Kp_f*ef + Ki_f*int_ef + Kd_f*def);
    P_f(i) = max(0, min(P_max, P_ff(i) + u_f));

    Ploss_f = K_loss(i)*(T_s_f(i-1)-T_a(i));
    T_s_f(i) = T_s_f(i-1) + (t_step/C_s)*(P_f(i)-Ploss_f);
    ef_prev = ef;

    %--- 传统PID(固定参数,无抗饱和)---
    et = T_s_target - T_s_t(i-1);
    int_et = int_et + et*t_step;
    int_et = max(-int_lim*1.5, min(int_lim*1.5, int_et));
    det = (et - et_prev)/t_step;

    u_t = Gc * (Kp_t*et + Ki_t*int_et + Kd_t*det);
    P_t(i) = max(0, min(P_max, P_ff(i) + u_t));

    Ploss_t = K_loss(i)*(T_s_t(i-1)-T_a(i));
    T_s_t(i) = T_s_t(i-1) + (t_step/C_s)*(P_t(i)-Ploss_t);
    et_prev = et;

    if t(i)>=30 && t(i)<30+t_step, fprintf('  工况2:极端低温高速工况开始\n'); end
    if t(i)>=60 && t(i)<60+t_step, fprintf('  工况3:突变工况开始\n'); end
end
fprintf('仿真完成!\n\n');


%% 7. 绘图
lw=1.8; fs=10;
idx_c1=t>=0&t<=30; idx_c2=t>=30&t<=60; idx_c3=t>=60&t<=150;

figure(1); clf;
plot(t(idx_c1),T_s_f(idx_c1),'r-','LineWidth',lw,'DisplayName','模糊PID'); hold on;
plot(t(idx_c1),T_s_t(idx_c1),'b--','LineWidth',lw,'DisplayName','传统PID');
yline(T_s_target,'k:','LineWidth',1.5,'DisplayName','目标 2℃');
yline(0,'g--','LineWidth',1.0,'DisplayName','防冰临界 0℃');
xlabel('时间 t (s)','FontSize',fs); ylabel('表面温度 (℃)','FontSize',fs);
title('工况1(常规):T_a=-8℃,v=8m/s,RH=75%','FontSize',fs);
legend('Location','southeast','FontSize',fs); grid on; xlim([0 30]);
set(gcf,'Position',[50,550,750,360]);

figure(2); clf;
plot(t(idx_c2),T_s_f(idx_c2),'r-','LineWidth',lw,'DisplayName','模糊PID'); hold on;
plot(t(idx_c2),T_s_t(idx_c2),'b--','LineWidth',lw,'DisplayName','传统PID');
yline(T_s_target,'k:','LineWidth',1.5,'DisplayName','目标 2℃');
yline(0,'g--','LineWidth',1.0,'DisplayName','防冰临界 0℃');
xlabel('时间 t (s)','FontSize',fs); ylabel('表面温度 (℃)','FontSize',fs);
title('工况2(极端):T_a: -8→-22℃,v: 8→22m/s,RH: 75→95%','FontSize',fs);
legend('Location','best','FontSize',fs); grid on; xlim([30 60]);
set(gcf,'Position',[50,130,750,360]);

figure(3); clf;
plot(t(idx_c3),T_s_f(idx_c3),'r-','LineWidth',lw,'DisplayName','模糊PID'); hold on;
plot(t(idx_c3),T_s_t(idx_c3),'b--','LineWidth',lw,'DisplayName','传统PID');
yline(T_s_target,'k:','LineWidth',1.5,'DisplayName','目标 2℃');
yline(0,'g--','LineWidth',1.0,'DisplayName','防冰临界 0℃');
xlabel('时间 t (s)','FontSize',fs); ylabel('表面温度 (℃)','FontSize',fs);
title('工况3(突变):T_a骤升至-5℃,v骤降至5m/s,RH降至65%','FontSize',fs);
legend('Location','best','FontSize',fs); grid on; xlim([60 150]);
set(gcf,'Position',[850,550,750,360]);

figure(4); clf;
plot(t,Kp_log,'r-','LineWidth',lw,'DisplayName','Kp'); hold on;
plot(t,Ki_log,'g-','LineWidth',lw,'DisplayName','Ki');
plot(t,Kd_log,'b-','LineWidth',lw,'DisplayName','Kd');
xline(30,'m--','LineWidth',1,'HandleVisibility','off');
xline(60,'m--','LineWidth',1,'HandleVisibility','off');
text(15,max(Kp_log)*0.9,'工况1','HorizontalAlignment','center','FontSize',9,'Color',[0.5 0.5 0.5]);
text(45,max(Kp_log)*0.9,'工况2','HorizontalAlignment','center','FontSize',9,'Color',[0.5 0.5 0.5]);
text(105,max(Kp_log)*0.9,'工况3','HorizontalAlignment','center','FontSize',9,'Color',[0.5 0.5 0.5]);
xlabel('时间 t (s)','FontSize',fs); ylabel('PID参数值','FontSize',fs);
title('模糊PID参数自整定曲线(全程)','FontSize',fs);
legend('Location','northeast','FontSize',fs); grid on;
set(gcf,'Position',[850,130,750,360]);

figure(5); clf;
plot(t,m_dot*1e4,'k-','LineWidth',lw);
xline(30,'m--','LineWidth',1); xline(60,'m--','LineWidth',1);
text(15,max(m_dot*1e4)*0.85,'工况1','HorizontalAlignment','center','FontSize',9,'Color',[0.5 0.5 0.5]);
text(45,max(m_dot*1e4)*0.85,'工况2','HorizontalAlignment','center','FontSize',9,'Color',[0.5 0.5 0.5]);
text(105,max(m_dot*1e4)*0.85,'工况3','HorizontalAlignment','center','FontSize',9,'Color',[0.5 0.5 0.5]);
xlabel('时间 t (s)','FontSize',fs);
ylabel('结冰速率 (×10⁻⁴ kg/(m²·s))','FontSize',fs);
title('结冰速率变化曲线(全程)','FontSize',fs);
grid on; set(gcf,'Position',[450,340,750,360]);

%% 8. 量化数据输出
fprintf('==================== 仿真量化数据 ====================\n');

% 工况1:上升时间(首次到达0℃/2℃)
T1f=T_s_f(idx_c1); T1t=T_s_t(idx_c1); t1=t(idx_c1);
tmp=find(T1f>=0,1,'first');   f_r0=ifv(isempty(tmp),NaN,(tmp-1)*t_step);
tmp=find(T1t>=0,1,'first');   t_r0=ifv(isempty(tmp),NaN,(tmp-1)*t_step);
tmp=find(T1f>=T_s_target,1,'first'); f_r2=ifv(isempty(tmp),NaN,(tmp-1)*t_step);
tmp=find(T1t>=T_s_target,1,'first'); t_r2=ifv(isempty(tmp),NaN,(tmp-1)*t_step);
idx1s=t>=20&t<30;
fprintf('工况1(常规)\n');
fprintf('  首次到达0℃:模糊PID=%.1fs,传统PID=%.1fs\n',f_r0,t_r0);
fprintf('  首次到达2℃:模糊PID=%.1fs,传统PID=%.1fs\n',f_r2,t_r2);
fprintf('  稳态均值(20~30s):模糊PID=%.3f℃,传统PID=%.3f℃\n',...
    mean(T_s_f(idx1s)),mean(T_s_t(idx1s)));
fprintf('  稳态偏差RMS:模糊PID=%.3f℃,传统PID=%.3f℃\n',...
    rms(T_s_f(idx1s)-T_s_target),rms(T_s_t(idx1s)-T_s_target));

% 工况2:温度最低点 + 恢复时间
T2f=T_s_f(idx_c2); T2t=T_s_t(idx_c2); t2=t(idx_c2);
[mn_f,mi_f]=min(T2f); [mn_t,mi_t]=min(T2t);
fprintf('工况2(极端)\n');
fprintf('  温度最低点:模糊PID=%.2f℃(t=%.1fs),传统PID=%.2f℃(t=%.1fs)\n',...
    mn_f,t2(mi_f),mn_t,t2(mi_t));
tmp=find(T2f(mi_f:end)>=T_s_target-0.5,1,'first');
f_rec=ifv(isempty(tmp),NaN,tmp*t_step);
tmp=find(T2t(mi_t:end)>=T_s_target-0.5,1,'first');
t_rec=ifv(isempty(tmp),NaN,tmp*t_step);
fprintf('  从最低点恢复至1.5℃:模糊PID=%.1fs,传统PID=%.1fs\n',f_rec,t_rec);

% 工况3:超调 + 稳态
T3f=T_s_f(idx_c3); T3t=T_s_t(idx_c3);
idx3s=t>=130&t<=150;
fprintf('工况3(突变)\n');
fprintf('  最大超调:模糊PID=%.2f℃,传统PID=%.2f℃\n',max(T3f),max(T3t));
fprintf('  稳态均值(130~150s):模糊PID=%.3f℃,传统PID=%.3f℃\n',...
    mean(T_s_f(idx3s)),mean(T_s_t(idx3s)));
fprintf('  稳态波动峰峰值:模糊PID=%.3f℃,传统PID=%.3f℃\n',...
    max(T_s_f(idx3s))-min(T_s_f(idx3s)),...
    max(T_s_t(idx3s))-min(T_s_t(idx3s)));

% 节能
fprintf('节能性(全程平均功率)\n');
fp=mean(P_f(2:end)); tp=mean(P_t(2:end));
fprintf('  模糊PID=%.1fW/m²,传统PID=%.1fW/m²,节能=%.1f%%\n',...
    fp,tp,(tp-fp)/tp*100);

fprintf('\n典型时刻(t=30/60/100/150s):\n');
for tk=[30,60,100,150]
    idx=find(t>=tk,1,'first');
    fprintf('  t=%3ds:m_dot=%.5f kg/(m²·s),P_ref=%.0fW/m²,模糊PID=%.2f℃,传统PID=%.2f℃\n',...
        tk,m_dot(idx),P_dyn_ref(idx),T_s_f(idx),T_s_t(idx));
end
fprintf('=======================================================\n');

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