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

打印 上一主题 下一主题

主题 934|帖子 934|积分 2802

电池和实验先容

本实验的实验对象为“力神”制造的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的图片总览


每一行分别是1个batch中的第一个电池的数据,从左到右分别是电压、电流、温度和容量。

代码

  1. import numpy as np
  2. import matplotlib.pyplot as plt
  3. from scipy.io import loadmat
  4. from scipy import interpolate
  5. import os
  6. import functools
复制代码
插值重采样装饰器
  1. def interpolate_resample(resample=True, num_points=128):
  2.     '''
  3.     插值重采样装饰器,如果resample为True,那么就进行插值重采样,点数为num_points,默认为128;
  4.     否则就不进行重采样
  5.     :param resample: bool: 是否进行重采样
  6.     :param num_points: int: 重采样的点数
  7.     :return:
  8.     '''
  9.     def decorator(func):
  10.         @functools.wraps(func)
  11.         def wrapper(self,*args, **kwargs):
  12.             data = func(self,*args, **kwargs)
  13.             if resample:
  14.                 x = np.linspace(0, 1, data.shape[0])
  15.                 f1 = interpolate.interp1d(x, data, kind='linear')
  16.                 new_x = np.linspace(0, 1, num_points)
  17.                 data = f1(new_x)
  18.             return data
  19.         return wrapper
  20.     return decorator
复制代码
Battery类,它可以用于读取XJTU电池数据集所有batch的数据
  1. class Battery:
  2.     def __init__(self,path):
  3.         mat = loadmat(path)
  4.         self.data = mat['data']
  5.         self.battery_name = path.split('/')[-1].split('.')[0]
  6.         self.summary = mat['summary']
  7.         self.cycle_life = self.summary[0][0][8][0][0]
  8.         self.description = self.summary[0][0][9][0]
  9.         self.variable_name = ['system_time','relative_time_min','voltage_V','current_A','capacity_Ah','power_Wh','temperature_C','description']
  10.         print(f'电池寿命:{self.cycle_life}, 电池描述:{self.description}')
  11.     def print_variable_name(self):
  12.         print('0:system_time, '
  13.               '1:relative_time_min, '
  14.               '2:voltage_V, '
  15.               '3:current_A, '
  16.               '4:capacity_Ah, '
  17.               '5:power_Wh, '
  18.               '6:temperature_C, '
  19.               '7:description'
  20.               )
  21.     def get_descriptions(self):
  22.         '''
  23.         电池每个cycle都有一个描述,这个函数返回所有的描述种类
  24.         :return:
  25.         '''
  26.         descriptions = []
  27.         for i in range(self.data.shape[1]):
  28.             description = self.data[0][i][7][0]
  29.             if description not in descriptions:
  30.                 descriptions.append(description)
  31.         return descriptions
  32.     def get_one_cycle_description(self,cycle):
  33.         '''
  34.         获取某个cycle的描述
  35.         :param cycle: int: 电池的循环次数
  36.         :return:
  37.         '''
  38.         # 如果cycle大于电池的循环次数,或者小于1,那么就报错,并提示用户
  39.         if cycle > self.data.shape[1] or cycle < 1:
  40.             raise ValueError(f'cycle的值应该在[1,{self.data.shape[1]}]之内')
  41.         description = self.data[0][cycle-1][7][0]
  42.         return description
  43.     def get_degradation_trajectory(self):
  44.         '''
  45.         获取电池的容量衰减轨迹。因为很多cycle没有完全放电,因此需要用[test capacity]的cycle来插值
  46.         对于完全放电的前几批次数据,该函数与self.get_capacity()函数的结果是一样的
  47.         :return:
  48.         '''
  49.         # 获取测量容量的cycle
  50.         test_capacity_cycles = []
  51.         for i in range(1,self.cycle_life+1):
  52.             des = self.get_one_cycle_description(i)
  53.             if 'test capacity' in des:
  54.                 test_capacity_cycles.append(i)
  55.         # 获取测量容量的cycle的容量
  56.         index = np.array(test_capacity_cycles)-1
  57.         capacity = self.get_capacity()
  58.         test_capacity = capacity[index]
  59.         # 利用插值法获取所有cycle的容量
  60.         cycle = np.arange(1,self.cycle_life+1)
  61.         try:
  62.             f = interpolate.interp1d(test_capacity_cycles,test_capacity,kind='cubic',fill_value='extrapolate')
  63.         except:
  64.             f = interpolate.interp1d(test_capacity_cycles,test_capacity,kind='linear',fill_value='extrapolate')
  65.         degradation_trajectory = f(cycle)
  66.         return degradation_trajectory #,(np.array(test_capacity_cycles),test_capacity)
  67.     def get_capacity(self):
  68.         '''
  69.         获取电池的容量曲线
  70.         :return:
  71.         '''
  72.         capacity = self.summary[0][0][1].reshape(-1)
  73.         return capacity
  74.     def get_value(self,cycle,variable):
  75.         '''
  76.         从cycle中提取出variable的数据
  77.         :param cycle: int: 电池的循环次数
  78.         :param variable: int or str: 变量的名称或者索引,可选self.variable_name中的变量
  79.         :return:
  80.         '''
  81.         if isinstance(variable,str):
  82.             variable = self.variable_name.index(variable)
  83.         assert cycle <= self.data.shape[1]
  84.         assert variable <= 7
  85.         value = self.data[0][cycle-1][variable]
  86.         if variable == 7:
  87.             value = value[0]
  88.         else:
  89.             value = value.reshape(-1)
  90.         return value
  91.     # 如果需要重采样,则取消下面这行注释
  92.     # @interpolate_resample(resample=False,num_points=128)
  93.     def get_partial_value(self,cycle,variable,stage=1):
  94.         '''
  95.         从cycle中提取出variable的stage阶段的数据
  96.         :param cycle: int: 电池的循环次数
  97.         :param variable: int or str: 变量的名称或者索引,可选self.variable_name中的变量
  98.         :param stage: int: 阶段的索引,可选[1,2,3,4], 分别是【充电,静置,放电,静置】; 对于Batch6模拟卫星的实验数据,一共有三个阶段[1,2,3],【分别是充电,静置,放电】
  99.         :return:
  100.         '''
  101.         value = self.get_value(cycle=cycle,variable=variable)
  102.         relative_time_min = self.get_value(cycle=cycle,variable='relative_time_min')
  103.         # 找到relative_time_min中等于0的index
  104.         index = np.where(relative_time_min == 0)[0]
  105.         index = np.insert(index,len(index),len(value))
  106.         value = value[index[stage-1]:index[stage]]
  107.         return value
  108.     # 如果需要重采样,则取消下面这行注释
  109.     # @interpolate_resample(resample=False,num_points=128)
  110.     def get_CC_value(self, cycle, variable, voltage_range=None):
  111.         '''
  112.         获取第cycle个充电的周期的CC过程中的variable的值;如果指定了voltage_range,那么就是在voltage_range范围内的值
  113.         :param cycle: int: 电池的循环次数
  114.         :param variable: int or str: 变量的名称或者索引,可选self.variable_name中的变量
  115.         :param voltage_range: list or None: 电压的范围,默认为None,表示整个CC过程的数据. 也可选其他范围,for example:[3.5,4.0]
  116.         :return:
  117.         '''
  118.         value = self.get_partial_value(cycle=cycle, variable=variable, stage=1)
  119.         voltage = self.get_partial_value(cycle=cycle, variable='voltage_V', stage=1)
  120.         if voltage_range is None:
  121.             index = np.where(voltage <= 4.199)[0]
  122.         else:
  123.             index = np.where((voltage >= voltage_range[0]) & (voltage <= voltage_range[1]))[0]
  124.         value = value[index]
  125.         return value
  126.     # 如果需要重采样,则取消下面这行注释
  127.     # @interpolate_resample(resample=False,num_points=128)
  128.     def get_CV_value(self, cycle, variable, current_range=None):
  129.         '''
  130.         获取第cycle个充电的周期的CV过程中的variable的值;如果指定了current_range,那么就是在current_range范围内的值
  131.         :param cycle: int: 电池的循环次数
  132.         :param variable: int or str: 变量的名称或者索引,可选self.variable_name中的变量
  133.         :param current_range: list or None: 电流的范围,默认为None,表示整个CV过程的数据. 其他可选:for example:[1.0,0.5]
  134.         :return:
  135.         '''
  136.         value = self.get_partial_value(cycle=cycle, variable=variable, stage=1)
  137.         current = self.get_partial_value(cycle=cycle, variable='current_A', stage=1)
  138.         voltage = self.get_partial_value(cycle=cycle, variable='voltage_V', stage=1)
  139.         if current_range is None:
  140.             index = np.where(voltage >= 4.199)[0]
  141.         else:
  142.             index = np.where((current >= np.min(current_range)) & (current <= np.max(current_range)))[0]
  143.         value = value[index]
  144.         return value
  145.     def get_one_cycle(self,cycle):
  146.         '''
  147.         获取某个cycle的所有通道数据
  148.         :param cycle: int: 电池的循环次数
  149.         :return:
  150.         '''
  151.         assert cycle <= self.data.shape[1]
  152.         cycle_data = {}
  153.         cycle_data['system_time'] = self.get_value(cycle=cycle,variable='system_time')
  154.         cycle_data['relative_time_min'] = self.get_value(cycle=cycle,variable='relative_time_min')
  155.         cycle_data['voltage_V'] = self.get_value(cycle=cycle,variable='voltage_V')
  156.         cycle_data['current_A'] = self.get_value(cycle=cycle,variable='current_A')
  157.         cycle_data['capacity_Ah'] = self.get_value(cycle=cycle,variable='capacity_Ah')
  158.         cycle_data['power_Wh'] = self.get_value(cycle=cycle,variable='power_Wh')
  159.         cycle_data['temperature_C'] = self.get_value(cycle=cycle,variable='temperature_C')
  160.         cycle_data['description'] = self.get_value(cycle=cycle,variable='description')
  161.         return cycle_data
  162.     def get_IC_curve1(self,cycle,voltage_range=[3.6,4.19],step_len=0.01):
  163.         '''
  164.         计算增量容量曲线,公式为:dQ/dV,其中Q为容量,V为电压
  165.         :param cycle: int: 电池的循环次数
  166.         :param voltage_range: list: 电压的范围,默认为None,表示整个电池的电压范围
  167.         :param step_len: float: 对容量数据进行等电压的间隔重采样,默认电压间隔为0.01V
  168.         :return:
  169.         '''
  170.         Q = self.get_CC_value(cycle=cycle,variable='capacity_Ah',voltage_range=voltage_range)
  171.         V = self.get_CC_value(cycle=cycle,variable='voltage_V',voltage_range=voltage_range)
  172.         if len(Q) <= 2 or len(V) <= 2:
  173.             return [],[]
  174.         # 对Q进行等V间隔重采样
  175.         f1 = interpolate.interp1d(V, Q, kind='linear')
  176.         num_points = int((voltage_range[1] - voltage_range[0]) / step_len) + 1
  177.         V_new = np.linspace(V[0], V[-1], num_points)
  178.         Q_new = f1(V_new)
  179.         dQ = np.diff(Q_new)
  180.         dV = np.diff(V_new)
  181.         IC = dQ/dV
  182.         return IC,V_new[1:]
  183.     def get_IC_curve2(self,cycle,voltage_range=[3.6,4.19],step_len=0.01):
  184.         '''
  185.         计算增量容量曲线,公式为:dQ/dV = I·dt/dV
  186.         :param cycle: int: 电池的循环次数
  187.         :param voltage_range: list: 电压的范围,默认为None,表示整个电池的电压范围
  188.         :param step_len: float: 对电流和时间数据进行等电压的间隔重采样,默认电压间隔为0.01V
  189.         :return:
  190.         '''
  191.         t = self.get_CC_value(cycle=cycle,variable='relative_time_min',voltage_range=voltage_range)
  192.         V = self.get_CC_value(cycle=cycle,variable='voltage_V',voltage_range=voltage_range)
  193.         I = self.get_CC_value(cycle=cycle,variable='current_A',voltage_range=voltage_range)
  194.         # 对t和I进行等电压V间隔重采样
  195.         num_points = int((voltage_range[1] - voltage_range[0]) / step_len) + 1
  196.         f1 = interpolate.interp1d(V, t, kind='linear')
  197.         V_new = np.linspace(V[0], V[-1], num_points)
  198.         t_new = f1(V_new)
  199.         f2 = interpolate.interp1d(V, I, kind='linear')
  200.         I_new = f2(V_new)
  201.         dt = np.diff(t_new)
  202.         dV = np.diff(V_new)
  203.         Idt = I_new[1:]*dt
  204.         IC = Idt/dV
  205.         return IC,V_new[1:]
复制代码
在上面的代码的底子上,我们分别对每个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分钟。
案例和可视化

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

  1. # 画容量退化曲线
  2. import scienceplots
  3. plt.style.use(['science'])
  4. %matplotlib inline
  5. degradation_trajectory = battery.get_capacity()
  6. fig, ax = plt.subplots(figsize=(3, 2),dpi=200)
  7. plt.plot(degradation_trajectory[1:])
  8. plt.xlabel('Cycle')
  9. plt.ylabel('Capacity (Ah)')
  10. plt.show()
复制代码

画任意一个cycle的电压、电流、温度曲线

  1. # 画第100个cycle的电压、电流、温度曲线
  2. current = battery.get_value(cycle=100,variable='current_A')
  3. voltage = battery.get_value(cycle=100,variable='voltage_V')
  4. temperature = battery.get_value(cycle=100,variable='temperature_C')
  5. # 在1*3的子图中画出电压、电流、温度曲线
  6. fig, axs = plt.subplots(1, 3, figsize=(9, 3),dpi=200)
  7. axs[0].plot(current)
  8. axs[0].set_xlabel('Time (s)')
  9. axs[0].set_ylabel('Current (A)')
  10. axs[1].plot(voltage)
  11. axs[1].set_xlabel('Time (s)')
  12. axs[1].set_ylabel('Voltage (V)')
  13. axs[2].plot(temperature)
  14. axs[2].set_xlabel('Time (s)')
  15. axs[2].set_ylabel('Temperature (C)')
  16. plt.tight_layout()
  17. plt.show()
复制代码

画任意一个cycle的【充电阶段】的电压、电流、温度曲线

  1. # 画第100个cycle的充电阶段的电压、电流、温度曲线
  2. current = battery.get_partial_value(cycle=100,stage=1,variable='current_A')
  3. voltage = battery.get_partial_value(cycle=100,stage=1,variable='voltage_V')
  4. temperature = battery.get_partial_value(cycle=100,stage=1,variable='temperature_C')
  5. # 在1*3的子图中画出电压、电流、温度曲线
  6. fig, axs = plt.subplots(1, 3, figsize=(9, 3),dpi=200)
  7. axs[0].plot(current)
  8. axs[0].set_xlabel('Time (s)')
  9. axs[0].set_ylabel('Current (A)')
  10. axs[1].plot(voltage)
  11. axs[1].set_xlabel('Time (s)')
  12. axs[1].set_ylabel('Voltage (V)')
  13. axs[2].plot(temperature)
  14. axs[2].set_xlabel('Time (s)')
  15. axs[2].set_ylabel('Temperature (C)')
  16. plt.tight_layout()
  17. plt.show()
复制代码

画任意一个cycle的【放电阶段】的电压、电流、温度曲线

  1. # 画第100个cycle的放电阶段的电压、电流、温度曲线
  2. current = battery.get_partial_value(cycle=100,stage=3,variable='current_A')
  3. voltage = battery.get_partial_value(cycle=100,stage=3,variable='voltage_V')
  4. temperature = battery.get_partial_value(cycle=100,stage=3,variable='temperature_C')
  5. # 在1*3的子图中画出电压、电流、温度曲线
  6. fig, axs = plt.subplots(1, 3, figsize=(9, 3),dpi=200)
  7. axs[0].plot(current)
  8. axs[0].set_ylim([-1,-3])
  9. axs[0].set_xlabel('Time (s)')
  10. axs[0].set_ylabel('Current (A)')
  11. axs[1].plot(voltage)
  12. axs[1].set_xlabel('Time (s)')
  13. axs[1].set_ylabel('Voltage (V)')
  14. axs[2].plot(temperature)
  15. axs[2].set_xlabel('Time (s)')
  16. axs[2].set_ylabel('Temperature (C)')
  17. plt.tight_layout()
  18. plt.show()
复制代码

画任意一个cycle的【恒流充电】阶段的曲线,可指定电压范围

  1. # 画第100个cycle恒流充电阶段,电压范围为[3.8,4.0]的电压、电流、温度曲线
  2. relative_time = battery.get_CC_value(cycle=100,variable='relative_time_min',voltage_range=[3.8,4.0])
  3. current = battery.get_CC_value(cycle=100,variable='current_A',voltage_range=[3.8,4.0])
  4. voltage = battery.get_CC_value(cycle=100,variable='voltage_V',voltage_range=[3.8,4.0])
  5. temperature = battery.get_CC_value(cycle=100,variable='temperature_C',voltage_range=[3.8,4.0])
  6. # 在1*3的子图中画出电压、电流、温度曲线
  7. fig, axs = plt.subplots(1, 3, figsize=(9, 3),dpi=200)
  8. axs[0].plot(relative_time,current)
  9. axs[0].set_ylim([3,5])
  10. axs[0].set_xlabel('Relative Time (min)')
  11. axs[0].set_ylabel('Current (A)')
  12. axs[1].plot(relative_time,voltage)
  13. axs[1].set_xlabel('Relative Time (min)')
  14. axs[1].set_ylabel('Voltage (V)')
  15. axs[2].plot(relative_time,temperature)
  16. axs[2].set_xlabel('Relative Time (min)')
  17. axs[2].set_ylabel('Temperature (C)')
  18. plt.tight_layout()
  19. plt.show()
复制代码

画任意一个cycle的【恒压充电】阶段的曲线,可指定电流范围

  1. # 画第100个cycle恒压充电阶段,电流范围为[1.0,0.5]A内的电压、电流、温度曲线
  2. relative_time = battery.get_CV_value(cycle=100,variable='relative_time_min',current_range=[1.0,0.5])
  3. current = battery.get_CV_value(cycle=100,variable='current_A',current_range=[1.0,0.5])
  4. voltage = battery.get_CV_value(cycle=100,variable='voltage_V',current_range=[1.0,0.5])
  5. temperature = battery.get_CV_value(cycle=100,variable='temperature_C',current_range=[1.0,0.5])
  6. # 在1*3的子图中画出电压、电流、温度曲线
  7. fig, axs = plt.subplots(1, 3, figsize=(9, 3),dpi=200)
  8. axs[0].plot(relative_time,current)
  9. axs[0].set_xlabel('Relative Time (min)')
  10. axs[0].set_ylabel('Current (A)')
  11. axs[1].plot(relative_time,voltage)
  12. axs[1].set_xlabel('Relative Time (min)')
  13. axs[1].set_ylabel('Voltage (V)')
  14. axs[1].set_ylim([4.1,4.3])
  15. axs[2].plot(relative_time,temperature)
  16. axs[2].set_xlabel('Relative Time (min)')
  17. axs[2].set_ylabel('Temperature (C)')
  18. plt.tight_layout()
  19. plt.show()
复制代码

画任意一个cycle的增量容量曲线

  1. # 画第100个cycle的增量容量曲线
  2. IC,V = battery.get_IC_curve1(cycle=100,voltage_range=[3.6,4.19],step_len=0.01)
  3. fig, ax = plt.subplots(figsize=(3, 2),dpi=200)
  4. plt.plot(V,IC)
  5. plt.xlabel('Voltage (V)')
  6. plt.ylabel('dQ/dV (Ah/V)')
  7. plt.show()
复制代码

画全寿命周期内的充电电压曲线

  1. # 画全寿命周期内的充电电压曲线
  2. fig, ax = plt.subplots(figsize=(3, 2),dpi=200)
  3. cm = plt.cm.GnBu(np.linspace(0,1,battery.cycle_life))
  4. sm = plt.cm.ScalarMappable(cmap='GnBu',norm=plt.Normalize(vmin=0,vmax=battery.cycle_life))
  5. for cycle in range(1,battery.cycle_life+1,5):
  6.     voltage = battery.get_partial_value(cycle=cycle,stage=1,variable='voltage_V')
  7.     plt.plot(voltage,color=cm[cycle-1])
  8. plt.xlabel('Time (s)')
  9. plt.ylabel('Voltage (V)')
  10. cbar = plt.colorbar(sm)
  11. cbar.set_label('Cycle')
  12. plt.show()
复制代码

同理,改变以上代码可以画出其他的曲线,例如增量容量曲线:
  1. fig, ax = plt.subplots(figsize=(3, 2),dpi=200)
  2. cm = plt.cm.GnBu(np.linspace(0,1,battery.cycle_life))
  3. sm = plt.cm.ScalarMappable(cmap='GnBu',norm=plt.Normalize(vmin=0,vmax=battery.cycle_life))
  4. for cycle in range(2,battery.cycle_life+1,5):
  5.     IC,V = battery.get_IC_curve1(cycle=cycle,voltage_range=[3.6,4.19],step_len=0.01)
  6.     plt.plot(V,IC,color=cm[cycle-1])
  7. plt.xlabel('Voltage (V)')
  8. plt.ylabel('dQ/dV (Ah/V)')
  9. cbar = plt.colorbar(sm)
  10. cbar.set_label('Cycle')
  11. plt.show()
复制代码

:以上所有的图都没有颠末重采样,如果需要重采样,可以取消相应函数的表明。

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分钟;
案例和可视化

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

  1. # 画容量退化曲线
  2. degradation_trajectory = battery.get_capacity()
  3. fig, ax = plt.subplots(figsize=(3, 2),dpi=200)
  4. plt.plot(degradation_trajectory)
  5. plt.xlabel('Cycle')
  6. plt.ylabel('Capacity (Ah)')
  7. plt.show()
复制代码

从上图可以看出,由于放电电量依次在{0.5,1,2,3,5}C中循环取值,因此放出的电量差异,导致容量退化曲线波动较大。
画电压、电流、温度曲线

在一张图上画出放电电流取值{0.5,1,2,3,5}C的电压、电流、温度曲线
  1. # 在1*3的图中画放电电流取值{0.5,1,2,3,5}C的电压、电流、温度曲线
  2. fig, axs = plt.subplots(1, 3, figsize=(9, 3),dpi=200)
  3. labels = ['0.5C','1C','2C','3C','5C']
  4. for cycle in [2,3,4,5,6]:
  5.     current = battery.get_value(cycle=cycle,variable='current_A')
  6.     voltage = battery.get_value(cycle=cycle,variable='voltage_V')
  7.     temperature = battery.get_value(cycle=cycle,variable='temperature_C')
  8.     axs[0].plot(current)
  9.     axs[0].set_xlabel('Time (s)')
  10.     axs[0].set_ylabel('Current (A)')
  11.     axs[1].plot(voltage)
  12.     axs[1].set_xlabel('Time (s)')
  13.     axs[1].set_ylabel('Voltage (V)')
  14.     axs[2].plot(temperature,label=labels[cycle-2])
  15.     axs[2].set_xlabel('Time (s)')
  16.     axs[2].set_ylabel('Temperature (C)')
  17. plt.legend()
  18. plt.tight_layout()
  19. plt.show()
复制代码

其他曲线的画法与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分钟;
案例和可视化

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

从Batch-4开始,所有电池都没有完全放电,因此用测试容量的cycle来插值,得到退化曲线。
  1. # 画容量退化曲线和退化轨迹
  2. capacity = battery.get_capacity()
  3. degradation_trajectory = battery.get_degradation_trajectory()
  4. x = np.arange(len(capacity))
  5. fig, ax = plt.subplots(figsize=(3, 1.5),dpi=200)
  6. plt.plot(x,capacity,'--k',linewidth=0.1,alpha=0.6)
  7. plt.scatter(x,capacity,c=cm,s=1,alpha=0.8)
  8. plt.plot(degradation_trajectory,linewidth=1.5,alpha=0.5,c='#FF371B',label='Degradation Trajectory')
  9. plt.xlabel('Cycle')
  10. plt.ylabel('Capacity (Ah)')
  11. plt.legend()
  12. plt.show()
复制代码

画电压、电流、温度曲线

在一张图上画出放电电流取值{0.5,1,2,3,5}C的电压、电流、温度曲线
  1. # 在1*3的图中画放电电流取值{0.5,1,2,3,5}C的电压、电流、温度曲线
  2. fig, axs = plt.subplots(1, 3, figsize=(9, 3),dpi=200)
  3. labels = ['0.5C','1C','2C','3C','5C']
  4. for cycle in [2,3,4,5,6]:
  5.     current = battery.get_value(cycle=cycle,variable='current_A')
  6.     voltage = battery.get_value(cycle=cycle,variable='voltage_V')
  7.     temperature = battery.get_value(cycle=cycle,variable='temperature_C')
  8.     axs[0].plot(current)
  9.     axs[0].set_xlabel('Time (s)')
  10.     axs[0].set_ylabel('Current (A)')
  11.     axs[1].plot(voltage)
  12.     axs[1].set_xlabel('Time (s)')
  13.     axs[1].set_ylabel('Voltage (V)')
  14.     axs[2].plot(temperature,label=labels[cycle-2])
  15.     axs[2].set_xlabel('Time (s)')
  16.     axs[2].set_ylabel('Temperature (C)')
  17. plt.legend()
  18. plt.tight_layout()
  19. plt.show()
复制代码

注: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为[2,8]区间内的随机整数,                                        y                                  y                     y为[2,6]区间内的随机整数),为保证安全,当电压降至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为[2,8]区间内的随机整数,y为[2,6]区间内的随机整数),为保证安全,当电压降至3.0V时停止放电;
    2.4. 静置10分钟。
案例和可视化

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

从Batch-4开始,所有电池都没有完全放电,因此用测试容量的cycle来插值,得到退化曲线。
  1. # 画容量退化曲线和退化轨迹
  2. capacity = battery.get_capacity()
  3. degradation_trajectory = battery.get_degradation_trajectory()
  4. x = np.arange(len(capacity))
  5. fig, ax = plt.subplots(figsize=(3, 1.5),dpi=200)
  6. plt.plot(x,capacity,'--k',linewidth=0.1,alpha=0.6)
  7. plt.scatter(x,capacity,c=cm,s=1,alpha=0.8)
  8. plt.plot(degradation_trajectory,linewidth=1.5,alpha=0.5,c='#FF371B',label='Degradation Trajectory')
  9. plt.xlabel('Cycle')
  10. plt.ylabel('Capacity (Ah)')
  11. plt.legend()
  12. plt.show()
复制代码

画电压、电流、温度曲线

  1. # 在1*3的图中随机画出5个cycle的电压、电流、温度曲线
  2. fig, axs = plt.subplots(1, 3, figsize=(9, 3),dpi=200)
  3. for i in range(1,6):
  4.     current = battery.get_value(cycle=i,variable='current_A')
  5.     voltage = battery.get_value(cycle=i,variable='voltage_V')
  6.     temperature = battery.get_value(cycle=i,variable='temperature_C')
  7.     axs[0].plot(current)
  8.     axs[0].set_xlabel('Time (s)')
  9.     axs[0].set_ylabel('Current (A)')
  10.     axs[1].plot(voltage)
  11.     axs[1].set_xlabel('Time (s)')
  12.     axs[1].set_ylabel('Voltage (V)')
  13.     axs[2].plot(temperature)
  14.     axs[2].set_xlabel('Time (s)')
  15.     axs[2].set_ylabel('Temperature (C)')
  16. plt.tight_layout()
  17. plt.show()
复制代码

其他曲线的画法与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)。
案例和可视化

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

从Batch-4开始,所有电池都没有完全放电,因此用测试容量的cycle来插值,得到退化曲线。
  1. # 画容量退化曲线和退化轨迹
  2. capacity = battery.get_capacity()
  3. degradation_trajectory = battery.get_degradation_trajectory()
  4. x = np.arange(len(capacity))
  5. fig, ax = plt.subplots(figsize=(3, 1.5),dpi=200)
  6. plt.plot(x,capacity,'--k',linewidth=0.1,alpha=0.6)
  7. plt.scatter(x,capacity,c=cm,s=1,alpha=0.8)
  8. plt.plot(degradation_trajectory,linewidth=1.5,alpha=0.5,c='#FF371B',label='Degradation Trajectory')
  9. plt.xlabel('Cycle')
  10. plt.ylabel('Capacity (Ah)')
  11. plt.legend()
  12. plt.show()
复制代码

从上图可以看出,电池放电时间以46个cycle为周期,其放出的容量也呈示了周期性。
画电压、电流、温度曲线

画半次循环(23个cycle)的电压、电流、温度曲线
  1. # 在1*3的图中画出23个cycle的电压、电流、温度曲线
  2. fig, axs = plt.subplots(1, 3, figsize=(9, 3),dpi=200)
  3. count = 0
  4. cycle = 2
  5. cm = plt.cm.rainbow(np.linspace(0,1,40))
  6. while count < 23:
  7.     description = battery.get_one_cycle_description(cycle=cycle)
  8.     if 'test capacity' in description:
  9.         cycle += 1
  10.         continue
  11.     current = battery.get_value(cycle=cycle,variable='current_A')
  12.     voltage = battery.get_value(cycle=cycle,variable='voltage_V')
  13.     temperature = battery.get_value(cycle=cycle,variable='temperature_C')
  14.     color = cm[count]
  15.     axs[0].plot(current,color=color)
  16.     axs[0].set_xlabel('Time (s)')
  17.     axs[0].set_ylabel('Current (A)')
  18.     axs[1].plot(voltage,color=color)
  19.     axs[1].set_xlabel('Time (s)')
  20.     axs[1].set_ylabel('Voltage (V)')
  21.     axs[2].plot(temperature,color=color)
  22.     axs[2].set_xlabel('Time (s)')
  23.     axs[2].set_ylabel('Temperature (C)')
  24.     count += 1
  25.     cycle += 1
  26. plt.tight_layout()
  27. plt.show()
复制代码

把静置阶段的index对齐,重新绘制电压、电流、温度曲线
  1. VOLTAGES_C = [] # 充电阶段电压
  2. VOLTAGES_R = [] # 静置阶段电压
  3. VOLTAGES_D = [] # 放电阶段电压
  4. CURRENTS_C = []
  5. CURRENTS_R = []
  6. CURRENTS_D = []
  7. TEMPERATURES_C = []
  8. TEMPERATURES_R = []
  9. TEMPERATURES_D = []
  10. count = 0
  11. cycle = 2
  12. while count < 23:
  13.     description = battery.get_one_cycle_description(cycle=cycle)
  14.     if 'test capacity' in description:
  15.         cycle += 1
  16.         continue
  17.     voltage_c = battery.get_partial_value(cycle=cycle,variable='voltage_V',stage=1)
  18.     voltage_r = battery.get_partial_value(cycle=cycle,variable='voltage_V',stage=2)
  19.     voltage_d = battery.get_partial_value(cycle=cycle,variable='voltage_V',stage=3)
  20.     current_c = battery.get_partial_value(cycle=cycle,variable='current_A',stage=1)
  21.     current_r = battery.get_partial_value(cycle=cycle,variable='current_A',stage=2)
  22.     current_d = battery.get_partial_value(cycle=cycle,variable='current_A',stage=3)
  23.     temperature_c = battery.get_partial_value(cycle=cycle,variable='temperature_C',stage=1)
  24.     temperature_r = battery.get_partial_value(cycle=cycle,variable='temperature_C',stage=2)
  25.     temperature_d = battery.get_partial_value(cycle=cycle,variable='temperature_C',stage=3)
  26.     VOLTAGES_C.append(voltage_c[1:])
  27.     VOLTAGES_R.append(voltage_r)
  28.     VOLTAGES_D.append(voltage_d)
  29.     CURRENTS_C.append(current_c[1:])
  30.     CURRENTS_R.append(current_r)
  31.     CURRENTS_D.append(current_d)
  32.     TEMPERATURES_C.append(temperature_c[1:])
  33.     TEMPERATURES_R.append(temperature_r)
  34.     TEMPERATURES_D.append(temperature_d)
  35.     count += 1
  36.     cycle += 1
  37. # 把voltage_c,voltage_r,voltage_d拼接起来得到voltage,并把voltage按照静置阶段的index对齐
  38. INDEXS = []
  39. VOLTAGES = []
  40. CURRENTS = []
  41. TEMPERATURES = []
  42. for i in range(len(VOLTAGES_C)):
  43.     # 把voltage_c,voltage_r,voltage_d拼接起来得到voltage,并把voltage按照voltage_r的index对齐
  44.     voltage = np.concatenate((VOLTAGES_C[i],VOLTAGES_R[i],VOLTAGES_D[i]))
  45.     current = np.concatenate((CURRENTS_C[i],CURRENTS_R[i],CURRENTS_D[i]))
  46.     temperature = np.concatenate((TEMPERATURES_C[i],TEMPERATURES_R[i],TEMPERATURES_D[i]))
  47.     index = np.arange(len(voltage))
  48.     left_shift = len(VOLTAGES_C[i])
  49.     index = index - left_shift
  50.     VOLTAGES.append(voltage)
  51.     CURRENTS.append(current)
  52.     TEMPERATURES.append(temperature)
  53.     INDEXS.append(index)
  54. # 在1*3的图中画出23个cycle的电压、电流、温度曲线
  55. fig, axs = plt.subplots(1, 3, figsize=(9, 3),dpi=200)
  56. for i in range(len(VOLTAGES)):
  57.     axs[0].plot(INDEXS[i],CURRENTS[i],linewidth=1.5,alpha=0.5,c=cm[i])
  58.     axs[1].plot(INDEXS[i],VOLTAGES[i],linewidth=1.5,alpha=0.5,c=cm[i])
  59.     axs[2].plot(INDEXS[i],TEMPERATURES[i],linewidth=1.5,alpha=0.5,c=cm[i])
  60.     axs[0].set_xlabel('Index')
  61.     axs[0].set_ylabel('Current (A)')
  62.     axs[1].set_xlabel('Index')
  63.     axs[1].set_ylabel('Voltage (V)')
  64.     axs[2].set_xlabel('Index')
  65.     axs[2].set_ylabel('Temperature (C)')
  66. plt.tight_layout()
  67. plt.show()
复制代码

其他曲线的画法与Batch-1一致,不再赘述。

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

魏晓东

金牌会员
这个人很懒什么都没写!
快速回复 返回顶部 返回列表