備注:作者有BMS采集板開發板出售,有意者私信我
電量(SOC)算法
除了參數的監控與保護之外,作為BMS系統,其中最重要的功能還有一項,那便是SOC的計算。
SOC,全稱是State of Charge,系統荷電狀態,也叫剩余電量,代表的是電池使用一段時間或長期擱置不用后的剩余容量與其完全充電狀態的容量的比值,常用百分數表示。
其取值范圍為0~100,當SOC=0時表示電池放電完全,當SOC=100時表示電池完全充滿。
那么SOC有什么意義呢?
任何一個產品,對于一般的終端用戶而言,如果對其直接提供電壓、電流之類的電池參數,那么用戶可能十分費解,因為對他們來說,使用的電源產品唯一能夠理解的,似乎就只有電量。
比如當我詢問你的手機還剩多少電?你肯定不會回答電池的端電壓還有3.54V,而是直接告訴我還剩大概80%。電動車也是一樣,我們甚至可以粗糙的用幾個柱狀圖來表示電池當前的狀況,這樣也總比直接提供準確的電壓要好理解很多,即使不準,但能讓用戶直觀的理解工程師想要表達的意思。
因此,計算出準確的SOC,不僅能提升用戶體驗,而且好能延長產品的使用壽命,這對于任何一塊產品而言意義都非常巨大。
在一般的BMS系統中,計算電量的方式大概有兩種:
①:硬件
所謂硬件,便是使用一些專門的電量計芯片來計算電量,比如說TI的BQ34Z100,這是一塊基于阻抗跟蹤技術的電量計,其計算精度不錯,而且操作簡單,只需要在前期進行一些簡單的操作(使用TI官方軟件進行基本參數配置,計算電池化學參數CHEM_ID,進行充放電循環學習導出量產文件等)然后就可以直接從芯片里讀出電量值。(電量計芯片的方法本文不涉及,感興趣的同學可以自行查閱資料,或者在本文下留郵箱)
②:軟件
軟件計算SOC的方法也不少,有開路電壓法、安時積分法、內阻法、神經網絡和卡爾曼濾波法……
開路電壓法由于要預計開路電壓,因此需要長時間靜置電池組,內阻法存在著估算內阻的困難,在硬件上也難以實現,神經網絡和卡爾曼濾波法則由于系統設置的困難,而且在電池管理系統中應用時成本很高,不具備優勢,因此相對于開路電壓法、內阻法、神經網絡和卡爾曼濾波法本而言,安時積分由于簡單、有效而常被采用。本文主要介紹基于STM32的BMS的SOC的編程語言算法。
----------------------------------------------------------------------------------------------
?積分是一個數學模擬的概念,如果轉化為生活語言,就是累積一端時間的量,如果轉化為程序語言,就是把某個變量相乘在相加計算和。
安時積分中的基本參量自然是電流,在任何一個能源系統運行之時,最能夠體現其運行負荷狀態的必然就是電流,比如一個電機,如果想要轉的快,回路上的電流必然增大,比如一個燈泡,如果想要更亮更閃,回路上的電流也要增大。
SOC的數學定義是什么?
上面說過,SOC就是一顆電池還剩多少電,也就是容量,電池容量的定義是,在一定條件下,所放出的電量,即電池的容量,我們通常以安培、小時作為單位,簡稱安時(用 AH 表示)。
假如有一顆電池當前的容量是20AH,就是說明,如果我們用1A的電流來進行放電,理論上它可以使用20個小時,等我們把這顆電池用光之后,再使用1A的電流來充電,理論上也需要20個小時才能充滿。
如果使用2A的電流來充放電,那么時間也會從20小時縮短到10小時……
安時積分的基本原理就是把電流按照時間進行累計,然后記入剩余電量之中,這和用管子朝泳池里灌水是一個道理。
系統啟動,傳感器開始電流采集,假如每隔20us采集一次,如果采集到的充電電流是1.5A,那么我就認為,在這20us的時間段內,充電電流一直都是1.5A,那么這段時間里增加的電量就是1.5A * 20us(這里為了表達清晰暫時不轉換單位)。
系統充電:現在的剩余電量 = 20us前的電量 + 20us內產生的電量;
系統放電:現在的剩余電量 = 20us前的電量 - 20us內產生的電量;
我們采集到的電流信息,是負載/充電器回路上的電流信息,當電流大于某個閾值的時候(300mA),我們認為是充電,當電流小于某個閾值的時候(-300mA),我們認為是放電,這個沒有問題,不過,如果采集到的電流為0,那么系統就真的沒有任何消耗嗎?
當然不是,就算是MCU本身也是需要消耗能源的,它使用的也是電池的電,只不過沒有計入積分之中,如果想要算法更加精確,我認為BMS板子的固定功耗是不能忽略的,雖然電流消耗不大,但畢竟是時時刻刻的在消耗,而且這個消耗幾乎不會有很大的改變,如果考慮了固定功耗,那么新的算法如下:
系統充電:現在的剩余電量 = 20us前的電量 + 20us內產生的電量 - 系統固定功耗電流;
系統放電:現在的剩余電量 = 20us前的電量 - 20us內產生的電量 - 系統固定功耗電流;
tim_cal_ms = OSTimeGet() - time;//就算現在經過的時間
time = OSTimeGet(); //保存現在的時間
/* 安時積分 */
/* 容量 = (當前功率電流 - 系統固定功耗) * 時間 */
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; /*整數個 mAh */
cap_mAms = cap_mAms % 3600000; /* 不足1mAh的電量,做累積 */
}
以上便是安時積分的基本原理,看著非常簡單,不過,現在還有一個問題,20us內產生的電量(current_mA * tim_cal_ms)這個值我是可以計算出來的,但是20us前的電量(cap_mAms)這個值又從何而來呢?
這個自然是來自20us之前的狀態,我們再往前推,找到40us前的狀態,然后再往前推,找到60us之前的狀態……
如果一直往前推以后,肯定會發現一個問題,這個電量算法的安時積分需要一個起點,也就是系統運行之后,我的第一個參與計算的電量是多少?
初始電量的來源一般采用開路電壓法來確認,一顆新電池,如果在靜態的情況下(無充放電)呆了2個小時以上,那么這個時候直接使用電壓來尋找電量是很準確的,比如說3.6V對應100%電量,2.7V對應1%電量,3V對應50%電量,這完全可以做幾次充放電實驗來列出一個表,橫坐標是電壓,縱坐標就是電量。
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}};
系統上電以后,讀取電池總電壓,然后尋找到一個初始的電量值,雖然有些誤差,不過完全可以用這個值來參與以后的積分運算……
不過,還有一個問題,如果這塊電池并未靜置2小時以上,剛才還在大功率放電,然后由于某種問題系統重啟,這個時候采用開路電壓法似乎就不可行了!
關于這個問題,可以用一些設計來解決,比如MCU不斷電,或者設計一顆外部獨立RTC,增加外部的flash,實時儲存SOC和相關的信息,在系統啟動后,讀取flash中的SOC,然后判斷其存入的時刻是否經過了2小時,如果上一次存入的SOC的時間和現在的時間相差2小時,那么可以采用開路電壓法確定初始SOC。如果事件間隔很小,那么就直接使用FLASH中存儲的SOC值來當做初始SOC。
----------------------------------------------------------------------------------------------------------------
用安時積分算法來計算SOC,其最大的缺點就是誤差容易累積,甚至有些誤差是不可避免的,比如采用開路電壓法得到的初始SOC值,比如硬件的采集精度,如果每次實際的充電電流是0.9A,而采集出來的電流是0.1A,按照時間長此以往的累積下去,最后的電量肯定是虛高的。
在這個時候,我們需要一些方法,利用電池本身的特性,來對安時積分算法進行校準。
在循環中校準
鋰電池充電需要經過幾個過程,當電池電量低,那么首先是恒流升壓充電,這時電流固定不變,電壓逐漸升高,等電池電量接近飽和之時,會變成恒壓降流充電,電壓不在發生明顯變化,電流會急速減小,過程如下圖所示。
?
正是因為鋰電池的如此特性,因此我們便有了一個校準SOC的時機,當在充電過程中,一旦出現了恒壓降流,并且這種狀態持續了足夠長的時間,那么就可以說明電池已經充滿了。
假如由于之前的計算和采集存在誤差,導致系統現在的SOC等于70%,系統也可以主動使用算法來修正這個結果,要么直接將SOC人工設定為100%,要么主動放大積分的因子,使其加速充電,以更快的速度朝著100%畢竟。
在放電過程中也可以校準,當電池的電壓已經接近低壓極限,然后電流也只有幾百個毫安,那么就可以將SOC看做是0%了。
卡爾曼濾波和開路電壓校準
前面提到過,當電池靜置2小時以后,此刻電壓相對平穩,我們可以使用開路電壓法直接估算SOC的最新值,也可以用開路電壓和卡爾曼濾波結合起來用。
卡爾曼濾波是一種很有名的數據校準算法,也可以應用在SOC的計算之上。
卡爾曼濾波的本質是解決一個信任度的問題,我們采集到的電壓查表得到的SOC,與安時積分計算出來的SOC,到底哪個更加準確?
具體的算法理論這里不展開,我直接把自己的代碼貼出來以供參考:
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增大,動態響應變快,收斂穩定性變壞
R:測量噪聲,R增大,動態響應變慢,收斂穩定性變好
*/
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;
// 先驗估算值
x_mid = calculation_vaule;
// 先驗協方差
p_mid = p_last + Q;
// 卡爾曼增益
kg = p_mid / (p_mid + R);
// 最優估計值
x_now = x_mid + kg*(measure_vaule - x_mid);
// 最新協方差
p_now = (1 - kg)*p_mid;
p_last = p_now;
x_last = x_now;
return (uint8_t)x_now;
}
有了以上量準校準的方法,相信系統的SOC在一般情況下不會偏差太大。
審核編輯 黃宇
-
鋰電池
+關注
關注
260文章
8115瀏覽量
170265 -
算法
+關注
關注
23文章
4613瀏覽量
92948 -
soc
+關注
關注
38文章
4169瀏覽量
218333 -
bms
+關注
關注
107文章
1001瀏覽量
66011 -
保護板
+關注
關注
1文章
53瀏覽量
11801
發布評論請先 登錄
相關推薦
評論