Trouble using lsqnonlin to fit the IV curve of a solar cell
1 view (last 30 days)
Show older comments
I am trying to fit some current density-voltage data of a solar cell which i have measured in the lab, to a non ideal solar cell equation. Basically, i have some arrays of V (voltage), and J (current density) from a solar cell measurement. I am trying to fit and extract some parameters from the equation (in this case, n, Rs and Rsh), where the equation also has some other constants and measured values which i know (namely, k, T, q, Jsc, Voc, V). This is J_cal below (basically for those interested, it is the non ideal solar cell equation rearranged, using the Lambert W function to solve for it).
I am trying to use lsqnonlin to fit the curve, to extract Rs, Rsh and n:
% % Define the initial guess for the parameters to be extracted
n0 = 2;
Rs0 = 2;
Rsh0= 500;
p0 = [n0, Rs0, Rsh0];
% Define the lower and upper bounds for the parameters to be extracted
lb = [0, 0.1, 25];
ub = [5, 100, 10000];
% Use the lsqnonlin function to find the best-fit parameters
options = optimoptions('lsqnonlin','Algorithm','levenberg-marquardt','Display','iter-detailed');
p = lsqnonlin( @ShockleyQueisser, p0, lb, ub, options)
and I also have the model function:
% Define the model function
function J_model = ShockleyQueisser(p)
global V Voc Jsc T k q J;
n = p(1);
Rs = p(2);
Rsh = p(3);
J_cal = ((n*k*T)/(q*Rs))*lambertw((q*Rs)/(n*k*T)*(Jsc-Voc/(Rs+Rsh))*(exp((-q*Voc)/(n*k*T)))*(exp(q/(n*k*T)*(Rs*Jsc+((Rsh.*V)./(Rsh+Rs))))))+V./Rs-Jsc-((Rsh.*V)./(Rs*(Rsh+Rs)));
J_model = J_cal-J;
end
which is what is trying to be solved.
My problem is, is that it just doesn't iterate and doesn't seem to find the minimum of the sum of squares. It runs once, returns p(0) as the starting guess, and then stops:
First-Order Norm of
Iteration Func-count Residual optimality Lambda step
0 4 0 0 0.01
Optimization completed: The final point is the initial point.
The first-order optimality measure, 0.000000e+00, is less than
1e-4*options.FunctionTolerance = 1.000000e-10.
I am confident J_cal is correct, since if i paste the equation into the command window after i set the initial guess, it gives me something which looks like a good starting guess, but my problem is the code wont iterate.
The global variables are all 1x1, apart from V and J which are 91x1.
I think the issue is how p is defined... in the online documentation, it says i just define the function (in this case 'ShockleyQueisser') however for some reason other help points at setting a handle, @, and i don't really know why. Setting the handle this way makes the code run, but iterates only once. Not putting it gives an error.
Accepted Answer
Torsten
on 27 Jan 2023
Edited: Torsten
on 27 Jan 2023
You did not include
global V Voc Jsc T k q J
in the script part.
clc
clear
global V Voc Jsc T k q J
%reads input file and extracts the IV parameters taken from Labview
%generated txt file
inputfile='data.txt'; %sets input file name
IV_param=readtable(inputfile, 'Headerlines',3, 'ReadRowNames', true);
IV_param(21:end,:)=[];
IV_param(:,1)=[];
%reads input file and extracts I and V data and puts into an array from a
%table
IV = readtable(inputfile, 'HeaderLines', 24);
IV=table2array(IV);
%Trims data to remove anything above the compliance limit
IV(IV(:,2)>= abs(IV_param.Var2(8,:)),:)=[];
% Sets voltage and current arrays
V=IV(:,1);
I=IV(:,2);
%Calculates current density in mA/cm2 from Labview defined area
J=(IV(:,2)/IV_param.Var2(4,:));
%constants
k = 1.380649e-23; % Boltzmann constant
T = 293; %Temp in Kelvin
q = 1.6e-19; %charge of an electron.
%Interpolate to estimate Voc
Voc=interp1(J,V,0);
%Interpolate to estimate Jsc
Jsc=interp1(V,J,0);
Jsc=-Jsc;
% % Define the initial guess for the parameters to be extracted
n0 = 2;
Rs0 = 2;
Rsh0= 500;
p0 = [n0, Rs0, Rsh0]
% Define the lower and upper bounds for the parameters to be extracted
lb = [0, 0.1, 25];
ub = [5, 100, 10000];
% Use the lsqnonlin function to find the best-fit parameters
options = optimoptions('lsqnonlin','Algorithm','levenberg-marquardt','Display','iter-detailed','MaxIterations',5000);
[p,exitflag] = lsqnonlin( @(p) ShockleyQueisser(p), p0, lb, ub, options);
J_model = ShockleyQueisser(p);
J_cal = J_model + J;
hold on
plot(V,J_cal)
%Defines Rs, Rsh and n in p
n = p(1)
Rs = p(2)
Rsh = p(3)
%Plot the original J-V data
%figure;
plot(V, J, 'o');
xlabel('Voltage (V)');
ylabel('Current Density (mA/cm^2)');
legend('Experimental Data');
hold off
% Define the model function
function J_model = ShockleyQueisser(p)
global V Voc Jsc T k q J
n = p(1);
Rs = p(2);
Rsh = p(3);
J_cal = ((n*k*T)/(q*Rs))*lambertw((q*Rs)/(n*k*T)*(Jsc-Voc/(Rs+Rsh))*(exp((-q*Voc)/(n*k*T)))*(exp(q/(n*k*T)*(Rs*Jsc+((Rsh*V)/(Rsh+Rs))))))+V/Rs-Jsc-((Rsh*V)/(Rs*(Rsh+Rs)));
%J_cal = ((n*k*T)/(q*Rs))*lambertw((q*Rs)/(n*k*T)*(Jsc-Voc/(Rs+Rsh))*(exp((-q*Voc)/(n*k*T)))*(exp(q/(n*k*T)*(Rs*Jsc+((Rsh.*V)./(Rsh+Rs))))))+V./Rs-Jsc-((Rsh.*V)./(Rs*(Rsh+Rs)));
J_model = J_cal-J;
end
More Answers (0)
See Also
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!