线性插值在BMS开发中的应用

原创 小飞哥玩嵌入式 2023-12-23 11:41

关注、星标公众号,直达精彩内容


Part11、什么是线性插值

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

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

11.1、 一维线性插值

如下图:

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

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

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

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

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

y = y0 + α(y1 − y0)

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

21.2、双线性插值

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

以下理论搬自网络。

红色的数据点与待插值得到的绿色点

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

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

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

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

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

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

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

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

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

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

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

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

#include 
#include 

#define SOC_FULL (100)
#define SOC_OCV_STEP (SOC_FULL / 20)
#define CELLVOL_LEN (21)

const uint16_t voltage[CELLVOL_LEN] 
= {2966314032443343342734913525,
                                       3576363336873730377238133858,
                                       3914395540074054407740994180};

/**
 *根据ocv曲线计算SOC
 */

uint8_t get_soc_by_cellocv(const uint16_t *cell_table, uint16_t cellvol)
{
  /** y = y0 + (x-x0)*(y1 − y0)/(x1-x0)*/
  /**计算3343和3427电压直接的电压对应的SOC值,取3400电压下的SOC*/

  uint16_t soc;
  uint8_t i;

  if (cellvol <= cell_table[0]) // 0%
  {
    return 0;
  }
  else if (cellvol >= cell_table[SOC_FULL / SOC_OCV_STEP]) // 100%
  {
    return SOC_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]);

  return soc;
}

int main(void)
{
  uint16_t soc_ocv = 0;

  soc_ocv = get_soc_by_cellocv(voltage, 3400);

  printf("\n\n----soc_ocv = %d---\n\n", soc_ocv);

  return 0;
}

vscode环境下编译看看结果,我们要计算的是3400mV时候对应的SOC为18%,计算结果是OK的,要注意限幅处理,0%和100%对应的点。

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

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

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

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

还是要回归到第一章节介绍的公式,双线性插值实际上是进行3次单线性插值,x轴进行2次插值计算,y轴进行1次插值计算。

就不再针对公式一一分析了,直接上代码:

#include 
#include 
#include 
#include 

#define SOC_FULL (100)
#define SOC_OCV_STEP (SOC_FULL / 20)
#define CELLVOL_LEN (21)

#define CURRENT_LEN 7
#define VOLTAGE_LEN 6

const uint16_t voltage[CELLVOL_LEN] 
= {2966314032443343342734913525,
                                       3576363336873730377238133858,
                                       3914395540074054407740994180};

static const int32_t current_map[CURRENT_LEN] = {050200500,
                                                 120025002501}; // 横轴
static const uint16_t voltage_map[VOLTAGE_LEN] = {025003200,
                                                  338035003501}; // 纵轴

static const int16_t load_soc_map[CURRENT_LEN][VOLTAGE_LEN] = {
    {100100100100100100},
    {0041535100},
    {-2, -20822100},
    {-4, -4, -1415100},
    {-6, -6, -3210100},
    {-6, -6, -3210100},
    {-6, -6, -3210100}};

/**
 *根据ocv曲线计算SOC
 */

uint8_t get_soc_by_cellocv(const uint16_t *cell_table, uint16_t cellvol)
{
  /** y = y0 + (x-x0)*(y1 − y0)/(x1-x0)*/
  /**计算3343和3427电压直接的电压对应的SOC值,取3400电压下的SOC*/

  uint16_t soc;
  uint8_t i;

  if (cellvol <= cell_table[0]) // 0%
  {
    return 0;
  }
  else if (cellvol >= cell_table[SOC_FULL / SOC_OCV_STEP]) // 100%
  {
    return SOC_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]);

  return soc;
}

/*
 *负载SOC查表
 */

static int16_t get_soc_by_load_map(const int16_t *table, uint16_t voltage, int32_t current)
{
  int16_t result = 0;
  int16_t map_voltage_low = 0, map_voltage_high = 0, map_current_low = 0,
          map_current_high = 0;

  int16_t map_high = 0, map_low = 0;
  uint8_t i = 0;

  int16_t vol_step = 0;
  int16_t vol_diff = 0;

  int32_t current_step = 0;
  int32_t current_diff = 0;
  int16_t soc_diff = 0;
  int16_t soc_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])))
  {
    return 100;
  }
  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);

  return result;
}

int main(void)
{
  int16_t soc_ocv = 0;
  uint16_t cell_vol = 3200;
  int32_t current = 0;

  while (1)
  {
    current += 100;
    soc_ocv = get_soc_by_cellocv(voltage, 3400);
    printf("----soc_ocv = %d----\n", soc_ocv);

    soc_ocv = get_soc_by_load_map((const int16_t *)load_soc_map, cell_vol, current);
    printf("!!!!current = %d,cell_vol = %d,soc_load = %d!!!!\n\n", current, cell_vol, soc_ocv);
    if (current > 2600)
      return 0;

    Sleep(1000);
  }

  return 0;
}

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

Part3经验交流

欢迎关注公众号“小飞哥玩嵌入式”,交流更多嵌入式相关的开发知识,目前从事BMS行业,也可以交流BMS开发相关的内容哈


小飞哥玩嵌入式 分享嵌入式开发相关知识,喜欢DIY分享
评论
  • 一、VSM的基本原理震动样品磁强计(Vibrating Sample Magnetometer,简称VSM)是一种灵敏且高效的磁性测量仪器。其基本工作原理是利用震动样品在探测线圈中引起的变化磁场来产生感应电压,这个感应电压与样品的磁矩成正比。因此,通过测量这个感应电压,我们就能够精确地确定样品的磁矩。在VSM中,被测量的样品通常被固定在一个震动头上,并以一定的频率和振幅震动。这种震动在探测线圈中引起了变化的磁通量,从而产生了一个交流电信号。这个信号的幅度和样品的磁矩有着直接的关系。因此,通过仔细
    锦正茂科技 2025-02-28 13:30 100浏览
  • 1,微软下载免费Visual Studio Code2,安装C/C++插件,如果无法直接点击下载, 可以选择手动install from VSIX:ms-vscode.cpptools-1.23.6@win32-x64.vsix3,安装C/C++编译器MniGW (MinGW在 Windows 环境下提供类似于 Unix/Linux 环境下的开发工具,使开发者能够轻松地在 Windows 上编写和编译 C、C++ 等程序.)4,C/C++插件扩展设置中添加Include Path 5,
    黎查 2025-02-28 14:39 140浏览
  • 在物联网领域中,无线射频技术作为设备间通信的核心手段,已深度渗透工业自动化、智慧城市及智能家居等多元场景。然而,随着物联网设备接入规模的不断扩大,如何降低运维成本,提升通信数据的传输速度和响应时间,实现更广泛、更稳定的覆盖已成为当前亟待解决的系统性难题。SoC无线收发模块-RFM25A12在此背景下,华普微创新推出了一款高性能、远距离与高性价比的Sub-GHz无线SoC收发模块RFM25A12,旨在提升射频性能以满足行业中日益增长与复杂的设备互联需求。值得一提的是,RFM25A12还支持Wi-S
    华普微HOPERF 2025-02-28 09:06 143浏览
  • 请移步 gitee 仓库 https://gitee.com/Newcapec_cn/LiteOS-M_V5.0.2-Release_STM32F103_CubeMX/blob/main/Docs/%E5%9F%BA%E4%BA%8ESTM32F103RCT6%E7%A7%BB%E6%A4%8DLiteOS-M-V5.0.2-Release.md基于STM32F103RCT6移植LiteOS-M-V5.0.2-Release下载源码kernel_liteos_m: OpenHarmon
    逮到一只程序猿 2025-02-27 08:56 195浏览
  • 构建巨量的驾驶场景时,测试ADAS和AD系统面临着巨大挑战,如传统的实验设计(Design of Experiments, DoE)方法难以有效覆盖识别驾驶边缘场景案例,但这些边缘案例恰恰是进一步提升自动驾驶系统性能的关键。一、传统解决方案:静态DoE标准的DoE方案旨在系统性地探索场景的参数空间,从而确保能够实现完全的测试覆盖范围。但在边缘案例,比如暴露在潜在安全风险的场景或是ADAS系统性能极限场景时,DoE方案通常会失效,让我们看一些常见的DoE方案:1、网格搜索法(Grid)实现原理:将
    康谋 2025-02-27 10:00 252浏览
  • RGB灯光无法同步?细致的动态光效设定反而成为产品客诉来源!随着科技的进步和消费者需求变化,电脑接口设备单一功能性已无法满足市场需求,因此在产品上增加「动态光效」的形式便应运而生,藉此吸引消费者目光。这种RGB灯光效果,不仅能增强电脑周边产品的视觉吸引力,还能为用户提供个性化的体验,展现独特自我风格。如今,笔记本电脑、键盘、鼠标、鼠标垫、耳机、显示器等多种电脑接口设备多数已配备动态光效。这些设备的灯光效果会随着音乐节奏、游戏情节或使用者的设置而变化。想象一个画面,当一名游戏玩家,按下电源开关,整
    百佳泰测试实验室 2025-02-27 14:15 137浏览
  • 美国加州CEC能效跟DOE能效有什么区别?CEC/DOE是什么关系?美国加州CEC能效跟DOE能效有什么区别?CEC/DOE是什么关系?‌美国加州CEC能效认证与美国DOE能效认证在多个方面存在显著差异‌。认证范围和适用地区‌CEC能效认证‌:仅适用于在加利福尼亚州销售的电器产品。CEC认证的范围包括制冷设备、房间空调、中央空调、便携式空调、加热器、热水器、游泳池加热器、卫浴配件、光源、应急灯具、交通信号模块、灯具、洗碗机、洗衣机、干衣机、烹饪器具、电机和压缩机、变压器、外置电源、消费类电子设备
    张工nx808593 2025-02-27 18:04 120浏览
  •           近日受某专业机构邀请,参加了官方举办的《广东省科技创新条例》宣讲会。在与会之前,作为一名技术工作者一直认为技术的法例都是保密和侵权方面的,而潜意识中感觉法律有束缚创新工作的进行可能。通过一个上午学习新法,对广东省的科技创新有了新的认识。广东是改革的前沿阵地,是科技创新的沃土,企业是创新的主要个体。《广东省科技创新条例》是广东省为促进科技创新、推动高质量发展而制定的地方性法规,主要内容包括: 总则:明确立法目
    广州铁金刚 2025-02-28 10:14 103浏览
  • 振动样品磁强计是一种用于测量材料磁性的精密仪器,广泛应用于科研、工业检测等领域。然而,其测量准确度会受到多种因素的影响,下面我们将逐一分析这些因素。一、温度因素温度是影响振动样品磁强计测量准确度的重要因素之一。随着温度的变化,材料的磁性也会发生变化,从而影响测量结果的准确性。因此,在进行磁性测量时,应确保恒温环境,以减少温度波动对测量结果的影响。二、样品制备样品的制备过程同样会影响振动样品磁强计的测量准确度。样品的形状、尺寸和表面处理等因素都会对测量结果产生影响。为了确保测量准确度,应严格按照规
    锦正茂科技 2025-02-28 14:05 134浏览
  • 在2024年的科技征程中,具身智能的发展已成为全球关注的焦点。从实验室到现实应用,这一领域正以前所未有的速度推进,改写着人类与机器的互动边界。这一年,我们见证了具身智能技术的突破与变革,它不仅落地各行各业,带来新的机遇,更在深刻影响着我们的生活方式和思维方式。随着相关技术的飞速发展,具身智能不再仅仅是一个技术概念,更像是一把神奇的钥匙。身后的众多行业,无论愿意与否,都像是被卷入一场伟大变革浪潮中的船只,注定要被这股汹涌的力量重塑航向。01为什么是具身智能?为什么在中国?最近,中国具身智能行业的进
    艾迈斯欧司朗 2025-02-28 15:45 221浏览
  • 应用趋势与客户需求,AI PC的未来展望随着人工智能(AI)技术的日益成熟,AI PC(人工智能个人电脑)逐渐成为消费者和企业工作中的重要工具。这类产品集成了最新的AI处理器,如NPU、CPU和GPU,并具备许多智能化功能,为用户带来更高效且直观的操作体验。AI PC的目标是提升工作和日常生活的效率,通过深度学习与自然语言处理等技术,实现更流畅的多任务处理、实时翻译、语音助手、图像生成等功能,满足现代用户对生产力和娱乐的双重需求。随着各行各业对数字转型需求的增长,AI PC也开始在各个领域中显示
    百佳泰测试实验室 2025-02-27 14:08 252浏览
  • 更多生命体征指标风靡的背后都只有一个原因:更多人将健康排在人生第一顺位!“AGEs,也就是晚期糖基化终末产物,英文名Advanced Glycation End-products,是存在于我们体内的一种代谢产物” 艾迈斯欧司朗亚太区健康监测高级市场经理王亚琴说道,“相信业内的朋友都会有关注,最近该指标的热度很高,它可以用来评估人的生活方式是否健康。”据悉,AGEs是可穿戴健康监测领域的一个“萌新”指标,近来备受关注。如果站在学术角度来理解它,那么AGEs是在非酶促条件下,蛋白质、氨基酸
    艾迈斯欧司朗 2025-02-27 14:50 400浏览
  • Matter 协议,原名 CHIP(Connected Home over IP),是由苹果、谷歌、亚马逊和三星等科技巨头联合ZigBee联盟(现连接标准联盟CSA)共同推出的一套基于IP协议的智能家居连接标准,旨在打破智能家居设备之间的 “语言障碍”,实现真正的互联互通。然而,目标与现实之间总有落差,前期阶段的Matter 协议由于设备支持类型有限、设备生态协同滞后以及设备通信协议割裂等原因,并未能彻底消除智能家居中的“设备孤岛”现象,但随着2025年的到来,这些现象都将得到完美的解决。近期,
    华普微HOPERF 2025-02-27 10:32 212浏览
  •         近日,广电计量在聚焦离子束(FIB)领域编写的专业著作《聚焦离子束:失效分析》正式出版,填补了国内聚焦离子束领域实践性专业书籍的空白,为该领域的技术发展与知识传播提供了重要助力。         随着芯片技术不断发展,芯片的集成度越来越高,结构也日益复杂。这使得传统的失效分析方法面临巨大挑战。FIB技术的出现,为芯片失效分析带来了新的解决方案。它能够在纳米尺度上对芯片进行精确加工和分析。当芯
    广电计量 2025-02-28 09:15 116浏览
我要评论
0
点击右上角,分享到朋友圈 我知道啦
请使用浏览器分享功能 我知道啦