0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

什么是线性插值?一维线性插值和双线性插值在BMS开发中的应用

jf_L18yujSQ 来源:小飞哥玩嵌入式 2023-12-24 10:44 次阅读

Part11、什么是线性插值

线性插值法(linear interpolation),是指使用连接两个已知量的直线来确定在这两个已知量之间的一个未知量的值的方法。

有好几种插值方法,本文仅仅介绍一维线性插值和双线性插值在BMS开发中的应用。

11.1、 一维线性插值

如下图:

a5866e84-a145-11ee-8b88-92fbcf53809c.png

已知坐标 (x0, y0) 与 (x1, y1),要得到 [x0, x1] 区间内某一位置 x 在直线上的值。

从数学上来看,3点处于1条直线,斜率是相等的,于是有:

a5936616-a145-11ee-8b88-92fbcf53809c.png

由于 x 值已知,所以可以从公式得到 y 的值:

a59a14ac-a145-11ee-8b88-92fbcf53809c.png

公式太长不好记,可以进行简化方便记忆,方然推导也没问题....

a5936616-a145-11ee-8b88-92fbcf53809c.png

令α = (y-y0)/(x-x0),同样有,α = (y1 - y0)/(x1 - x0),上面的方程式就可以简化为:

y = y0 + α(y1 − y0)

这样已知x的值,就可以轻松计算出y的值,同样的,已知y的值,可以轻松求出x的值。

21.2、双线性插值

在数学上,双线性插值是有两个变量的插值函数的线性插值扩展,其核心思想是在两个方向分别进行一次线性插值。

以下理论搬自网络

a5a9e49a-a145-11ee-8b88-92fbcf53809c.png红色的数据点与待插值得到的绿色点

假如我们想得到未知函数 f 在点 P = (x, y) 的值,假设我们已知函数 f 在 Q11 = (x1, y1)、Q12 = (x1, y2), Q21 = (x2, y1) 以及 Q22 = (x2, y2) 四个点的值。

首先在 x 方向进行线性插值,得到:

a5b7a29c-a145-11ee-8b88-92fbcf53809c.pnga5c26506-a145-11ee-8b88-92fbcf53809c.png

然后在 y 方向进行线性插值,得到:

a5cf4654-a145-11ee-8b88-92fbcf53809c.png

这样就得到所要的结果 f(x, y):

a5daa0da-a145-11ee-8b88-92fbcf53809c.pnga5ed1774-a145-11ee-8b88-92fbcf53809c.png

Part22、线性插值在BMS中的应用

32.1 一维线性插值在BMS中的应用

电芯SOC和开路电压是有一定关系的,也就是我们常听说的OCV,OCV是Open circuit voltage(开路电压),指的是电池不放电开路时,两极之间的电位差.

但是因为电池的极化效应,想要测量准确的OCV得静止2小时,假设我们通过设置放电电流来控制电池的SOC从100%-0%变化,间隔为1%,那么整个实验做完至少需要200小时。

来看一组电池数据,一般电芯厂家提供的都是5%步进的SOC对应的电压值,在两个电压点之间的SOC可以近似直线,当然这样也是有误差的。

a5fa59b6-a145-11ee-8b88-92fbcf53809c.pnga612b09c-a145-11ee-8b88-92fbcf53809c.png

那么如何利用一维线性差值计算不同电压下对应的SOC值呢?

例如:计算红框中的某一电压对应的SOC值

根据一维线性差值的公式编写代码如下:

#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};

/**
*根据ocv曲线计算SOC
*/
uint8_tget_soc_by_cellocv(constuint16_t*cell_table,uint16_tcellvol)
{
/**y=y0+(x-x0)*(y1−y0)/(x1-x0)*/
/**计算3343和3427电压直接的电压对应的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;i< SOC_FULL / SOC_OCV_STEP;)
  {
    if (cellvol >cell_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%均匀步进,所以直接取了步进值作为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环境下编译看看结果,我们要计算的是3400mV时候对应的SOC为18%,计算结果是OK的,要注意限幅处理,0%和100%对应的点。

a624a7a2-a145-11ee-8b88-92fbcf53809c.pnga6317446-a145-11ee-8b88-92fbcf53809c.png

42.2 双线性插值在BMS中的应用

要计算在负载情况下的SOC,需要对电压和电流做建模,获得比较准确的SOC,当然这个SOC也只是尽可能准确一些,相比较OCV,电池工作过程中是不能直接使用OCV计算SOC的。

包括电池的充放电MAP,都是需要进行二维插值计算的,例如:

a63aceb0-a145-11ee-8b88-92fbcf53809c.png

看一组数据,横轴是电流,纵轴是电压,中间数据为SOC值,接下来看看如何利用双线性插值计算SOC,这里取得都是1%精度,没有用浮点类型数据。

a64cff86-a145-11ee-8b88-92fbcf53809c.png

还是要回归到第一章节介绍的公式,双线性插值实际上是进行3次单线性插值,x轴进行2次插值计算,y轴进行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}};

/**
*根据ocv曲线计算SOC
*/
uint8_tget_soc_by_cellocv(constuint16_t*cell_table,uint16_tcellvol)
{
/**y=y0+(x-x0)*(y1−y0)/(x1-x0)*/
/**计算3343和3427电压直接的电压对应的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;i< SOC_FULL / SOC_OCV_STEP;)
  {
    if (cellvol >cell_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%均匀步进,所以直接取了步进值作为y1-y0*/

soc=(i-1)*SOC_OCV_STEP+SOC_OCV_STEP*(cellvol-cell_table[i-1])/
(cell_table[i]-cell_table[i-1]);

returnsoc;
}

/*
*负载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;i< VOLTAGE_LEN; i++) // 循环电压
  {
    if (voltage < voltage_map[i])
    {
      if (i != 0)
      {
        map_voltage_low = i - 1;
        map_voltage_high = i;
      }
      else
      {
        map_voltage_low = i;
        map_voltage_high = i;
      }
      break;
    }
  }
  for (i = 0; i < CURRENT_LEN; i++) // 循环电流
  {
    if (abs(current) < current_map[i])
    {

      if (i != 0)
      {
        map_current_low = i - 1;
        map_current_high = i;
      }
      else
      {
        map_current_low = i;
        map_current_high = i;
      }
      break;
    }
  }
  if (((map_voltage_high == map_voltage_low) ||
       (abs(current) >current_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;
}

看下运行结果,验证也是OK的,这个代码写的略微shi,大家可以自己优化优化,可以把一维线性函数抽出来封装,这样单线性和双线性可以复用函数,代码更简洁一些。

a65ed2f6-a145-11ee-8b88-92fbcf53809c.png

Part3经验交流








审核编辑:刘清

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • bms
    bms
    +关注

    关注

    103

    文章

    854

    浏览量

    64839
  • OCV
    OCV
    +关注

    关注

    0

    文章

    23

    浏览量

    12475
  • 线性插值
    +关注

    关注

    0

    文章

    6

    浏览量

    6657
  • 开路电压
    +关注

    关注

    0

    文章

    31

    浏览量

    12399
  • vscode
    +关注

    关注

    1

    文章

    146

    浏览量

    7376

原文标题:线性插值在BMS开发中的应用

文章出处:【微信号:小飞哥玩嵌入式,微信公众号:小飞哥玩嵌入式】欢迎添加关注!文章转载请注明出处。

收藏 人收藏

    评论

    相关推荐

    Matlab应用函数

    10 table1功能 查表格式 Y = table1(TAB,X0) %返回用表格矩阵TAB 的行线性插值元素,对X0(TAB的第
    发表于 11-03 16:06

    线性插值

    求解线性插值的时候,我先把个数组分成两个,再求的时候,有时候出结果,有时候不出结果,求指教
    发表于 11-08 22:04

    双线性插值法的C语言程序!帮帮忙!拜托各位了!

    DSP6000开发平台上用C语言实现双线性插值法,实现对图像的缩放效果的改进。
    发表于 04-20 18:52

    【安富莱——DSP教程】第21章 InterpolationFunctions的使用

    第21章InterpolationFunctions的使用 本期教程主要讲解数据的线性插值和二数据的双线性插值。 21.1
    发表于 06-23 14:13

    第21章 InterpolationFunctions的使用

    转dsp系列教程本期教程主要讲解数据的线性插值和二数据的双线性插值。 21.1 线性
    发表于 09-26 09:54

    种基于FPGA的实时视频图像处理算法研究与实现

    针对视频的输出显示要求,重点介绍了基于双线性插值算法的实现。ModelSim的仿真结果表明,该算法符合多屏幕显示系统的要求。关键词 视频监控;视频图像处理;双线性插值;FPGA;多屏幕
    发表于 06-28 07:06

    线性插值拟合算法相关资料推荐

    1ohm的阻值或者0.01v的电压建立很大张对应表。般情况下会标定有限个的参考点,然后软件经过差值拟合去估算实际。以电池电压和电量为例。...
    发表于 12-21 06:50

    基于FPGA的线性插值-上

    1,背景 利用FPGA做数据处理、系统控制时,经常需要做线性插值。如图(1)所示,给点A和B的x,y坐标,需要求A,B中间某点C的坐标。限定x取整数。 图(1) 示意图 根据A,
    发表于 11-20 23:10

    基于FPGA的线性插值-

    上次分享了基于FPGA的线性插值的背景和方法原理,今天分享 方法原理的验证。 通常FPGA的开发分为电路功能设计、设计输入、功能仿真、综合优化、综合后仿真、实现、布线后仿真、板级仿真以及芯片编程
    发表于 11-23 23:09

    基于Matlab的双线性插值算法在图像旋转中的应用

    MATLAB双线性插值图像处理的算法,读者可以自行参考。
    发表于 05-04 16:04 1次下载

    基于最优移位双线性插值的图像缩放旋转硬件加速研究

    基于最优移位双线性插值的图像缩放旋转硬件加速研究_丁家隆
    发表于 01-08 15:15 10次下载

    基于双线性插值的图像缩放在GPU上的实现

    基于双线性插值的图像缩放在GPU上的实现
    发表于 01-08 14:47 0次下载

    在FPGA上如何实现双线性插值的计算

    双线性插值顾名思义是线性插值Pro,为了说明白什么是双线性插值,首先得先从线性插值说起。那么什么又是线性呢?
    发表于 08-09 17:33 4435次阅读

    双线性插值算法的讲解

    双线性插值中,我们现在找x0', y0'所在位置旁边的四个点,再根据这四个点与(x0',y0')距离的关系得到权重值,最后计算出目标图像中(x,y)一点的像素值。
    的头像 发表于 09-19 10:25 2319次阅读

    基于FPGA的图像旋转和双线性插值算法设计

    今天开源一个FPGA图像处理相关的项目:图像旋转。图像旋转算法本身非常简单,但是如果想让旋转之后的图像更加完整、平滑,还需要进行双线性插值处理,因此整个算法FPGA实现起来还是有一定难度的。
    的头像 发表于 09-04 16:52 827次阅读
    基于FPGA的图像旋转和<b class='flag-5'>双线性插值</b>算法设计