function [D, K] = CCMPPT_BUCK(Vpv, Ipv)
%#codegen
% CCMPPT for BUCK converter with irradiance change handling
% Vout assumed regulated at 12 V
%% -------- Parameters --------
Vout = 12;
step = 0.003;
eps_val = 1e-6;
Dmin = 0.25;
Dmax_lim = 0.95;
I_change_th = 0.08; % 8% current change threshold
settle_delay = 2; % MPPT cycles to wait after change
%% -------- Persistent Variables --------
persistent i counter FirstRun
persistent Dsample V I
persistent Iph Rs A B
persistent Vmax Pmax Dmax
persistent I_mpp_old I_prev
persistent settle_cnt sudden_flag
%% -------- Initialization --------
if isempty(i)
i = 0;
counter = 0;
FirstRun = 1;
Dsample = [0.7 0.65 0.6];
V = zeros(1,3);
I = zeros(1,3);
Iph = 1;
Rs = 0;
A = 1;
B = 1;
Vmax = 18;
Pmax = 1;
Dmax = Vout / Vmax;
I_mpp_old = max(Ipv, eps_val);
I_prev = Ipv;
settle_cnt = 0;
sudden_flag = 0;
end
K = i;
D = Dmax;
%% =========================================================
%% SUDDEN IRRADIANCE CHANGE DETECTION
%% =========================================================
if I_mpp_old > eps_val
change = abs(Ipv - I_mpp_old) / I_mpp_old;
else
change = 0;
end
if change > I_change_th && sudden_flag == 0
sudden_flag = 1;
settle_cnt = settle_delay;
% Reset CC completely
i = 0;
counter = 0;
FirstRun = 1;
% Hold last duty during settling
D = Dmax;
K = -1; % debug indicator
return;
end
%% Settling time after sudden change
if sudden_flag == 1
D = Dmax;
settle_cnt = settle_cnt - 1;
if settle_cnt <= 0
sudden_flag = 0;
counter = 0;
i = 0;
end
K = -2; % debug indicator
return;
end
%% =========================================================
%% CCMPPT STATE MACHINE
%% =========================================================
%% -------- i = 0 : Estimate Iph --------
if i == 0
D = 0.7;
if counter == 1
Iph = max(Ipv, eps_val);
end
counter = counter + 1;
if counter >= 2
i = 1;
counter = 1;
end
K = i;
return;
end
%% -------- Sampling i = 1,2,3 --------
if i >= 1 && i <= 3
D = Dsample(i);
if counter == 1
% Reject unstable samples
if abs(Ipv - I_prev) > 0.05 * max(I_prev, eps_val)
I_prev = Ipv;
return;
end
V(i) = Vpv;
I(i) = Ipv;
end
I_prev = Ipv;
counter = counter + 1;
if counter >= 2
i = i + 1;
counter = 1;
end
K = i;
return;
end
%% -------- i = 4 : Curve Computing --------
if i == 4
dI1 = max(Iph - I(1), eps_val);
dI2 = max(Iph - I(2), eps_val);
K1 = log(dI1);
K2 = log(dI2);
V21 = V(2) - V(1);
I21 = I(2) - I(1);
K21 = K2 - K1;
if FirstRun
dI3 = max(abs(Iph - I(3)), eps_val);
K3 = log(dI3);
V31 = V(3) - V(1);
I31 = I(3) - I(1);
K31 = K3 - K1;
den = (K21 * I31 - K31 * I21);
if abs(den) < eps_val
i = 0;
counter = 1;
return;
end
Rs = (K31 * V21 - K21 * V31) / den;
FirstRun = 0;
end
denB = V21 + I21 * Rs;
if abs(denB) < eps_val
i = 0;
counter = 1;
return;
end
B = K21 / denB;
A = exp(K1 - B * (V(1) + I(1) * Rs));
I_scan = linspace(0.85 * Iph, 0.95 * Iph, 100);
Pmax = 0;
for k = 1:length(I_scan)
V_est = (1/B) * log(max((Iph - I_scan(k)) / A, eps_val)) ...
- Rs * I_scan(k);
P_est = V_est * I_scan(k);
if P_est > Pmax
Pmax = P_est;
Vmax = V_est;
end
end
Dmax = Vout / max(Vmax, eps_val);
D = Dmax;
I_mpp_old = max(Ipv, eps_val);
i = 5;
counter = 1;
K = i;
return;
end
%% -------- i >= 5 : P&O Tracking --------
P = Vpv * Ipv;
if P > Pmax
Pmax = P;
Vmax = Vpv;
Dmax = Vout / max(Vmax, eps_val);
D = Dmax - step;
else
step = -step;
D = Dmax - step;
end
%% -------- Clamp Duty --------
D = min(max(D, Dmin), Dmax_lim);
K = i;
end