魏晓东 发表于 2025-3-8 19:45:18

XJTU电池数据集详细分析(附代码)—— XJTU battery dataset analysis

电池和实验先容

本实验的实验对象为“力神”制造的18650型镍钴锰酸锂电池,其化学成分为                                             LiNi                            0.5                                          Co                            0.2                                          Mn                            0.3                                          O                            2                                       \text{LiNi}_{0.5}\text{Co}_{0.2}\text{Mn}_{0.3}\text{O}_2                  LiNi0.5​Co0.2​Mn0.3​O2​。
电池的标称容量为2000 mAh,标称电压为3.6 V,充电截止电压和放电截止电压分别为4.2 V和2.5 V。整个实验在室温下举行。
一共包括55只电池,分成6个批次。
充放电装备为ACTS-5V10A-GGS-D,所有数据的采样频率为1Hz。
数据集链接:XJTU battery dataset
论文链接:Physics-informed neural network for lithium-ion battery degradation stable modeling and prognosis
GitHub 链接:Battery-dataset-preprocessing-code-library
SOH估计的Benchmark:Benchmark
所有batch的图片总览

https://i-blog.csdnimg.cn/direct/e1827e23ee5b4261b2a33e45abf0eb36.png
每一行分别是1个batch中的第一个电池的数据,从左到右分别是电压、电流、温度和容量。
代码

import numpy as np
import matplotlib.pyplot as plt
from scipy.io import loadmat
from scipy import interpolate
import os
import functools
插值重采样装饰器
def interpolate_resample(resample=True, num_points=128):
    '''
    插值重采样装饰器,如果resample为True,那么就进行插值重采样,点数为num_points,默认为128;
    否则就不进行重采样
    :param resample: bool: 是否进行重采样
    :param num_points: int: 重采样的点数
    :return:
    '''
    def decorator(func):
      @functools.wraps(func)
      def wrapper(self,*args, **kwargs):
            data = func(self,*args, **kwargs)
            if resample:
                x = np.linspace(0, 1, data.shape)
                f1 = interpolate.interp1d(x, data, kind='linear')
                new_x = np.linspace(0, 1, num_points)
                data = f1(new_x)
            return data
      return wrapper
    return decorator
Battery类,它可以用于读取XJTU电池数据集所有batch的数据
class Battery:
    def __init__(self,path):
      mat = loadmat(path)
      self.data = mat['data']
      self.battery_name = path.split('/')[-1].split('.')
      self.summary = mat['summary']
      self.cycle_life = self.summary
      self.description = self.summary
      self.variable_name = ['system_time','relative_time_min','voltage_V','current_A','capacity_Ah','power_Wh','temperature_C','description']
      print(f'电池寿命:{self.cycle_life}, 电池描述:{self.description}')

    def print_variable_name(self):
      print('0:system_time, '
            '1:relative_time_min, '
            '2:voltage_V, '
            '3:current_A, '
            '4:capacity_Ah, '
            '5:power_Wh, '
            '6:temperature_C, '
            '7:description'
            )

    def get_descriptions(self):
      '''
      电池每个cycle都有一个描述,这个函数返回所有的描述种类
      :return:
      '''
      descriptions = []
      for i in range(self.data.shape):
            description = self.data
            if description not in descriptions:
                descriptions.append(description)
      return descriptions

    def get_one_cycle_description(self,cycle):
      '''
      获取某个cycle的描述
      :param cycle: int: 电池的循环次数
      :return:
      '''
      # 如果cycle大于电池的循环次数,或者小于1,那么就报错,并提示用户
      if cycle > self.data.shape or cycle < 1:
            raise ValueError(f'cycle的值应该在}]之内')
      description = self.data
      return description

    def get_degradation_trajectory(self):
      '''
      获取电池的容量衰减轨迹。因为很多cycle没有完全放电,因此需要用的cycle来插值
      对于完全放电的前几批次数据,该函数与self.get_capacity()函数的结果是一样的
      :return:
      '''
      # 获取测量容量的cycle
      test_capacity_cycles = []
      for i in range(1,self.cycle_life+1):
            des = self.get_one_cycle_description(i)
            if 'test capacity' in des:
                test_capacity_cycles.append(i)
      # 获取测量容量的cycle的容量
      index = np.array(test_capacity_cycles)-1
      capacity = self.get_capacity()
      test_capacity = capacity

      # 利用插值法获取所有cycle的容量
      cycle = np.arange(1,self.cycle_life+1)
      try:
            f = interpolate.interp1d(test_capacity_cycles,test_capacity,kind='cubic',fill_value='extrapolate')
      except:
            f = interpolate.interp1d(test_capacity_cycles,test_capacity,kind='linear',fill_value='extrapolate')
      degradation_trajectory = f(cycle)
      return degradation_trajectory #,(np.array(test_capacity_cycles),test_capacity)

    def get_capacity(self):
      '''
      获取电池的容量曲线
      :return:
      '''
      capacity = self.summary.reshape(-1)
      return capacity

    def get_value(self,cycle,variable):
      '''
      从cycle中提取出variable的数据
      :param cycle: int: 电池的循环次数
      :param variable: int or str: 变量的名称或者索引,可选self.variable_name中的变量
      :return:
      '''
      if isinstance(variable,str):
            variable = self.variable_name.index(variable)
      assert cycle <= self.data.shape
      assert variable <= 7
      value = self.data
      if variable == 7:
            value = value
      else:
            value = value.reshape(-1)
      return value

    # 如果需要重采样,则取消下面这行注释
    # @interpolate_resample(resample=False,num_points=128)
    def get_partial_value(self,cycle,variable,stage=1):
      '''
      从cycle中提取出variable的stage阶段的数据
      :param cycle: int: 电池的循环次数
      :param variable: int or str: 变量的名称或者索引,可选self.variable_name中的变量
      :param stage: int: 阶段的索引,可选, 分别是【充电,静置,放电,静置】; 对于Batch6模拟卫星的实验数据,一共有三个阶段,【分别是充电,静置,放电】
      :return:
      '''
      value = self.get_value(cycle=cycle,variable=variable)
      relative_time_min = self.get_value(cycle=cycle,variable='relative_time_min')
      # 找到relative_time_min中等于0的index
      index = np.where(relative_time_min == 0)
      index = np.insert(index,len(index),len(value))
      value = value:index]
      return value

    # 如果需要重采样,则取消下面这行注释
    # @interpolate_resample(resample=False,num_points=128)
    def get_CC_value(self, cycle, variable, voltage_range=None):
      '''
      获取第cycle个充电的周期的CC过程中的variable的值;如果指定了voltage_range,那么就是在voltage_range范围内的值
      :param cycle: int: 电池的循环次数
      :param variable: int or str: 变量的名称或者索引,可选self.variable_name中的变量
      :param voltage_range: list or None: 电压的范围,默认为None,表示整个CC过程的数据. 也可选其他范围,for example:
      :return:
      '''
      value = self.get_partial_value(cycle=cycle, variable=variable, stage=1)
      voltage = self.get_partial_value(cycle=cycle, variable='voltage_V', stage=1)
      if voltage_range is None:
            index = np.where(voltage <= 4.199)
      else:
            index = np.where((voltage >= voltage_range) & (voltage <= voltage_range))
      value = value
      return value

    # 如果需要重采样,则取消下面这行注释
    # @interpolate_resample(resample=False,num_points=128)
    def get_CV_value(self, cycle, variable, current_range=None):
      '''
      获取第cycle个充电的周期的CV过程中的variable的值;如果指定了current_range,那么就是在current_range范围内的值
      :param cycle: int: 电池的循环次数
      :param variable: int or str: 变量的名称或者索引,可选self.variable_name中的变量
      :param current_range: list or None: 电流的范围,默认为None,表示整个CV过程的数据. 其他可选:for example:
      :return:
      '''
      value = self.get_partial_value(cycle=cycle, variable=variable, stage=1)
      current = self.get_partial_value(cycle=cycle, variable='current_A', stage=1)
      voltage = self.get_partial_value(cycle=cycle, variable='voltage_V', stage=1)
      if current_range is None:
            index = np.where(voltage >= 4.199)
      else:
            index = np.where((current >= np.min(current_range)) & (current <= np.max(current_range)))
      value = value
      return value

    def get_one_cycle(self,cycle):
      '''
      获取某个cycle的所有通道数据
      :param cycle: int: 电池的循环次数
      :return:
      '''
      assert cycle <= self.data.shape
      cycle_data = {}
      cycle_data['system_time'] = self.get_value(cycle=cycle,variable='system_time')
      cycle_data['relative_time_min'] = self.get_value(cycle=cycle,variable='relative_time_min')
      cycle_data['voltage_V'] = self.get_value(cycle=cycle,variable='voltage_V')
      cycle_data['current_A'] = self.get_value(cycle=cycle,variable='current_A')
      cycle_data['capacity_Ah'] = self.get_value(cycle=cycle,variable='capacity_Ah')
      cycle_data['power_Wh'] = self.get_value(cycle=cycle,variable='power_Wh')
      cycle_data['temperature_C'] = self.get_value(cycle=cycle,variable='temperature_C')
      cycle_data['description'] = self.get_value(cycle=cycle,variable='description')
      return cycle_data

    def get_IC_curve1(self,cycle,voltage_range=,step_len=0.01):
      '''
      计算增量容量曲线,公式为:dQ/dV,其中Q为容量,V为电压
      :param cycle: int: 电池的循环次数
      :param voltage_range: list: 电压的范围,默认为None,表示整个电池的电压范围
      :param step_len: float: 对容量数据进行等电压的间隔重采样,默认电压间隔为0.01V
      :return:
      '''
      Q = self.get_CC_value(cycle=cycle,variable='capacity_Ah',voltage_range=voltage_range)
      V = self.get_CC_value(cycle=cycle,variable='voltage_V',voltage_range=voltage_range)

      if len(Q) <= 2 or len(V) <= 2:
            return [],[]

      # 对Q进行等V间隔重采样
      f1 = interpolate.interp1d(V, Q, kind='linear')
      num_points = int((voltage_range - voltage_range) / step_len) + 1
      V_new = np.linspace(V, V[-1], num_points)
      Q_new = f1(V_new)

      dQ = np.diff(Q_new)
      dV = np.diff(V_new)
      IC = dQ/dV

      return IC,V_new

    def get_IC_curve2(self,cycle,voltage_range=,step_len=0.01):
      '''
      计算增量容量曲线,公式为:dQ/dV = I·dt/dV
      :param cycle: int: 电池的循环次数
      :param voltage_range: list: 电压的范围,默认为None,表示整个电池的电压范围
      :param step_len: float: 对电流和时间数据进行等电压的间隔重采样,默认电压间隔为0.01V
      :return:
      '''
      t = self.get_CC_value(cycle=cycle,variable='relative_time_min',voltage_range=voltage_range)
      V = self.get_CC_value(cycle=cycle,variable='voltage_V',voltage_range=voltage_range)
      I = self.get_CC_value(cycle=cycle,variable='current_A',voltage_range=voltage_range)

      # 对t和I进行等电压V间隔重采样
      num_points = int((voltage_range - voltage_range) / step_len) + 1
      f1 = interpolate.interp1d(V, t, kind='linear')
      V_new = np.linspace(V, V[-1], num_points)
      t_new = f1(V_new)
      f2 = interpolate.interp1d(V, I, kind='linear')
      I_new = f2(V_new)

      dt = np.diff(t_new)
      dV = np.diff(V_new)
      Idt = I_new*dt
      IC = Idt/dV
      return IC,V_new
在上面的代码的底子上,我们分别对每个batch的数据举行可视化。
注:下面所画的图都可以调用Battery类中的函数获取数据。
Batch-1

数据先容

固定充放电战略,充满,放完。
第一个cycle测量电池的初始容量:
以0.5C(1A)恒流充电至4.2V,然后维持电压不变,直至电流降至0.02C(40mA);
静置5分钟;以0.2C(0.4A)放电至2.5V。
其他cycles:

[*]以2.0C(4A)恒流充电至4.2V,然后维持电压不变,直至电流降至0.05C(0.1A);
[*]静置5分钟;
[*]以1.0C(2A)放电至2.5V;
[*]静置5分钟。
案例和可视化

# Batch1
battery_path = r'..\Batch-1\2C_battery-1.mat'
battery = Battery(battery_path)
电池寿命:390, 电池描述:2C charge experiment
画容量退化曲线

# 画容量退化曲线
import scienceplots
plt.style.use(['science'])
%matplotlib inline
degradation_trajectory = battery.get_capacity()
fig, ax = plt.subplots(figsize=(3, 2),dpi=200)
plt.plot(degradation_trajectory)
plt.xlabel('Cycle')
plt.ylabel('Capacity (Ah)')
plt.show()
https://i-blog.csdnimg.cn/direct/dc9cce2c04644f5283d978706098c640.png
画任意一个cycle的电压、电流、温度曲线

# 画第100个cycle的电压、电流、温度曲线
current = battery.get_value(cycle=100,variable='current_A')
voltage = battery.get_value(cycle=100,variable='voltage_V')
temperature = battery.get_value(cycle=100,variable='temperature_C')
# 在1*3的子图中画出电压、电流、温度曲线
fig, axs = plt.subplots(1, 3, figsize=(9, 3),dpi=200)
axs.plot(current)
axs.set_xlabel('Time (s)')
axs.set_ylabel('Current (A)')
axs.plot(voltage)
axs.set_xlabel('Time (s)')
axs.set_ylabel('Voltage (V)')
axs.plot(temperature)
axs.set_xlabel('Time (s)')
axs.set_ylabel('Temperature (C)')
plt.tight_layout()
plt.show()
https://i-blog.csdnimg.cn/direct/7d34dfa0287b43f9a20f937c86693bf6.png
画任意一个cycle的【充电阶段】的电压、电流、温度曲线

# 画第100个cycle的充电阶段的电压、电流、温度曲线
current = battery.get_partial_value(cycle=100,stage=1,variable='current_A')
voltage = battery.get_partial_value(cycle=100,stage=1,variable='voltage_V')
temperature = battery.get_partial_value(cycle=100,stage=1,variable='temperature_C')
# 在1*3的子图中画出电压、电流、温度曲线
fig, axs = plt.subplots(1, 3, figsize=(9, 3),dpi=200)
axs.plot(current)
axs.set_xlabel('Time (s)')
axs.set_ylabel('Current (A)')
axs.plot(voltage)
axs.set_xlabel('Time (s)')
axs.set_ylabel('Voltage (V)')
axs.plot(temperature)
axs.set_xlabel('Time (s)')
axs.set_ylabel('Temperature (C)')
plt.tight_layout()
plt.show()
https://i-blog.csdnimg.cn/direct/3ab6b16ac6b446419e4ff519e3f1468a.png
画任意一个cycle的【放电阶段】的电压、电流、温度曲线

# 画第100个cycle的放电阶段的电压、电流、温度曲线
current = battery.get_partial_value(cycle=100,stage=3,variable='current_A')
voltage = battery.get_partial_value(cycle=100,stage=3,variable='voltage_V')
temperature = battery.get_partial_value(cycle=100,stage=3,variable='temperature_C')
# 在1*3的子图中画出电压、电流、温度曲线
fig, axs = plt.subplots(1, 3, figsize=(9, 3),dpi=200)
axs.plot(current)
axs.set_ylim([-1,-3])
axs.set_xlabel('Time (s)')
axs.set_ylabel('Current (A)')
axs.plot(voltage)
axs.set_xlabel('Time (s)')
axs.set_ylabel('Voltage (V)')
axs.plot(temperature)
axs.set_xlabel('Time (s)')
axs.set_ylabel('Temperature (C)')
plt.tight_layout()
plt.show()
https://i-blog.csdnimg.cn/direct/01a3d39d596e4f908147ac0e97c8b149.png
画任意一个cycle的【恒流充电】阶段的曲线,可指定电压范围

# 画第100个cycle恒流充电阶段,电压范围为的电压、电流、温度曲线
relative_time = battery.get_CC_value(cycle=100,variable='relative_time_min',voltage_range=)
current = battery.get_CC_value(cycle=100,variable='current_A',voltage_range=)
voltage = battery.get_CC_value(cycle=100,variable='voltage_V',voltage_range=)
temperature = battery.get_CC_value(cycle=100,variable='temperature_C',voltage_range=)
# 在1*3的子图中画出电压、电流、温度曲线
fig, axs = plt.subplots(1, 3, figsize=(9, 3),dpi=200)
axs.plot(relative_time,current)
axs.set_ylim()
axs.set_xlabel('Relative Time (min)')
axs.set_ylabel('Current (A)')
axs.plot(relative_time,voltage)
axs.set_xlabel('Relative Time (min)')
axs.set_ylabel('Voltage (V)')
axs.plot(relative_time,temperature)
axs.set_xlabel('Relative Time (min)')
axs.set_ylabel('Temperature (C)')
plt.tight_layout()
plt.show()
https://i-blog.csdnimg.cn/direct/22e634ec67664b17a9bfb627c4bb61d0.png
画任意一个cycle的【恒压充电】阶段的曲线,可指定电流范围

# 画第100个cycle恒压充电阶段,电流范围为A内的电压、电流、温度曲线
relative_time = battery.get_CV_value(cycle=100,variable='relative_time_min',current_range=)
current = battery.get_CV_value(cycle=100,variable='current_A',current_range=)
voltage = battery.get_CV_value(cycle=100,variable='voltage_V',current_range=)
temperature = battery.get_CV_value(cycle=100,variable='temperature_C',current_range=)
# 在1*3的子图中画出电压、电流、温度曲线
fig, axs = plt.subplots(1, 3, figsize=(9, 3),dpi=200)
axs.plot(relative_time,current)
axs.set_xlabel('Relative Time (min)')
axs.set_ylabel('Current (A)')
axs.plot(relative_time,voltage)
axs.set_xlabel('Relative Time (min)')
axs.set_ylabel('Voltage (V)')
axs.set_ylim()
axs.plot(relative_time,temperature)
axs.set_xlabel('Relative Time (min)')
axs.set_ylabel('Temperature (C)')
plt.tight_layout()
plt.show()
https://i-blog.csdnimg.cn/direct/cbbb3860c2534a0895086e42cdc2bb5a.png
画任意一个cycle的增量容量曲线

# 画第100个cycle的增量容量曲线
IC,V = battery.get_IC_curve1(cycle=100,voltage_range=,step_len=0.01)
fig, ax = plt.subplots(figsize=(3, 2),dpi=200)
plt.plot(V,IC)
plt.xlabel('Voltage (V)')
plt.ylabel('dQ/dV (Ah/V)')
plt.show()
https://i-blog.csdnimg.cn/direct/eba133a6166d4bc6be3fdcc6f298495b.png
画全寿命周期内的充电电压曲线

# 画全寿命周期内的充电电压曲线
fig, ax = plt.subplots(figsize=(3, 2),dpi=200)
cm = plt.cm.GnBu(np.linspace(0,1,battery.cycle_life))
sm = plt.cm.ScalarMappable(cmap='GnBu',norm=plt.Normalize(vmin=0,vmax=battery.cycle_life))
for cycle in range(1,battery.cycle_life+1,5):
    voltage = battery.get_partial_value(cycle=cycle,stage=1,variable='voltage_V')
    plt.plot(voltage,color=cm)
plt.xlabel('Time (s)')
plt.ylabel('Voltage (V)')
cbar = plt.colorbar(sm)
cbar.set_label('Cycle')
plt.show()
https://i-blog.csdnimg.cn/direct/d750e7e160d344128d6d5b5bd39c64b0.png
同理,改变以上代码可以画出其他的曲线,例如增量容量曲线:
fig, ax = plt.subplots(figsize=(3, 2),dpi=200)
cm = plt.cm.GnBu(np.linspace(0,1,battery.cycle_life))
sm = plt.cm.ScalarMappable(cmap='GnBu',norm=plt.Normalize(vmin=0,vmax=battery.cycle_life))
for cycle in range(2,battery.cycle_life+1,5):
    IC,V = battery.get_IC_curve1(cycle=cycle,voltage_range=,step_len=0.01)
    plt.plot(V,IC,color=cm)
plt.xlabel('Voltage (V)')
plt.ylabel('dQ/dV (Ah/V)')
cbar = plt.colorbar(sm)
cbar.set_label('Cycle')
plt.show()
https://i-blog.csdnimg.cn/direct/fe5b7a0c6d5f433b89e83e83626de40a.png
注:以上所有的图都没有颠末重采样,如果需要重采样,可以取消相应函数的表明。
Batch-2

数据集先容

固定充放电战略,充满,放完。
第一个cycle测量电池的初始容量:以0.5C(1A)恒流充电至4.2V,然后维持电压不变,直至电流降至0.02C(40mA);
静置5分钟;以0.2C(0.4A)放电至2.5V。
其他cycles:

[*]以3.0C(A)恒流充电至4.2V,然后维持电压不变,直至电流降至0.05C(0.1A);
[*]静置5分钟;
[*]以1.0C(2A)放电至2.5V;
[*]静置5分钟。
案例和可视化

Batch-2的数据集和Batch-1的数据集类似,可以参考Batch-1的案例和可视化
Batch-3

数据集先容

不固定放电战略,充满,放完。
第一个cycle测量电池的初始容量:以0.5C(1A)恒流充电至4.2V,然后维持电压不变,直至电流降至0.02C(40mA);
静置5分钟;以0.2C(0.4A)放电至2.5V。
其他cycles:

[*]以2.0C(2A)恒流充电至4.2V,然后维持电压不变,直至电流降至0.05C(0.1A);
[*]静置5分钟;
[*]以                                        x                                  x                     xC放电至2.5V(                                        x                                  x                     x在{0.5,1,2,3,5}中循环取值);
[*]静置5分钟;
案例和可视化

battery = Battery('../Batch-3/R2.5_battery-1.mat')
cm = plt.cm.GnBu(np.linspace(0,1,battery.cycle_life))
sm = plt.cm.ScalarMappable(cmap='GnBu',norm=plt.Normalize(vmin=0,vmax=battery.cycle_life))
电池寿命:592, 电池描述:Random discharge to 2.5V
画容量退化曲线

# 画容量退化曲线
degradation_trajectory = battery.get_capacity()
fig, ax = plt.subplots(figsize=(3, 2),dpi=200)
plt.plot(degradation_trajectory)
plt.xlabel('Cycle')
plt.ylabel('Capacity (Ah)')
plt.show()
https://i-blog.csdnimg.cn/direct/7195b1b045504fb58084429dd0cae838.png
从上图可以看出,由于放电电量依次在{0.5,1,2,3,5}C中循环取值,因此放出的电量差异,导致容量退化曲线波动较大。
画电压、电流、温度曲线

在一张图上画出放电电流取值{0.5,1,2,3,5}C的电压、电流、温度曲线
# 在1*3的图中画放电电流取值{0.5,1,2,3,5}C的电压、电流、温度曲线
fig, axs = plt.subplots(1, 3, figsize=(9, 3),dpi=200)
labels = ['0.5C','1C','2C','3C','5C']
for cycle in :
    current = battery.get_value(cycle=cycle,variable='current_A')
    voltage = battery.get_value(cycle=cycle,variable='voltage_V')
    temperature = battery.get_value(cycle=cycle,variable='temperature_C')

    axs.plot(current)
    axs.set_xlabel('Time (s)')
    axs.set_ylabel('Current (A)')
    axs.plot(voltage)
    axs.set_xlabel('Time (s)')
    axs.set_ylabel('Voltage (V)')
    axs.plot(temperature,label=labels)
    axs.set_xlabel('Time (s)')
    axs.set_ylabel('Temperature (C)')
plt.legend()
plt.tight_layout()
plt.show()

https://i-blog.csdnimg.cn/direct/219326d570e940e08b7c7a5307e003e4.png
其他曲线的画法与Batch-1一致,不再赘述。

Batch-4

数据集先容

不固定放电战略,充满,不放完。
第一个cycle测量电池的初始容量:以0.5C(1A)恒流充电至4.2V,然后维持电压不变,直至电流降至0.02C(40mA);
静置5分钟;以0.2C(0.4A)放电至2.5V。
其他cycles:

[*]以2.0C(2A)恒流充电至4.2V,然后维持电压不变,直至电流降至0.05C(0.1A);
[*]静置5分钟;
[*]以                                        x                                  x                     x C放电至3.0V(                                        x                                  x                     x在{0.5,1,2,3,5}中循环取值);
[*]静置5分钟;
每当                                        x                                  x                     x循环完一轮,执行一次以下操作测量容量:以2C(4A)恒流恒压充电至4.2V;静置5分钟;以1C(2A)放电至2.5V;静置5分钟;
案例和可视化

battery = Battery('../Batch-4/R3_battery-1.mat')
cm = plt.cm.GnBu(np.linspace(0,1,battery.cycle_life))
sm = plt.cm.ScalarMappable(cmap='GnBu',norm=plt.Normalize(vmin=0,vmax=battery.cycle_life))
电池寿命:799, 电池描述:Random discharge to 3V
画容量退化曲线和退化轨迹

从Batch-4开始,所有电池都没有完全放电,因此用测试容量的cycle来插值,得到退化曲线。
# 画容量退化曲线和退化轨迹
capacity = battery.get_capacity()
degradation_trajectory = battery.get_degradation_trajectory()
x = np.arange(len(capacity))
fig, ax = plt.subplots(figsize=(3, 1.5),dpi=200)
plt.plot(x,capacity,'--k',linewidth=0.1,alpha=0.6)
plt.scatter(x,capacity,c=cm,s=1,alpha=0.8)
plt.plot(degradation_trajectory,linewidth=1.5,alpha=0.5,c='#FF371B',label='Degradation Trajectory')
plt.xlabel('Cycle')
plt.ylabel('Capacity (Ah)')
plt.legend()
plt.show()
https://i-blog.csdnimg.cn/direct/13d2916368ce43b0babf1f1993cedc01.png
画电压、电流、温度曲线

在一张图上画出放电电流取值{0.5,1,2,3,5}C的电压、电流、温度曲线
# 在1*3的图中画放电电流取值{0.5,1,2,3,5}C的电压、电流、温度曲线
fig, axs = plt.subplots(1, 3, figsize=(9, 3),dpi=200)
labels = ['0.5C','1C','2C','3C','5C']
for cycle in :
    current = battery.get_value(cycle=cycle,variable='current_A')
    voltage = battery.get_value(cycle=cycle,variable='voltage_V')
    temperature = battery.get_value(cycle=cycle,variable='temperature_C')

    axs.plot(current)
    axs.set_xlabel('Time (s)')
    axs.set_ylabel('Current (A)')
    axs.plot(voltage)
    axs.set_xlabel('Time (s)')
    axs.set_ylabel('Voltage (V)')
    axs.plot(temperature,label=labels)
    axs.set_xlabel('Time (s)')
    axs.set_ylabel('Temperature (C)')
plt.legend()
plt.tight_layout()
plt.show()

https://i-blog.csdnimg.cn/direct/31762a59c8184f89b5386b40ed9636f5.png
注:Batch-4的数据集和Batch-3的数据集类似,可以参考Batch-3的案例和可视化
Batch-5

数据集先容

随机游走战略,充满,不放完。
1-20个cycle:

[*]以0.5C(1A)充电至4.2V,然后维持电压不变,直至电流降至0.02C(40mA);
[*]静置5分钟;
[*]然后以                                        x                                  x                     x A放电                                        y                                  y                     y分钟(                                        x                                  x                     x为区间内的随机整数,                                        y                                  y                     y为区间内的随机整数),为保证安全,当电压降至3.0V时停止放电;
[*]静置20分钟。
从21个cycle起重复以下循环:

[*] 测一次容量(以1C(2A)恒流恒压充电至4.2V;静置5分钟;以1C(2A)放电至2.5V;静置5分钟)。
[*] 随机放电10个cycles:
2.1. 以3.0C(6A)充电至4.2V,然后维持电压不变,直至电流降至0.05C(0.1A);
2.2. 静置5分钟;
2.3. 然后以                                             x                                    x                        x A放电                                             y                                    y                        y分钟(x为区间内的随机整数,y为区间内的随机整数),为保证安全,当电压降至3.0V时停止放电;
2.4. 静置10分钟。
案例和可视化

battery = Battery('../Batch-5/RW_battery-1.mat')
cm = plt.cm.GnBu(np.linspace(0,1,battery.cycle_life))
sm = plt.cm.ScalarMappable(cmap='GnBu',norm=plt.Normalize(vmin=0,vmax=battery.cycle_life))
电池寿命:197, 电池描述:Random Walk Discharging experiment
画容量退化曲线和退化轨迹

从Batch-4开始,所有电池都没有完全放电,因此用测试容量的cycle来插值,得到退化曲线。
# 画容量退化曲线和退化轨迹
capacity = battery.get_capacity()
degradation_trajectory = battery.get_degradation_trajectory()
x = np.arange(len(capacity))
fig, ax = plt.subplots(figsize=(3, 1.5),dpi=200)
plt.plot(x,capacity,'--k',linewidth=0.1,alpha=0.6)
plt.scatter(x,capacity,c=cm,s=1,alpha=0.8)
plt.plot(degradation_trajectory,linewidth=1.5,alpha=0.5,c='#FF371B',label='Degradation Trajectory')
plt.xlabel('Cycle')
plt.ylabel('Capacity (Ah)')
plt.legend()
plt.show()
https://i-blog.csdnimg.cn/direct/da60babd7b4f4353b4331cfb77fb9c94.png
画电压、电流、温度曲线

# 在1*3的图中随机画出5个cycle的电压、电流、温度曲线
fig, axs = plt.subplots(1, 3, figsize=(9, 3),dpi=200)
for i in range(1,6):
    current = battery.get_value(cycle=i,variable='current_A')
    voltage = battery.get_value(cycle=i,variable='voltage_V')
    temperature = battery.get_value(cycle=i,variable='temperature_C')
    axs.plot(current)
    axs.set_xlabel('Time (s)')
    axs.set_ylabel('Current (A)')
    axs.plot(voltage)
    axs.set_xlabel('Time (s)')
    axs.set_ylabel('Voltage (V)')
    axs.plot(temperature)
    axs.set_xlabel('Time (s)')
    axs.set_ylabel('Temperature (C)')
plt.tight_layout()
plt.show()
https://i-blog.csdnimg.cn/direct/69ced0c6bc5447f8954a7bc9c4b1cc3c.png
其他曲线的画法与Batch-1一致,不再赘述。
Batch-6

数据集先容

模拟地球同步轨道(Geosynchronous Earth Orbit)卫星电池充放电。
第一个cycle测量电池的初始容量:以0.5C(1A)恒流充电至4.2V,然后维持电压不变,直至电流降至0.02C(40mA);静置5分钟;以0.2C(0.4A)放电至2.5V。
其他cycles:
以2C(4A)充电至4.2V,然后维持电压不变,直至电流降至0.05C(0.1A);
静置5分钟,以0.667C(1.334A)放电,放电持续时间下表所示:
Cycle number1234567891011121314151617181920212223Duration (min)520344146505456586062646869707172727272727272 Cycle number4645444342414039383736353433323130292827262524Duration (min)520344146505456586062646869707172727272727272 大约每5个cycle测一次容量(以1C(2A)恒流恒压充电至4.2V;静置5分钟;以0.5C(1A)放电至2.5V)。
案例和可视化

battery = Battery('../Batch-6/Sim_satellite_battery-1.mat')
cm = plt.cm.GnBu(np.linspace(0,1,battery.cycle_life))
sm = plt.cm.ScalarMappable(cmap='GnBu',norm=plt.Normalize(vmin=0,vmax=battery.cycle_life))
电池寿命:949, 电池描述:Simulate satellite
画容量退化曲线和退化轨迹

从Batch-4开始,所有电池都没有完全放电,因此用测试容量的cycle来插值,得到退化曲线。
# 画容量退化曲线和退化轨迹
capacity = battery.get_capacity()
degradation_trajectory = battery.get_degradation_trajectory()
x = np.arange(len(capacity))
fig, ax = plt.subplots(figsize=(3, 1.5),dpi=200)
plt.plot(x,capacity,'--k',linewidth=0.1,alpha=0.6)
plt.scatter(x,capacity,c=cm,s=1,alpha=0.8)
plt.plot(degradation_trajectory,linewidth=1.5,alpha=0.5,c='#FF371B',label='Degradation Trajectory')
plt.xlabel('Cycle')
plt.ylabel('Capacity (Ah)')
plt.legend()
plt.show()
https://i-blog.csdnimg.cn/direct/efeae3824c344f4b83d4959d9c73f6f0.png
从上图可以看出,电池放电时间以46个cycle为周期,其放出的容量也呈示了周期性。
画电压、电流、温度曲线

画半次循环(23个cycle)的电压、电流、温度曲线
# 在1*3的图中画出23个cycle的电压、电流、温度曲线
fig, axs = plt.subplots(1, 3, figsize=(9, 3),dpi=200)
count = 0
cycle = 2
cm = plt.cm.rainbow(np.linspace(0,1,40))
while count < 23:
    description = battery.get_one_cycle_description(cycle=cycle)
    if 'test capacity' in description:
      cycle += 1
      continue
    current = battery.get_value(cycle=cycle,variable='current_A')
    voltage = battery.get_value(cycle=cycle,variable='voltage_V')
    temperature = battery.get_value(cycle=cycle,variable='temperature_C')
    color = cm
    axs.plot(current,color=color)
    axs.set_xlabel('Time (s)')
    axs.set_ylabel('Current (A)')
    axs.plot(voltage,color=color)
    axs.set_xlabel('Time (s)')
    axs.set_ylabel('Voltage (V)')
    axs.plot(temperature,color=color)
    axs.set_xlabel('Time (s)')
    axs.set_ylabel('Temperature (C)')
    count += 1
    cycle += 1
plt.tight_layout()
plt.show()
https://i-blog.csdnimg.cn/direct/29531876d1104054b6a7a7c3fa59aaf9.png
把静置阶段的index对齐,重新绘制电压、电流、温度曲线
VOLTAGES_C = [] # 充电阶段电压
VOLTAGES_R = [] # 静置阶段电压
VOLTAGES_D = [] # 放电阶段电压
CURRENTS_C = []
CURRENTS_R = []
CURRENTS_D = []
TEMPERATURES_C = []
TEMPERATURES_R = []
TEMPERATURES_D = []
count = 0
cycle = 2
while count < 23:
    description = battery.get_one_cycle_description(cycle=cycle)
    if 'test capacity' in description:
      cycle += 1
      continue

    voltage_c = battery.get_partial_value(cycle=cycle,variable='voltage_V',stage=1)
    voltage_r = battery.get_partial_value(cycle=cycle,variable='voltage_V',stage=2)
    voltage_d = battery.get_partial_value(cycle=cycle,variable='voltage_V',stage=3)
    current_c = battery.get_partial_value(cycle=cycle,variable='current_A',stage=1)
    current_r = battery.get_partial_value(cycle=cycle,variable='current_A',stage=2)
    current_d = battery.get_partial_value(cycle=cycle,variable='current_A',stage=3)
    temperature_c = battery.get_partial_value(cycle=cycle,variable='temperature_C',stage=1)
    temperature_r = battery.get_partial_value(cycle=cycle,variable='temperature_C',stage=2)
    temperature_d = battery.get_partial_value(cycle=cycle,variable='temperature_C',stage=3)

    VOLTAGES_C.append(voltage_c)
    VOLTAGES_R.append(voltage_r)
    VOLTAGES_D.append(voltage_d)
    CURRENTS_C.append(current_c)
    CURRENTS_R.append(current_r)
    CURRENTS_D.append(current_d)
    TEMPERATURES_C.append(temperature_c)
    TEMPERATURES_R.append(temperature_r)
    TEMPERATURES_D.append(temperature_d)

    count += 1
    cycle += 1

# 把voltage_c,voltage_r,voltage_d拼接起来得到voltage,并把voltage按照静置阶段的index对齐
INDEXS = []
VOLTAGES = []
CURRENTS = []
TEMPERATURES = []
for i in range(len(VOLTAGES_C)):
    # 把voltage_c,voltage_r,voltage_d拼接起来得到voltage,并把voltage按照voltage_r的index对齐
    voltage = np.concatenate((VOLTAGES_C,VOLTAGES_R,VOLTAGES_D))
    current = np.concatenate((CURRENTS_C,CURRENTS_R,CURRENTS_D))
    temperature = np.concatenate((TEMPERATURES_C,TEMPERATURES_R,TEMPERATURES_D))
    index = np.arange(len(voltage))
    left_shift = len(VOLTAGES_C)
    index = index - left_shift
    VOLTAGES.append(voltage)
    CURRENTS.append(current)
    TEMPERATURES.append(temperature)
    INDEXS.append(index)

# 在1*3的图中画出23个cycle的电压、电流、温度曲线
fig, axs = plt.subplots(1, 3, figsize=(9, 3),dpi=200)
for i in range(len(VOLTAGES)):
    axs.plot(INDEXS,CURRENTS,linewidth=1.5,alpha=0.5,c=cm)
    axs.plot(INDEXS,VOLTAGES,linewidth=1.5,alpha=0.5,c=cm)
    axs.plot(INDEXS,TEMPERATURES,linewidth=1.5,alpha=0.5,c=cm)
    axs.set_xlabel('Index')
    axs.set_ylabel('Current (A)')
    axs.set_xlabel('Index')
    axs.set_ylabel('Voltage (V)')
    axs.set_xlabel('Index')
    axs.set_ylabel('Temperature (C)')
plt.tight_layout()
plt.show()

https://i-blog.csdnimg.cn/direct/d658701034a04f93bfb9c071222a99aa.png
其他曲线的画法与Batch-1一致,不再赘述。

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
页: [1]
查看完整版本: XJTU电池数据集详细分析(附代码)—— XJTU battery dataset analysis