備注:作者有BMS采集板開發(fā)板出售,有意者私信我
電量(SOC)算法
除了參數(shù)的監(jiān)控與保護(hù)之外,作為BMS系統(tǒng),其中最重要的功能還有一項(xiàng),那便是SOC的計(jì)算。
SOC,全稱是State of Charge,系統(tǒng)荷電狀態(tài),也叫剩余電量,代表的是電池使用一段時(shí)間或長期擱置不用后的剩余容量與其完全充電狀態(tài)的容量的比值,常用百分?jǐn)?shù)表示。
其取值范圍為0~100,當(dāng)SOC=0時(shí)表示電池放電完全,當(dāng)SOC=100時(shí)表示電池完全充滿。
那么SOC有什么意義呢?
任何一個(gè)產(chǎn)品,對于一般的終端用戶而言,如果對其直接提供電壓、電流之類的電池參數(shù),那么用戶可能十分費(fèi)解,因?yàn)閷λ麄儊碚f,使用的電源產(chǎn)品唯一能夠理解的,似乎就只有電量。
比如當(dāng)我詢問你的手機(jī)還剩多少電?你肯定不會回答電池的端電壓還有3.54V,而是直接告訴我還剩大概80%。電動車也是一樣,我們甚至可以粗糙的用幾個(gè)柱狀圖來表示電池當(dāng)前的狀況,這樣也總比直接提供準(zhǔn)確的電壓要好理解很多,即使不準(zhǔn),但能讓用戶直觀的理解工程師想要表達(dá)的意思。
因此,計(jì)算出準(zhǔn)確的SOC,不僅能提升用戶體驗(yàn),而且好能延長產(chǎn)品的使用壽命,這對于任何一塊產(chǎn)品而言意義都非常巨大。
在一般的BMS系統(tǒng)中,計(jì)算電量的方式大概有兩種:
①:硬件
所謂硬件,便是使用一些專門的電量計(jì)芯片來計(jì)算電量,比如說TI的BQ34Z100,這是一塊基于阻抗跟蹤技術(shù)的電量計(jì),其計(jì)算精度不錯,而且操作簡單,只需要在前期進(jìn)行一些簡單的操作(使用TI官方軟件進(jìn)行基本參數(shù)配置,計(jì)算電池化學(xué)參數(shù)CHEM_ID,進(jìn)行充放電循環(huán)學(xué)習(xí)導(dǎo)出量產(chǎn)文件等)然后就可以直接從芯片里讀出電量值。(電量計(jì)芯片的方法本文不涉及,感興趣的同學(xué)可以自行查閱資料,或者在本文下留郵箱)
②:軟件
軟件計(jì)算SOC的方法也不少,有開路電壓法、安時(shí)積分法、內(nèi)阻法、神經(jīng)網(wǎng)絡(luò)和卡爾曼濾波法……
開路電壓法由于要預(yù)計(jì)開路電壓,因此需要長時(shí)間靜置電池組,內(nèi)阻法存在著估算內(nèi)阻的困難,在硬件上也難以實(shí)現(xiàn),神經(jīng)網(wǎng)絡(luò)和卡爾曼濾波法則由于系統(tǒng)設(shè)置的困難,而且在電池管理系統(tǒng)中應(yīng)用時(shí)成本很高,不具備優(yōu)勢,因此相對于開路電壓法、內(nèi)阻法、神經(jīng)網(wǎng)絡(luò)和卡爾曼濾波法本而言,安時(shí)積分由于簡單、有效而常被采用。本文主要介紹基于STM32的BMS的SOC的編程語言算法。
----------------------------------------------------------------------------------------------
?積分是一個(gè)數(shù)學(xué)模擬的概念,如果轉(zhuǎn)化為生活語言,就是累積一端時(shí)間的量,如果轉(zhuǎn)化為程序語言,就是把某個(gè)變量相乘在相加計(jì)算和。
安時(shí)積分中的基本參量自然是電流,在任何一個(gè)能源系統(tǒng)運(yùn)行之時(shí),最能夠體現(xiàn)其運(yùn)行負(fù)荷狀態(tài)的必然就是電流,比如一個(gè)電機(jī),如果想要轉(zhuǎn)的快,回路上的電流必然增大,比如一個(gè)燈泡,如果想要更亮更閃,回路上的電流也要增大。
SOC的數(shù)學(xué)定義是什么?
上面說過,SOC就是一顆電池還剩多少電,也就是容量,電池容量的定義是,在一定條件下,所放出的電量,即電池的容量,我們通常以安培、小時(shí)作為單位,簡稱安時(shí)(用 AH 表示)。
假如有一顆電池當(dāng)前的容量是20AH,就是說明,如果我們用1A的電流來進(jìn)行放電,理論上它可以使用20個(gè)小時(shí),等我們把這顆電池用光之后,再使用1A的電流來充電,理論上也需要20個(gè)小時(shí)才能充滿。
如果使用2A的電流來充放電,那么時(shí)間也會從20小時(shí)縮短到10小時(shí)……
安時(shí)積分的基本原理就是把電流按照時(shí)間進(jìn)行累計(jì),然后記入剩余電量之中,這和用管子朝泳池里灌水是一個(gè)道理。
系統(tǒng)啟動,傳感器開始電流采集,假如每隔20us采集一次,如果采集到的充電電流是1.5A,那么我就認(rèn)為,在這20us的時(shí)間段內(nèi),充電電流一直都是1.5A,那么這段時(shí)間里增加的電量就是1.5A * 20us(這里為了表達(dá)清晰暫時(shí)不轉(zhuǎn)換單位)。
系統(tǒng)充電:現(xiàn)在的剩余電量 = 20us前的電量 + 20us內(nèi)產(chǎn)生的電量;
系統(tǒng)放電:現(xiàn)在的剩余電量 = 20us前的電量 - 20us內(nèi)產(chǎn)生的電量;
我們采集到的電流信息,是負(fù)載/充電器回路上的電流信息,當(dāng)電流大于某個(gè)閾值的時(shí)候(300mA),我們認(rèn)為是充電,當(dāng)電流小于某個(gè)閾值的時(shí)候(-300mA),我們認(rèn)為是放電,這個(gè)沒有問題,不過,如果采集到的電流為0,那么系統(tǒng)就真的沒有任何消耗嗎?
當(dāng)然不是,就算是MCU本身也是需要消耗能源的,它使用的也是電池的電,只不過沒有計(jì)入積分之中,如果想要算法更加精確,我認(rèn)為BMS板子的固定功耗是不能忽略的,雖然電流消耗不大,但畢竟是時(shí)時(shí)刻刻的在消耗,而且這個(gè)消耗幾乎不會有很大的改變,如果考慮了固定功耗,那么新的算法如下:
系統(tǒng)充電:現(xiàn)在的剩余電量 = 20us前的電量 + 20us內(nèi)產(chǎn)生的電量 - 系統(tǒng)固定功耗電流;
系統(tǒng)放電:現(xiàn)在的剩余電量 = 20us前的電量 - 20us內(nèi)產(chǎn)生的電量 - 系統(tǒng)固定功耗電流;
tim_cal_ms = OSTimeGet() - time;//就算現(xiàn)在經(jīng)過的時(shí)間
time = OSTimeGet(); //保存現(xiàn)在的時(shí)間
/* 安時(shí)積分 */
/* 容量 = (當(dāng)前功率電流 - 系統(tǒng)固定功耗) * 時(shí)間 */
cap_mAms = (cap_mAms - (current_mA * tim_cal_ms)) - (SYSTEM_FIXED_POWER_CURRENT * tim_cal);
/* 充電電量或者放電電量累積超過 10mAh */
if((cap_mAms > 36000000) || (cap_mAms < -36000000))
{
capacity += cap_mAms / 3600000; /*整數(shù)個(gè) mAh */
cap_mAms = cap_mAms % 3600000; /* 不足1mAh的電量,做累積 */
}
以上便是安時(shí)積分的基本原理,看著非常簡單,不過,現(xiàn)在還有一個(gè)問題,20us內(nèi)產(chǎn)生的電量(current_mA * tim_cal_ms)這個(gè)值我是可以計(jì)算出來的,但是20us前的電量(cap_mAms)這個(gè)值又從何而來呢?
這個(gè)自然是來自20us之前的狀態(tài),我們再往前推,找到40us前的狀態(tài),然后再往前推,找到60us之前的狀態(tài)……
如果一直往前推以后,肯定會發(fā)現(xiàn)一個(gè)問題,這個(gè)電量算法的安時(shí)積分需要一個(gè)起點(diǎn),也就是系統(tǒng)運(yùn)行之后,我的第一個(gè)參與計(jì)算的電量是多少?
初始電量的來源一般采用開路電壓法來確認(rèn),一顆新電池,如果在靜態(tài)的情況下(無充放電)呆了2個(gè)小時(shí)以上,那么這個(gè)時(shí)候直接使用電壓來尋找電量是很準(zhǔn)確的,比如說3.6V對應(yīng)100%電量,2.7V對應(yīng)1%電量,3V對應(yīng)50%電量,這完全可以做幾次充放電實(shí)驗(yàn)來列出一個(gè)表,橫坐標(biāo)是電壓,縱坐標(biāo)就是電量。
1 const OCV_VALUE_S OcvTable_Dischg_1C[101] = { {2999, 0},
2 {3129, 1}, {3262, 2}, {3292, 3}, {3314, 4}, {3330, 5},
3 {3344, 6}, {3366, 7}, {3375, 8}, {3383, 9}, {3390, 10},
4 {3404, 11}, {3410, 12}, {3416, 13}, {3421, 14}, {3426, 15},
5 {3437, 16}, {3441, 17}, {3446, 18}, {3450, 19}, {3454, 20},
6 {3462, 21}, {3466, 22}, {3470, 23}, {3473, 24}, {3480, 25},
7 {3484, 26}, {3487, 27}, {3490, 28}, {3493, 29}, {3497, 30},
8 {3503, 31}, {3506, 32}, {3510, 33}, {3513, 34}, {3519, 35},
9 {3523, 36}, {3526, 37}, {3529, 38}, {3532, 39}, {3539, 40},
10 {3543, 41}, {3546, 42}, {3550, 43}, {3554, 44}, {3561, 45},
11 {3565, 46}, {3569, 47}, {3573, 48}, {3578, 49}, {3587, 50},
12 {3592, 51}, {3596, 52}, {3601, 53}, {3607, 54}, {3617, 55},
13 {3623, 56}, {3629, 57}, {3635, 58}, {3641, 59}, {3654, 60},
14 {3661, 61}, {3667, 62}, {3674, 63}, {3688, 64}, {3696, 65},
15 {3703, 66}, {3710, 67}, {3718, 68}, {3726, 69}, {3741, 70},
16 {3749, 71}, {3758, 72}, {3766, 73}, {3782, 74}, {3790, 75},
17 {3799, 76}, {3807, 77}, {3816, 78}, {3833, 79}, {3842, 80},
18 {3851, 81}, {3860, 82}, {3877, 83}, {3887, 84}, {3896, 85},
19 {3905, 86}, {3914, 87}, {3933, 88}, {3943, 89}, {3953, 90},
20 {3962, 91}, {3972, 92}, {3992, 93}, {4002, 94}, {4013, 95},
21 {4024, 96}, {4048, 97}, {4063, 98}, {4082, 99}, {4190, 100}};
系統(tǒng)上電以后,讀取電池總電壓,然后尋找到一個(gè)初始的電量值,雖然有些誤差,不過完全可以用這個(gè)值來參與以后的積分運(yùn)算……
不過,還有一個(gè)問題,如果這塊電池并未靜置2小時(shí)以上,剛才還在大功率放電,然后由于某種問題系統(tǒng)重啟,這個(gè)時(shí)候采用開路電壓法似乎就不可行了!
關(guān)于這個(gè)問題,可以用一些設(shè)計(jì)來解決,比如MCU不斷電,或者設(shè)計(jì)一顆外部獨(dú)立RTC,增加外部的flash,實(shí)時(shí)儲存SOC和相關(guān)的信息,在系統(tǒng)啟動后,讀取flash中的SOC,然后判斷其存入的時(shí)刻是否經(jīng)過了2小時(shí),如果上一次存入的SOC的時(shí)間和現(xiàn)在的時(shí)間相差2小時(shí),那么可以采用開路電壓法確定初始SOC。如果事件間隔很小,那么就直接使用FLASH中存儲的SOC值來當(dāng)做初始SOC。
----------------------------------------------------------------------------------------------------------------
用安時(shí)積分算法來計(jì)算SOC,其最大的缺點(diǎn)就是誤差容易累積,甚至有些誤差是不可避免的,比如采用開路電壓法得到的初始SOC值,比如硬件的采集精度,如果每次實(shí)際的充電電流是0.9A,而采集出來的電流是0.1A,按照時(shí)間長此以往的累積下去,最后的電量肯定是虛高的。
在這個(gè)時(shí)候,我們需要一些方法,利用電池本身的特性,來對安時(shí)積分算法進(jìn)行校準(zhǔn)。
在循環(huán)中校準(zhǔn)
鋰電池充電需要經(jīng)過幾個(gè)過程,當(dāng)電池電量低,那么首先是恒流升壓充電,這時(shí)電流固定不變,電壓逐漸升高,等電池電量接近飽和之時(shí),會變成恒壓降流充電,電壓不在發(fā)生明顯變化,電流會急速減小,過程如下圖所示。
?
正是因?yàn)殇囯姵氐娜绱颂匦?,因此我們便有了一個(gè)校準(zhǔn)SOC的時(shí)機(jī),當(dāng)在充電過程中,一旦出現(xiàn)了恒壓降流,并且這種狀態(tài)持續(xù)了足夠長的時(shí)間,那么就可以說明電池已經(jīng)充滿了。
假如由于之前的計(jì)算和采集存在誤差,導(dǎo)致系統(tǒng)現(xiàn)在的SOC等于70%,系統(tǒng)也可以主動使用算法來修正這個(gè)結(jié)果,要么直接將SOC人工設(shè)定為100%,要么主動放大積分的因子,使其加速充電,以更快的速度朝著100%畢竟。
在放電過程中也可以校準(zhǔn),當(dāng)電池的電壓已經(jīng)接近低壓極限,然后電流也只有幾百個(gè)毫安,那么就可以將SOC看做是0%了。
卡爾曼濾波和開路電壓校準(zhǔn)
前面提到過,當(dāng)電池靜置2小時(shí)以后,此刻電壓相對平穩(wěn),我們可以使用開路電壓法直接估算SOC的最新值,也可以用開路電壓和卡爾曼濾波結(jié)合起來用。
卡爾曼濾波是一種很有名的數(shù)據(jù)校準(zhǔn)算法,也可以應(yīng)用在SOC的計(jì)算之上。
卡爾曼濾波的本質(zhì)是解決一個(gè)信任度的問題,我們采集到的電壓查表得到的SOC,與安時(shí)積分計(jì)算出來的SOC,到底哪個(gè)更加準(zhǔn)確?
具體的算法理論這里不展開,我直接把自己的代碼貼出來以供參考:
uint8_t Kalman_Filter_Algorithm(float calculation_vaule, float Q, float R, float measure_vaule)
{
static float x_last = 0;
static float p_last = 0;
static float kg;
static float x_mid;
static float x_now;
static float p_mid;
static float p_now;
/*
Q:過程噪聲,Q增大,動態(tài)響應(yīng)變快,收斂穩(wěn)定性變壞
R:測量噪聲,R增大,動態(tài)響應(yīng)變慢,收斂穩(wěn)定性變好
*/
if ((measure_vaule > calculation_vaule) && ((measure_vaule - calculation_vaule) > 10))
{
measure_vaule = calculation_vaule + 10;
}
else if ((calculation_vaule > measure_vaule) && ((calculation_vaule - measure_vaule) > 10))
{
measure_vaule = calculation_vaule - 10;
}
else
{
;
}
x_now = calculation_vaule;
// 先驗(yàn)估算值
x_mid = calculation_vaule;
// 先驗(yàn)協(xié)方差
p_mid = p_last + Q;
// 卡爾曼增益
kg = p_mid / (p_mid + R);
// 最優(yōu)估計(jì)值
x_now = x_mid + kg*(measure_vaule - x_mid);
// 最新協(xié)方差
p_now = (1 - kg)*p_mid;
p_last = p_now;
x_last = x_now;
return (uint8_t)x_now;
}
有了以上量準(zhǔn)校準(zhǔn)的方法,相信系統(tǒng)的SOC在一般情況下不會偏差太大。
審核編輯 黃宇
-
鋰電池
+關(guān)注
關(guān)注
259文章
7997瀏覽量
169149 -
算法
+關(guān)注
關(guān)注
23文章
4588瀏覽量
92505 -
soc
+關(guān)注
關(guān)注
38文章
4099瀏覽量
217781 -
bms
+關(guān)注
關(guān)注
106文章
966瀏覽量
65634 -
保護(hù)板
+關(guān)注
關(guān)注
1文章
52瀏覽量
11757
發(fā)布評論請先 登錄
相關(guān)推薦
評論