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
    +关注

    关注

    107

    文章

    996

    浏览量

    65946
  • OCV
    OCV
    +关注

    关注

    0

    文章

    25

    浏览量

    12527
  • 线性插值
    +关注

    关注

    0

    文章

    6

    浏览量

    6675
  • 开路电压
    +关注

    关注

    0

    文章

    36

    浏览量

    12608
  • vscode
    +关注

    关注

    1

    文章

    155

    浏览量

    7696

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

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

收藏 人收藏

    评论

    相关推荐

    线性插值

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

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

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

    基于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

    基于PLC的线性插值模糊控制器的设计

    通过对喷淋式除尘系统采用的常规模糊控制器实际应用存在的问题进行分析,提出种分段线性插值的设计方法,并将该方法模糊控制器
    发表于 05-03 17:29 60次下载
    基于PLC的<b class='flag-5'>线性插值</b>模糊控制器的设计

    种改进的线性图像算法

    针对传统的双线性插值法在对图像进行后会不可避免的产生边缘模糊的问题,提出了种改进的线性插值法,该算法首先把待
    发表于 08-20 12:01 29次下载

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

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

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

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

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

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

    基于AIS线性插值的综合方法

    实时视景显示,为了使目标的运动轨迹平滑,针对传统AIS线性插值的弊端,本文提出种综合考虑目标的航速、航向等运行信息的
    发表于 11-13 17:20 13次下载
    基于AIS<b class='flag-5'>线性插值</b>的综合<b class='flag-5'>插</b><b class='flag-5'>值</b>方法

    种不同于双线性插值的上采样方法

    我们可以看到,该网络将传统的非线性插值替换成 DUpsample,同时 feature fuse 方面,不同于之前方法将 Decoder 的特征上采样与 Encoder 特征融合,本工作将 Encoder
    的头像 发表于 04-08 14:47 6415次阅读
    <b class='flag-5'>一</b>种不同于<b class='flag-5'>双线性插值</b>的上采样方法

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

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

    双线性插值算法的讲解

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

    LInterp之线性插值PROGMEM数组生成器

    电子发烧友网站提供《LInterp之线性插值PROGMEM数组生成器.zip》资料免费下载
    发表于 10-20 17:32 0次下载
    LInterp之<b class='flag-5'>线性插值</b>PROGMEM数组生成器

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

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