电池循环数据处理简单步骤(电压曲线,IC(容量增量)曲线,容量退化曲线)MIT数据举例

'''2024.3.28更新,这些是已经可以跑通的代码,大家自行取用

CALCE放电过程:CALCE电池数据CS2_35放电过程的IC曲线处理代码--对于异常值处理方式是直接舍弃

CALCE充电过程:CALCE电池数据CS2_35充电过程的IC曲线处理代码--对于异常值处理方式是使用前一个循环的数据进行替代

MIT放电过程:

MIT电池IC数据提取--替代补充版本

NASA充电过程:

NASA电池充电过程IC曲线与放电容量提取

Oxford充电过程:

Oxford充电过程IC曲线和放电容量曲线数据处理

这些对某一块电池进行的数据处理,不同电池不同处理方式,还需要自己理解后根据实际情况处理

'''

#数据集介绍

MIT数据集是当今世界上最大的开源数据集,包含124块快充策略工况的电池(其中一块电池老化很快,一般使用123块电池数据)感兴趣的可以了解出版物《Data-driven prediction of battery cycle life before capacity degradation》,数据地址:Experimental Data Platform (matr.io)

最近在做新的方向,重新处理了一下MIT数据集,才发现作者提供的代码自带转mat为pkl的python代码,mat数据中已经有作者简单计算的dQdV,想来当时要是早看到这个就不用自己去积分电流计算了,不过异常值处理思路还是一样的,也算积累经验了。废话不多说,开始正题。

#容量退化曲线

作者开源了部分加载数据的代码,可以简单了解数据情况,直观了解到异常值较为普遍,不过这种算较为简单的情况,数据的退化曲线较为平滑,能省去不少滤波的步骤。

图1

这里我先拿一块异常的电池做举例(b1c0)其退化情况如图2,阶跃异常和中途的数据波动噪声异常

图2

首先处理阶跃异常,设定阈值,通过diff判断,超过阈值的情况进行差值补充,一般是线性,但为了方便我直接使用前后的数据直接补充,处理结果展示如图3

#bats为数据结构,包含了所有电池的数据,bat_names为电池名称列表
name=bat_names[0]
threshold=0.05#突跃阈值
#去除突跃值
cycle_ind=bats[name]['summary']['cycle'].copy()
QD=bats[name]['summary']['QD'].copy()
QD_nor=QD.copy()
QD_nor[0]=QD_nor[1]#初始循环大部分cell存在突跃值,直接用后一个值代替
QD_diff=np.diff(QD_nor)
outliers = np.where(QD_diff > threshold)[0]

#使用前后循环补充,最好的方式是线性插值补充,但为了方便处理,我就直接这样了
while len(outliers) > 0:
    QD_nor[outliers+1]=QD_nor[outliers]
    QD_diff=np.diff(QD_nor)
    outliers = np.where(QD_diff > threshold)[0]
plt.plot(cycle_ind, QD,color='blue')
plt.plot(cycle_ind, QD_nor,color='red')

图3

随后使用savgol_filter滤波器滤掉噪声干扰,结果如图4,可以看到处理后的曲线平滑且无异常值

#滤波去除干扰,根据实际情况调整参数
window_size =155  # 窗口大小(处理原始数据)
poly_order = 3  # 多项式阶数
QD_S=list(savgol_filter(QD_nor, window_size, poly_order))
plt.plot(cycle_ind, QD_nor,color='red')
plt.plot(cycle_ind, QD_S,color='green')

图4

#IC曲线处理

先简单看一下IC曲线的原始情况如图5,噪声和阶跃同时存在,甚至还有一个循环特别异常(曲线绘制调整cycle范围后,判断在100cycle内)

图5

端口的异常很好处理,根据IC曲线的特性直接将端口附近十个值替代为平坦部分的大概均值就行,而大阶跃使用之前处理容量退化曲线的方法,一直使用前一个值补充,直到没有异常阶跃。小的噪声波动就使用滤波了,这里我常使用分段滤波,平坦部分我希望尽可能平滑,所以使用大窗口滤波,而峰区域小窗口或者不滤波尽可能保留特征。处理结果如图6

#IC曲线处理
i=100     #i!=0,因为第一行数据存在问题
dQdV=bats[name]['cycles'][str(i)]['dQdV'].copy()
dQdV_nor=np.array(dQdV.copy())
#dQdV数据的2.0V端存在突跃情况
dQdV_nor[-10:]=-0.05#曲线的平坦大部分值为-0.1
dQdV_nor[:10]=-0.05
#部分曲线存在突跃值,需要去除
threshold=-0.5
V_ind=np.array(bats[name]['Vdlin'].copy())
outliers = np.where(((V_ind < 2.70) | (V_ind > 3.30))&(dQdV_nor < threshold))[0]
while len(outliers) > 0:
    # 使用前一个值替换这些索引的值
    dQdV_nor[outliers] = dQdV_nor[outliers - 1]
    outliers = np.where(((V_ind < 2.70) | (V_ind > 3.30))&(dQdV_nor < threshold))[0]# & dQdV_nor < threshold)[0]

#对平坦区域大窗口滤波
window=125
poly_order=2
forward=np.where(V_ind<2.70)[0]
backward=np.where(V_ind>3.25)[0]
dQdV_S=dQdV_nor.copy()
dQdV_S[forward]=list(savgol_filter(dQdV_S[forward], window, poly_order))
dQdV_S[backward]=list(savgol_filter(dQdV_S[backward], window, poly_order))
#峰值区域小滤波
window=5
poly_order=3
#peak=np.where((V_ind>2.69)&(V_ind<3.31))[0]
#dQdV_S[peak]=list(savgol_filter(dQdV_S[peak], window, poly_order))
#dQdV_S=list (savgol_filter(dQdV_S, window, poly_order))
plt.plot(V_ind,dQdV,color='red')
plt.plot(V_ind,dQdV_S,color='green')

图6

我们之前看到有一个cycle存在很异常的值,图5的蓝色曲线,可以明显看到IC的峰值与其他的cycle不在同一个范围,我们采用剔除策略,然后看一下前100个cycle的情况如图7,明显没有异常值了

for i in range (1,100):
    dQdV=bats[name]['cycles'][str(i)]['dQdV'].copy()
    
    dQdV_nor=np.array(dQdV.copy())
    #dQdV数据的2.0V端存在突跃情况
    dQdV_nor[-10:]=-0.05#曲线的平坦大部分值为-0.1
    dQdV_nor[:10]=-0.05
    #部分曲线存在突跃值,需要去除
    threshold=-0.5
    V_ind=np.array(bats[name]['Vdlin'].copy())
    outliers = np.where(((V_ind < 2.70) | (V_ind > 3.30))&(dQdV_nor < threshold))[0]
    while len(outliers) > 0:
        # 使用前一个值替换这些索引的值
        dQdV_nor[outliers] = dQdV_nor[outliers - 1]
        outliers = np.where(((V_ind < 2.70) | (V_ind > 3.20))&(dQdV_nor < threshold))[0]# & dQdV_nor < threshold)[0]
    if (min(dQdV_nor)>-6):
            continue
    #对平坦区域大窗口滤波
    window=135
    poly_order=3
    forward=np.where(V_ind<2.70)[0]
    backward=np.where(V_ind>3.25)[0]
    dQdV_S=dQdV_nor.copy()
    dQdV_S[forward]=list(savgol_filter(dQdV_S[forward], window, poly_order))
    dQdV_S[backward]=list(savgol_filter(dQdV_S[backward], window, poly_order))
    #峰值区域小滤波
    window=15
    poly_order=3
    #peak=np.where((V_ind>2.69)&(V_ind<3.31))[0]
    #dQdV_S[peak]=list(savgol_filter(dQdV_S[peak], window, poly_order))
    # dQdV_S=list (savgol_filter(dQdV_S, window, poly_order))
    #plt.plot(V_ind,dQdV_nor)
    plt.plot(V_ind,dQdV_S)
    #plt.plot(V_ind,dQdV)

图7

#电压曲线处理

这里我们举例处理MIT数据的放电曲线,充电曲线是类似的思想处理,简单看一下前100cycle情况如图8。

图8

首先分析曲线下方的0.0的横线,这是由于数据记录是整个cycle记录的,充放电都在同一个list中,而放电容量QD在充电阶段都是0,而电压在整个工作区间变化,我们只需要截取QD非0区段即可;黄线的很明显的阶跃,可能是研究人员整理数据时,不小心将电流数据I放到QD中了(判断依据是所有电池到达80%SOC后会进行1C速率的CCCV的充电策略,电流基本不会改变多少);蓝色曲线的异常可能是将Qc计入QD了,即将充电容量Q_charge错误整理到QD了,知道这些异常原因,我们可以使用diff判断等方法排除异常值了,处理代码如下,最终结果如图9所示,展示200cycle看看情况。

x=0
i=0
while(x<200):
    i+=1
    Q=bats[name]['cycles'][str(i)]['Qd'].copy()
    V=bats[name]['cycles'][str(i)]['V'].copy()
    no_zero=np.where(Q>0.00001)[0][0]
    Q=Q[no_zero:]
    V=V[no_zero:]
    Q[0]=0
    if (max(Q)>1.2) or (max(abs(np.diff(Q)))>1):
        continue
    x+=1
    plt.plot(V,Q)

图9

#结束

至此,基本电池数据处理的简单流程已经展示完了,核心思想是理解异常值的产生,根据实际情况去处理,但仍需保留曲线的特征。

 欢迎批评指正,如果本文对您有帮助,顺手点赞收藏关注博主,谢谢您的阅读。

本文仅供参考,引用请标注来源,禁止copy。

  • 53
    点赞
  • 51
    收藏
    觉得还不错? 一键收藏
  • 17
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 17
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值