In the code presented the "End of Discharge" point for matching the real SOC with the calculated one is (eventually) used because the BMS reports a drop in the real SOC at the end of discharge from around 10% to 5%.
Battery nominal capacity estimation using Coulomb Counting
10 views (last 30 days)
Show older comments
Hi all,
I'm trying to estimate the nominal capacity of a PV plant battery pack collecting SOC data from the BMS using current discharge. Once I've collected current, time and SOC data I put those data into matlab and use an optimization algorithm to evaluate the capacity using the following expression (in the attachment) and the following code:
%% Optimization phase
clear all;
clc;
%% Estimation procedure using LSQNONLIN with two possible approach evaluated
% in 'SOCestimation.m': (1) Estimate the C by comparing the REAL SOC (filtered)
% and the one evaluated with CC in each single point till the end; (2) Evaluate C as
% same as before but considering the specific EOD (End of Discharge) point.
% x = C_estimated for battery pack (React) in Ah
x = 5;
x0 = rand*[x];
% Capacity (x stands for unknown) lower and upper bounds
xlb=[1];
xub=[50];
% Setting the optimization alg.
options = optimset('MaxFunEvals',15000,'MaxIter',10,'TolFun',1e-100,'TolX',1e-100,'Algorithm', 'levenberg-marquardt','Display','iter-detailed', 'FinDiffType', 'central'); %'levenberg-marquardt'
[x,resnorm,residual,exitflag,output]=lsqnonlin(@SOCestimation, x0, [xlb], [], options);
---------------------------------------------------------------------------------------------
%% Soc estimation file
function [f] = SOCestimation(x)
%% Loading OCV curve (discharge curves at 200 W during 02/03 november)
%% Filtering the SOC_real from a stepped curve into a linear one (can be commented out)
%
% y = smooth(SOC, 1e100, 'moving');
% filt_len = 1;
% a = 1;
% b = (1/filt_len)*ones(1,filt_len);
% SOC_real_filtered = filter(b,a,y);
%% Evaluate SOC as a function of C in Ah (=x) and the difference between SOC real
% and calculated (Discharge current is negative)
SOC_estim = ((1-(1/(x*3600))*cumtrapz(Time, -Current))*100);
% Estimate the C by comparing the real SOC (filtered or not) with the Coulomb Counting one
% considering also the last SOC value (End of Discharge)
f=SOC_real-SOC_estim;
plot(Time,SOC_real,Time,SOC_estim)
legend({'Real SOC filtered from stepped function','SOC estimated studying the C'})
drawnow
end
The problem is that I'm analyzing different discharge curves (1kW, 200W, 2kW constant power discharge) and I'm obtaining always different nominal capacity:
- 16.06 Ah for 1kW discharge;
- 15.9 Ah for 200W discharge;
- 14.97 Ah for 2kW discharge.
From the datasheet I've got that this battery pack has 4.8 kWh initial capacity and 288V as nominal voltage so nominal initial capacity is 16.8Ah but during lifetime is reported that the nominal capacity is around 4.0 kWh and 4.4 kWh so 13.8Ah - 15.4 Ah.
Please..what is wrong with my code? I'm trying to estimate the maximum capacity of the battery in order to evaluate for example the state of health comparing it to a new battery pack.
Here's the expression used:
5 Comments
MAHENDRAN A
on 29 Nov 2022
Bro, Im too developing SOC estimation model using coulomb counting and kalman filter method. And based on what you asked, I too have doubt on this.
Can you explain me about this topic Battery nominal capacity estimation using Coulomb Counting
Accepted Answer
Askic V
on 17 Nov 2022
Hello Mateo,
I don't think there is a problem in your code. It seems that you used correct way to perform numerical integration.
I have examined your data with the following script:
clear all
clc
close all
load data_R1_15-11-2022.mat
subplot(3, 1, 1)
plot(Tempo, Corrente);
xlabel('Tempo')
ylabel('Corrente');
title('data\_R1\_15-11-2022');
clear % clear variable from previous load
subplot(3,1,2)
load R1_02_nov.mat
Tempo = Tempo_ext_R1;
plot(Tempo, Corrente);
xlabel('Tempo')
ylabel('Corrente');
title('R1\_02nov');
clear % clear variable from previous load
subplot(3,1,3)
load R1_19_ott.mat
Tempo = Tempo_ext_R1;
Corrente = Corrente_ext_R1;
plot(Tempo, Corrente);
xlabel('Tempo')
ylabel('Corrente');
title('R1\_19\_ott');
and the results are shown in the following figure. It seems that you have an unusual spikes in the current. So the difference can be because of the data you used for estimation.
3 Comments
Askic V
on 17 Nov 2022
Just out of curiosity, why do you think this is an error, if you integrate the real measured data?
I have found this info:
If the battery is being discharged very quickly (i.e., the discharge current is high), then the amount of energy that can be extracted from the battery is reduced and the battery capacity is lower.
The source:
So your estimation based on integration of real data confirm this.
More Answers (1)
Askic V
on 16 Nov 2022
Try to add the following line immediately before lsqnonlin call
rng default
I cannot test it myself, because your function use variable 'Time' that is not defined (perhaps global).
See Also
Categories
Find more on Estimators in Help Center and File Exchange
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!