Part11、什么是線性插值
線性插值法(linear interpolation),是指使用連接兩個已知量的直線來確定在這兩個已知量之間的一個未知量的值的方法。
有好幾種插值方法,本文僅僅介紹一維線性插值和雙線性插值在BMS開發(fā)中的應(yīng)用。
11.1、 一維線性插值
如下圖:
已知坐標(biāo) (x0, y0) 與 (x1, y1),要得到 [x0, x1] 區(qū)間內(nèi)某一位置 x 在直線上的值。
從數(shù)學(xué)上來看,3點處于1條直線,斜率是相等的,于是有:
由于 x 值已知,所以可以從公式得到 y 的值:
公式太長不好記,可以進(jìn)行簡化方便記憶,方然推導(dǎo)也沒問題....
由,
令α = (y-y0)/(x-x0),同樣有,α = (y1 - y0)/(x1 - x0),上面的方程式就可以簡化為:
y = y0 + α(y1 ? y0)
這樣已知x的值,就可以輕松計算出y的值,同樣的,已知y的值,可以輕松求出x的值。
21.2、雙線性插值
在數(shù)學(xué)上,雙線性插值是有兩個變量的插值函數(shù)的線性插值擴(kuò)展,其核心思想是在兩個方向分別進(jìn)行一次線性插值。
以下理論搬自網(wǎng)絡(luò)。
紅色的數(shù)據(jù)點與待插值得到的綠色點
假如我們想得到未知函數(shù) f 在點 P = (x, y) 的值,假設(shè)我們已知函數(shù) f 在 Q11 = (x1, y1)、Q12 = (x1, y2), Q21 = (x2, y1) 以及 Q22 = (x2, y2) 四個點的值。
首先在 x 方向進(jìn)行線性插值,得到:
然后在 y 方向進(jìn)行線性插值,得到:
這樣就得到所要的結(jié)果 f(x, y):
Part22、線性插值在BMS中的應(yīng)用
32.1 一維線性插值在BMS中的應(yīng)用
電芯SOC和開路電壓是有一定關(guān)系的,也就是我們常聽說的OCV,OCV是Open circuit voltage(開路電壓),指的是電池不放電開路時,兩極之間的電位差.
但是因為電池的極化效應(yīng),想要測量準(zhǔn)確的OCV得靜止2小時,假設(shè)我們通過設(shè)置放電電流來控制電池的SOC從100%-0%變化,間隔為1%,那么整個實驗做完至少需要200小時。
來看一組電池數(shù)據(jù),一般電芯廠家提供的都是5%步進(jìn)的SOC對應(yīng)的電壓值,在兩個電壓點之間的SOC可以近似直線,當(dāng)然這樣也是有誤差的。
那么如何利用一維線性差值計算不同電壓下對應(yīng)的SOC值呢?
例如:計算紅框中的某一電壓對應(yīng)的SOC值
根據(jù)一維線性差值的公式編寫代碼如下:
#include#include #defineSOC_FULL(100) #defineSOC_OCV_STEP(SOC_FULL/20) #defineCELLVOL_LEN(21) constuint16_tvoltage[CELLVOL_LEN]={2966,3140,3244,3343,3427,3491,3525, 3576,3633,3687,3730,3772,3813,3858, 3914,3955,4007,4054,4077,4099,4180}; /** *根據(jù)ocv曲線計算SOC */ uint8_tget_soc_by_cellocv(constuint16_t*cell_table,uint16_tcellvol) { /**y=y0+(x-x0)*(y1?y0)/(x1-x0)*/ /**計算3343和3427電壓直接的電壓對應(yīng)的SOC值,取3400電壓下的SOC*/ uint16_tsoc; uint8_ti; if(cellvol<=?cell_table[0])?//?0% ??{ ????return?0; ??} ??else?if?(cellvol?>=cell_table[SOC_FULL/SOC_OCV_STEP])//100% { returnSOC_FULL; } for(i=0;icell_table[i]) { i++; } else { break; } } /**y0=(i-1)*SOC_OCV_STEP*/ /**(x-x0)=(cellvol-cell_table[i-1])*/ /**(y1?y0)=SOC_OCV_STEP,這里由于SOC是5%均勻步進(jìn),所以直接取了步進(jìn)值作為y1-y0*/ soc=(i-1)*SOC_OCV_STEP+SOC_OCV_STEP*(cellvol-cell_table[i-1])/ (cell_table[i]-cell_table[i-1]); returnsoc; } intmain(void) { uint16_tsoc_ocv=0; soc_ocv=get_soc_by_cellocv(voltage,3400); printf(" ----soc_ocv=%d--- ",soc_ocv); return0; }
vscode環(huán)境下編譯看看結(jié)果,我們要計算的是3400mV時候?qū)?yīng)的SOC為18%,計算結(jié)果是OK的,要注意限幅處理,0%和100%對應(yīng)的點。
42.2 雙線性插值在BMS中的應(yīng)用
要計算在負(fù)載情況下的SOC,需要對電壓和電流做建模,獲得比較準(zhǔn)確的SOC,當(dāng)然這個SOC也只是盡可能準(zhǔn)確一些,相比較OCV,電池工作過程中是不能直接使用OCV計算SOC的。
包括電池的充放電MAP,都是需要進(jìn)行二維插值計算的,例如:
看一組數(shù)據(jù),橫軸是電流,縱軸是電壓,中間數(shù)據(jù)為SOC值,接下來看看如何利用雙線性插值計算SOC,這里取得都是1%精度,沒有用浮點類型數(shù)據(jù)。
還是要回歸到第一章節(jié)介紹的公式,雙線性插值實際上是進(jìn)行3次單線性插值,x軸進(jìn)行2次插值計算,y軸進(jìn)行1次插值計算。
就不再針對公式一一分析了,直接上代碼:
#include#include #include #include #defineSOC_FULL(100) #defineSOC_OCV_STEP(SOC_FULL/20) #defineCELLVOL_LEN(21) #defineCURRENT_LEN7 #defineVOLTAGE_LEN6 constuint16_tvoltage[CELLVOL_LEN]={2966,3140,3244,3343,3427,3491,3525, 3576,3633,3687,3730,3772,3813,3858, 3914,3955,4007,4054,4077,4099,4180}; staticconstint32_tcurrent_map[CURRENT_LEN]={0,50,200,500, 1200,2500,2501};//橫軸 staticconstuint16_tvoltage_map[VOLTAGE_LEN]={0,2500,3200, 3380,3500,3501};//縱軸 staticconstint16_tload_soc_map[CURRENT_LEN][VOLTAGE_LEN]={ {100,100,100,100,100,100}, {0,0,4,15,35,100}, {-2,-2,0,8,22,100}, {-4,-4,-1,4,15,100}, {-6,-6,-3,2,10,100}, {-6,-6,-3,2,10,100}, {-6,-6,-3,2,10,100}}; /** *根據(jù)ocv曲線計算SOC */ uint8_tget_soc_by_cellocv(constuint16_t*cell_table,uint16_tcellvol) { /**y=y0+(x-x0)*(y1?y0)/(x1-x0)*/ /**計算3343和3427電壓直接的電壓對應(yīng)的SOC值,取3400電壓下的SOC*/ uint16_tsoc; uint8_ti; if(cellvol<=?cell_table[0])?//?0% ??{ ????return?0; ??} ??else?if?(cellvol?>=cell_table[SOC_FULL/SOC_OCV_STEP])//100% { returnSOC_FULL; } for(i=0;icell_table[i]) { i++; } else { break; } } /**y0=(i-1)*SOC_OCV_STEP*/ /**(x-x0)=(cellvol-cell_table[i-1])*/ /**(y1?y0)=SOC_OCV_STEP,這里由于SOC是5%均勻步進(jìn),所以直接取了步進(jìn)值作為y1-y0*/ soc=(i-1)*SOC_OCV_STEP+SOC_OCV_STEP*(cellvol-cell_table[i-1])/ (cell_table[i]-cell_table[i-1]); returnsoc; } /* *負(fù)載SOC查表 */ staticint16_tget_soc_by_load_map(constint16_t*table,uint16_tvoltage,int32_tcurrent) { int16_tresult=0; int16_tmap_voltage_low=0,map_voltage_high=0,map_current_low=0, map_current_high=0; int16_tmap_high=0,map_low=0; uint8_ti=0; int16_tvol_step=0; int16_tvol_diff=0; int32_tcurrent_step=0; int32_tcurrent_diff=0; int16_tsoc_diff=0; int16_tsoc_step=0; for(i=0;icurrent_map[CURRENT_LEN-1])|| (voltage>voltage_map[VOLTAGE_LEN-1]))) { return100; } vol_diff=voltage-voltage_map[map_voltage_low]; vol_step=voltage_map[map_voltage_high]- voltage_map[map_voltage_low]; soc_step=table[(CURRENT_LEN-1-map_current_low)*VOLTAGE_LEN+ map_voltage_high]- table[(CURRENT_LEN-1-map_current_low)*VOLTAGE_LEN+ map_voltage_low]; map_low=(int16_t)(soc_step*vol_diff/vol_step+ table[(CURRENT_LEN-1-map_current_low)*VOLTAGE_LEN+map_voltage_low]); vol_diff=voltage-voltage_map[map_voltage_low]; vol_step=(voltage_map[map_voltage_high]- voltage_map[map_voltage_low]); soc_step=(table[(CURRENT_LEN-1-map_current_high)*VOLTAGE_LEN+ map_voltage_high]- table[(CURRENT_LEN-1-map_current_high)*VOLTAGE_LEN+ map_voltage_low]); map_high=(int16_t)(vol_diff*soc_step/vol_step+ table[(CURRENT_LEN-1-map_current_high)*VOLTAGE_LEN+ map_voltage_low]); result= (int16_t)((abs(current)-current_map[map_current_low])* (map_high-map_low)/(current_map[map_current_high]-current_map[map_current_low])+ map_low); returnresult; } intmain(void) { int16_tsoc_ocv=0; uint16_tcell_vol=3200; int32_tcurrent=0; while(1) { current+=100; soc_ocv=get_soc_by_cellocv(voltage,3400); printf("----soc_ocv=%d---- ",soc_ocv); soc_ocv=get_soc_by_load_map((constint16_t*)load_soc_map,cell_vol,current); printf("!!!!current=%d,cell_vol=%d,soc_load=%d!!!! ",current,cell_vol,soc_ocv); if(current>2600) return0; Sleep(1000); } return0; }
看下運行結(jié)果,驗證也是OK的,這個代碼寫的略微shi,大家可以自己優(yōu)化優(yōu)化,可以把一維線性函數(shù)抽出來封裝,這樣單線性和雙線性可以復(fù)用函數(shù),代碼更簡潔一些。
Part3經(jīng)驗交流
審核編輯:劉清
-
bms
+關(guān)注
關(guān)注
107文章
996瀏覽量
65946 -
OCV
+關(guān)注
關(guān)注
0文章
25瀏覽量
12527 -
線性插值
+關(guān)注
關(guān)注
0文章
6瀏覽量
6675 -
開路電壓
+關(guān)注
關(guān)注
0文章
36瀏覽量
12608 -
vscode
+關(guān)注
關(guān)注
1文章
155瀏覽量
7696
原文標(biāo)題:線性插值在BMS開發(fā)中的應(yīng)用
文章出處:【微信號:小飛哥玩嵌入式,微信公眾號:小飛哥玩嵌入式】歡迎添加關(guān)注!文章轉(zhuǎn)載請注明出處。
發(fā)布評論請先 登錄
相關(guān)推薦
評論