Trouble using lsqnonlin to fit the IV curve of a solar cell
5 visualizaciones (últimos 30 días)
Mostrar comentarios más antiguos
Jake Bowers
el 26 de En. de 2023
Comentada: Jake Bowers
el 27 de En. de 2023
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.
4 comentarios
Torsten
el 27 de En. de 2023
Editada: Torsten
el 27 de En. de 2023
For lsqnonlin,
sum_i f(i)^2
is minimized, and the user is asked to provide the f(i).
Thus returning
res = J_calc - J_experiment
is correct (if J_experiment is an array of experimental measurements of the same size as J_calc).
Is it possible that the values returned by lambertW are complex and that this is the reason lsqnonlin stops ?
Respuesta aceptada
Torsten
el 27 de En. de 2023
Editada: Torsten
el 27 de En. de 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
Más respuestas (0)
Ver también
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!