Main Content

Generate Parameter Data for Datasheet Battery Block

This example shows how to import lithium-ion battery sheet data and generate parameters for the Datasheet Battery block.

In step 1, you import the datasheet data. Steps 2-5 show how to use curve-fitting techniques to obtain the open circuit voltage and battery resistance from the datasheet data. In steps 6-8, you validate the curve-fit voltage and battery values by comparing them to the Arrhenius behavior and the datasheet data. Finally, in step 9, you specify these Datasheet Battery block parameters:

  • Rated capacity at nominal temperature

  • Open circuit voltage, per cell

  • State of charge breakpoints for open circuit voltage

  • Internal resistance, per cell

  • Battery temperature breakpoints

  • State of charge breakpoints for internal resistance

  • Initial battery charge

Step 1: Import Battery Datasheet Data

Import the battery discharge and temperature datasheet into MATLAB®. Ensure that each data set in the datasheet includes a starting battery cell output voltage. Typically, data collected at different temperatures has the same reference current. Data collected at different currents has the same reference temperature.

For this example, load the battery datasheet discharge and temperature data for a lithium-ion battery from a file that contains 12 data sets. Each data set corresponds to battery data for a specific current and temperature. The data sets each have two columns. The first column contains the discharge capacity, in percent. The second column contains the corresponding battery cell voltage.

exp_data=load('ex_datasheetbattery_liion_100Ah.mat');

The example does not use the data set that corresponds to a current of 500 A at 25 °C.

Plot the discharge and temperature curves. Figure 1 shows the lithium-ion battery discharge characteristics at constant temperature (at five levels of current, shown as C-rate) and constant current (at six temperatures). Figure 1 indicates the curve that corresponds to the reference temperature of 25 °C and the reference current of 50 A.

ex_datasheetbattery_plot_data

Figure contains 2 axes objects. Axes object 1 with xlabel Discharge Capacity [Ah], ylabel Voltage [V] contains 5 objects of type line. These objects represent 0.33C, 0.5C, 1.0C, 2.0C, 3.0C. Axes object 2 with title Temperature Characteristics at Constant 50A, xlabel Discharge Capacity [Ah], ylabel Voltage [V] contains 7 objects of type line. These objects represent 25 \circC, -30 \circC, -20 \circC, -10 \circC, 0 \circC, 10 \circC, 40 \circC.

Step 2: Normalize State-of-Charge (SOC) Data

To represent 1-SOC capacity at constant temperature, normalize the relative discharge capacity with values between 0 and 1. Let 1 represent a fully discharged battery.

Set ref_exp to the data set that corresponds to the reference temperature of 25 °C and the reference current of 50 A. Typically, the reference temperature is room temperature.

ref_exp = 2;

If you have several data sets, use a few for validation. Do not include them as part of the estimation data set.

For this example, use val_exp to set up the validation and estimation data sets. Let 1 represent a validation data set and 0 represent an estimation data set.

val_exp = logical([1 0 0 0 1 0 0 0 0 1 0]);

Define reference current and temperature. For this example, the reference temperature is 25 °C and the reference current is 50 A.

ref_curr = current == current(ref_exp);
ref_temp = temperature == temperature(ref_exp);

[sort_current, sort_index_current] = sort(current(ref_temp));
[sort_temp, sort_index_temp] = sort(temperature(ref_curr));
N = length(current); % Number of experiments

Prepare normalized x axes for each data set and find the actual capacity. x is a structure with as many fields as data sets and values between 0 and 1. Use experimental capacity at 0.33 C and 50 A as total capacity for SOC calculation. Ideally, total capacity should have been tested under a much lower rate.

for i=1:N 
    x.(['curr' current_label{i} '_temp' temperature_label{i}]) = ...
            exp_data.([label '_' current_label{i} '_' temperature_label{i}])(:,1)/...
            exp_data.([label '_' current_label{1} '_' temperature_label{1}])(end,1);
    % Calculate actual capacity for each datasheet
    correct_cap.(['curr' current_label{i} '_temp' temperature_label{i}]) = ...
            exp_data.([label '_' current_label{i} '_' temperature_label{i}])(end,1);
end

Plot the normalized SOC data.

ex_datasheetbattery_plot_soc

Figure contains an axes object. The axes object with xlabel 1-SOC, ylabel Voltage [V] contains 5 objects of type line. These objects represent I = 33.3 A, I = 50 A, I = 100 A, I = 200 A, I = 300 A.

Step 3: Fit Curves

Create fitObj curves for constant temperatures at different discharge rates and constant discharge rates at different temperatures. Use the fitObj curves to create a matrix of cell/module voltage versus discharge current at varying levels of SOC.

fitObj is a structure of fit objects that contains as many fields as data sets. The structure fits a discharge voltage to the normalized ([0,1]) extracted Ah. This allows the discharge curves to be algebraically combined to calculate resistance at each SOC level.

Define state of charge vector and breakpoints.

SOCbkpts = 0:.1:1;

Fit the discharge curves at different currents for reference temperature.

for i=find(ref_temp)
    fitObj.(['fit' current_label{i}]) = ...
        fit(x.(['curr' current_label{i} '_temp' temperature_label{i}]),...
        exp_data.([label '_' current_label{i} '_' temperature_label{ref_exp}])(:,2),'smoothingspline');
    SOC_array_tmp = x.(['curr' current_label{i} '_temp' temperature_label{i}]);
    SOC_Max_temp(i) = SOC_array_tmp(end);

end
SOC_LUT = (0:.01:min(SOC_Max_temp))'; % SOC is not going to cover the whole range of 0 to 1

Fit the discharge curves at different temperatures for reference current.

for i=find(ref_curr)
    fitObj.(['fit' temperature_label{i}]) = ...
        fit(x.(['curr' current_label{i} '_temp' temperature_label{i}]),...
        exp_data.([label '_' current_label{ref_exp} '_' temperature_label{i}])(:,2),'smoothingspline');
    SOC_array_tmp = x.(['curr' current_label{i} '_temp' temperature_label{i}]);
    SOC_Max_curr(i) = SOC_array_tmp(end);
end

Construct the voltage versus discharge current for different SOC levels. Em_MAT is a matrix with the SOC in rows and the current in columns.

Em_MAT = [];
for i=find(ref_temp)
    Em_MAT = [Em_MAT fitObj.(['fit' current_label{i}])(SOC_LUT)];
end

Figure 3 shows the voltage versus current at different SOCs.

ex_datasheetbattery_plot_curves

Figure contains an axes object. The axes object with xlabel Current [A], ylabel Voltage [V] contains 10 objects of type line. These objects represent 0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9.

Step 4: Extrapolate Open Circuit Voltage

To obtain the open circuit voltage, Em, fit a line to the voltage versus current curve and extrapolate to i=0.

R0_refTemp = [];
for i=1:length(SOC_LUT)
    % Fit a line to V=f(I)
    fitSOC.(['SOC' num2str(i)]) = fit(sort_current',Em_MAT(i,sort_index_current)','poly1');
end

To estimate open circuit voltage, Em, at all SOC levels, extrapolate the values of voltage to i=0.

Em = [];
for i=1:length(SOC_LUT)
    % Em = f(0)
    Em = [Em fitSOC.(['SOC' num2str(i)])(0)];
end
Em = Em';

Use C/3 and 25 °C voltage plus DCIR related voltage to fill in the gap where Em is not available for low SOC range.

SOC_LUT_full = (0:0.01:1)';
soc_33p3A_temp25C = x.curr33p3A_temp25C;
volt_33p3A_temp25C = exp_data.LiIon_33p3A_25C(:,2);
v_interp = interp1(soc_33p3A_temp25C, volt_33p3A_temp25C, SOC_LUT_full);
% Obtain the average DCIR between OCV and C/33, 25 deg;C voltage.
delta_V = mean(Em - v_interp(1:length(Em)));
indx = SOC_LUT_full' > SOC_LUT(end);
Em_full = [Em; v_interp(indx) + delta_V]; % fill in the gap
Em_full_smoothed = smooth(SOC_LUT_full, Em_full,'sgolay');

Step 5: Determine Battery Voltage and Resistance at Different Temperatures

Use the discharge and temperature data to determine the battery resistance as a function of current and SOC at varying temperatures. The validation data is not included. Figure 4 shows the battery voltage at different temperatures.

ex_datasheetbattery_plot_voltage

Figure contains an axes object. The axes object with xlabel 1-SOC, ylabel Voltage [V] contains 7 objects of type line. These objects represent 25C, n30, n20, n10, 0C, 10C, 40C.

Calculate the resistance at different temperatures using the reference current data set.

R0_LUT = [];
SOC_ub_min = 1;
for i=find(ref_curr & ~val_exp)    
    % determine the max SOC for each temperature
    SOC_array_tmp = x.(['curr50A'  '_temp' temperature_label{i}]);
    SOC_Max_Tempe = SOC_array_tmp(end);
    SOC_ub_min = min(SOC_ub_min,SOC_Max_Tempe);
    SOC_LUT_actual = (0:0.01:SOC_Max_Tempe)';
    N_actual = length(SOC_LUT_actual);
    % Create fit object for V vs. SOC
    voltVsSOC.(['temp' temperature_label{i}]) = fitObj.(['fit' temperature_label{i}])(SOC_LUT_actual);
    % Calculate R0(SOC,T) assuming linear behavior R0 = DeltaV / I
    R0.(['temp' temperature_label{i}]) = (Em_full_smoothed(1:N_actual) - voltVsSOC.(['temp' temperature_label{i}]))./current(ref_exp);
    % Initialize R0 matrix with NaN so that the out of range SOC will
    % retain NaN values
    R0_tmp = NaN*ones(size(SOC_LUT_full));
    R0_tmp (1:N_actual) = smooth(R0.(['temp' temperature_label{i}]),'lowess');
%     R0_tmp (1:N_actual) = R0.(['temp' temperature_label{i}]);
    % Construct LUT
    R0_LUT = [R0_LUT R0_tmp];
end

Determine the battery resistance at different temperatures. R0_LUT = max(R0_LUT,0);

R0_LUT(R0_LUT < 0) = 0;
% For all those SOC break points where R0 is not available and is NaN,
% replace NaN with the R0 at the last SOC at which R0 is available (last
% value hold). This is the most reasonable thing to do with the available
% data. This last value hold would also has minimum real-world impact
% because it would be less likely to discharge a battery to such low SOC
% under low temperature if a fixed discharge cut-off voltage is used.
for i=1:size(R0_LUT,2)
    indx_NAN =isnan(R0_LUT(:,i));
    R0_tmp = R0_LUT(~indx_NAN,i);
    R0_LUT(indx_NAN,i)=R0_tmp(end);
end
T_LUT = 273.15 + temperature(ref_curr & ~val_exp);
[T_LUT1,idx] = sort(T_LUT);
xtmp=R0_LUT;
R0_LUT1(:,1:length(T_LUT)) = xtmp(:,idx);

Figure 5 shows the battery resistance at different temperatures.

ex_datasheetbattery_plot_resistance;

Figure contains an axes object. The axes object with xlabel 1-SOC, ylabel Resistance [ Omega ] contains 6 objects of type line. These objects represent 25C, n30, n20, n10, 0C, 40C.

Step 6: Compare to Arrhenius Behavior

Since the temperature-dependent reaction rate for the lithium-ion battery follows an Arrhenius behavior, you can use a comparison to validate the curve fit.

To determine the curve-fit prediction for the Arrhenius behavior, examine the activation energy, Ea. Obtain the activation energy via the slope of the internal resistance, Ro, versus 1000/T curve for different SOCs. The slope equals the activation energy, Ea, divided by the universal gas constant, Rg.

For a lithium-ion battery, a typical value of Ea is 20 kJ/mol[2]. Figure 6 indicates that the activation energy, Ea, obtained via the slope compares closely with 20 kJ/mol.

ex_datasheetbattery_plot_arrhenius

Figure contains an axes object. The axes object with xlabel 1000/T [1/K], ylabel ln(R indexOf 0 baseline ) blank [ Omega ] contains 10 objects of type scatter, line. These objects represent SOC = 0, SOC = 0.1, SOC = 0.2, SOC = 0.3, SOC = 0.4.

 
Activation energy for Li ion conduction
Ea = 18.5474      20.9467      22.6839      24.3306      23.8578 kJ/mol
Ea for electrolyte transport in Li ion battery = 20 kJ/mol

Step 7: Fit Battery Resistance

Fit the battery resistance to the validated temperature data as a function of SOC and temperature.

R0_LUT_bkpts = [];
counter = 1;
[SOC_LUT_index, ~] = find(abs(SOC_LUT_full-SOCbkpts)<0.001);

for i=find(ref_curr & ~val_exp)
    R0_LUT_bkpts = [R0_LUT_bkpts R0_LUT1(SOC_LUT_index,counter)];
    counter = counter+1;
end

[xx,yy,zz] = prepareSurfaceData(1000./T_LUT1',SOCbkpts,log(R0_LUT_bkpts));
Warning: Removing NaN and Inf from data
[R0_vs_T_SOC_fit, gof] = fit([xx,yy],zz,'linearinterp');
% [R0_vs_T_SOC_fit, gof] = fit([xx,yy],zz,'poly12');
[xx1,yy1,zz1] = prepareSurfaceData(T_LUT1',SOCbkpts,R0_LUT_bkpts);
[R0_vs_T_SOC_fit1, gof] = fit([xx1,yy1],zz1,'linearinterp');

Figures 7 and 8 show the surface plots of the battery resistance as a function of SOC and temperature.

ex_datasheetbattery_plot_surface

Figure contains an axes object. The axes object with xlabel 1000/T [1/K], ylabel SOC contains 2 objects of type line, surface. One or more of the lines displays its values using only markers

Figure contains an axes object. The axes object with xlabel Temperature [K], ylabel SOC contains 2 objects of type line, surface. One or more of the lines displays its values using only markers

Step 8: Validate Battery Model Fit

Figure 9 shows the calculated data and the experimental data set data.

ex_datasheetbattery_plot_validation

Figure contains an axes object. The axes object with xlabel 1-SOC, ylabel Voltage [V] contains 9 objects of type line. One or more of the lines displays its values using only markers These objects represent calc_curr33p3A_temp25C, exper_curr33p3A_temp25C, calc_curr300A_temp25C, exper_curr300A_temp25C, calc_curr50A_temp10C, exper_curr50A_temp10C, calc_curr50A_temp40C, exper_curr50A_temp40C, Em.

Step 9: Set the Datasheet Battery Block Parameters

Set the Rated capacity at nominal temperature parameter to the capacity provided by the datasheet.

BattChargeMax = 100; % Ah Capacity from datasheet 

Set the Open circuit voltage, per cell parameter to Em.

Em=flipud(Em_full_smoothed);

Set the State of charge breakpoints for open circuit voltage parameter to the state of charge vector.

SOCEmBp=SOC_LUT_full;

Set the Internal resistance, per cell parameter to the fitted battery resistance data as a function of SOC and temperature.

RInt=(flipud(R0_LUT_bkpts))';

Set the Battery temperature breakpoints parameter to the temperature vector.

BattTempBp=T_LUT1;

Set the State of charge breakpoints for internal resistance parameter to the SOC vector.

SOCRintBp=SOCbkpts;

Set the Initial battery charge parameter to the value provided by the datasheet.

BattCapInit=100; 

Clean up.

ex_datasheetbattery_cleanup

References

[1] Jackey, Robyn, Tarun Huria, Massimo Ceraolo, and Javier Gazzarri. "High fidelity electrical model with thermal dependence for characterization and simulation of high power lithium battery cells." IEEE International Electric Vehicle Conference. March 2012, pp. 1-8.

[2] Ji, Yan, Yancheng Zhang, and Chao-Yang Wang. Journal of the Electrochemical Society. Volume 160, Issue 4 (2013), A636-A649.

See Also

| | | |