深度学习 | 基于 LSTM 模型的多电池健康状态对比及预测

news/2025/1/22 2:25:25/

Hi,大家好,我是半亩花海。在电池管理系统(BMS)中,电池的健康状态(State of Health, SOH)是评估电池剩余寿命的重要指标,而准确预测电池的健康状态可以帮助实现电池的高效管理,延长电池的使用寿命并预防电池故障。本项目的目标是使用长短期记忆(LSTM神经网络对多个电池进行健康状态对比及预测,并使用收集到的电池循环数据来训练模型并评估其性能。

目录

一、数据概述

二、数据可视化

1. 绘制容量与循环次数的关系

2. 绘制健康状态与循环次数的关系

3. 多电池的健康状态对比

三、数据预处理

四、LSTM模型构建

五、模型训练

六、模型评估

七、保存预测结果


一、数据概述

数据来自八个电池单元(B05, B07, B18, B33, B34, B46, B47, B48),每个电池包含多个充放电周期的数据。如下所示,数据存储在CSV文件中。经过初步数据处理之后,每个数据文件提取了包含以下字段的关键信息:

  • cycle:循环次数
  • capacity:容量
  • SOH:健康状态(State of Health)

以下是数据的读取和清洗过程。

import os
import pandas as pd# 获取数据集目录
directory_main = os.listdir('D:\Soochow University\Battery Research\ML_Course_SOH\case_one\datasets')
directory_edited = [file for file in directory_main if file != '.ipynb_checkpoints']  # 排除.ipynb_checkpoints目录
print(directory_main)
print(directory_edited)
print("The numbers of datasets:", len(directory_main))
print("The numbers of datasets:", len(directory_edited))
  • os.listdir() 用于列出指定路径下的所有文件,返回一个文件名列表。

# 定义电池编号
num = ['B05', 'B07', 'B18', 'B33', 'B34', 'B46', 'B47', 'B48']
# 循环读取每个电池的数据文件
for i in range(len(directory_edited)):path = os.path.join('D:\Soochow University\Battery Research\ML_Course_SOH\case_one\datasets/', num[i] + '_discharge_soh.csv')csv = pd.read_csv(path)df = pd.DataFrame(csv)vec = df[['cycle', 'capacity', 'SOH']]globals()['data_{}'.format(num[i])] = vecdata = pd.read_csv('D:\Soochow University\Battery Research\ML_Course_SOH\case_one\datasets/B05_discharge_soh.csv')
df = pd.DataFrame(data)
df
  • 通过pandas.read_csv()读取每个电池单元的CSV文件,并提取其包含的循环次数、容量、SOH数据。
  • 使用globals()动态创建每个电池的数据框(data_B05data_B07等),便于后续的处理。

data_B05

以其中一个电池为例,展示其 'cycle', 'capacity', 'SOH' 部分的数据,如上所示。


二、数据可视化

我们通过可视化来分析电池数据的特点。以下图表展示了电池的容量、健康状态(SOH)与循环次数之间的关系,即电池退化曲线、健康状态分析曲线

1. 绘制容量与循环次数的关系

import seaborn as sns
import matplotlib.pyplot as plt# 绘制每个电池的容量随循环次数变化的散点图
for i in range(len(directory_edited)):dff = globals()['data_{}'.format(num[i])]sns.set_style("darkgrid")plt.figure(figsize=(12, 8))plt.scatter(dff['cycle'], dff['capacity'])plt.ylabel('Capacity', fontsize=15)plt.xlabel('cycle', fontsize=15)plt.title('Discharge_' + num[i], fontsize=15)plt.show()
  • 使用seaborn.set_style()设置图表背景样式。
  • 使用matplotlib.pyplot.scatter()绘制每个电池的容量随循环次数的变化。
  • plt.show()显示每张图表。

2. 绘制健康状态与循环次数的关系

# 绘制每个电池的SOH随循环次数变化的散点图
for i in range(len(directory_edited)):dff = globals()['data_{}'.format(num[i])]sns.set_style("darkgrid")plt.figure(figsize=(12, 8))plt.scatter(dff['cycle'], dff['SOH'])plt.ylabel('SoH', fontsize=15)plt.xlabel('cycle', fontsize=15)plt.title('Discharge_' + num[i], fontsize=15)plt.show()
  • 通过同样的方式,我们可以查看电池的健康状态(SOH)与循环次数之间的关系。
  • 每个电池的健康状态随循环次数的变化趋势会有所不同。

3. 多电池的健康状态对比

  • 为了比较不同电池的健康状态,我们将多个电池的SOH变化绘制在同一张图上。
  • 通过plt.legend()添加图例,便于区分不同电池。
# 比较不同电池的SOH变化
sns.set_style("darkgrid")
plt.figure(figsize=(12, 8))
plt.scatter(data_B05['cycle'], data_B05['SOH'], label='B05')
plt.scatter(data_B07['cycle'], data_B07['SOH'], label='B07')
plt.scatter(data_B18['cycle'], data_B18['SOH'], label='B18')
plt.legend(prop={'size': 16})
plt.ylabel('SoH', fontsize=15)
plt.xlabel('Discharge cycle', fontsize=15)
plt.title('SoH of group A', fontsize=15)
plt.show()

    sns.set_style("darkgrid")
    plt.figure(figsize=(12, 8))plt.scatter(data_B33['cycle'], data_B33['SOH'],label='B33')
    plt.scatter(data_B34['cycle'], data_B34['SOH'],label='B34')plt.legend(prop={'size': 16})plt.ylabel('SoH', fontsize = 15)
    plt.xlabel('Discharge cycle', fontsize = 15)
    plt.title('SoH of group B', fontsize = 15)
    plt.show()

    sns.set_style("darkgrid")
    plt.figure(figsize=(12, 8))plt.scatter(data_B46['cycle'], data_B46['SOH'],label='B46')
    plt.scatter(data_B47['cycle'], data_B47['SOH'],label='B47')
    plt.scatter(data_B48['cycle'], data_B48['SOH'],label='B48')plt.legend(prop={'size': 16})plt.ylabel('SoH', fontsize = 15)
    plt.xlabel('Discharge cycle', fontsize = 15)
    plt.title('SoH of group C', fontsize = 15)
    plt.show()

     


    三、数据预处理

    LSTM模型需要以时间序列的形式输入数据,因此我们需要电池健康状态的数据转化为适合LSTM的格式。以下是模型构建之前的数据集创建部分。

    • create_dataset():该函数将原始的时间序列数据切分成多个子序列,每个子序列的长度由look_back决定。每个子序列的目标值是该子序列之后的一个时间步的健康状态(SoH)。
    • 数据集被划分为50%的训练集和50%的测试集。
    import numpy as np# 划分训练集和测试集
    dataset = data_B48["SOH"]
    cycle = data_B48['cycle']dataset = np.array(dataset)
    dataset = dataset.reshape((len(dataset), 1))
    dataset.shape

      train_size = int(len(dataset) * 0.5)
      test_size = len(dataset) - train_size
      train, test = dataset[0:train_size,:], dataset[train_size:len(dataset),:]
      print(len(train), len(test))

      # 创建时间序列数据集
      def create_dataset(dataset, look_back=1):dataX, dataY = [], []for i in range(len(dataset) - look_back):a = dataset[i:(i + look_back), 0]dataX.append(a)dataY.append(dataset[i + look_back, 0])return np.array(dataX), np.array(dataY)look_back = 10
      trainX, trainY = create_dataset(train, look_back)
      testX, testY = create_dataset(test, look_back)

      trainX

      # 重塑数据以适应LSTM输入
      trainX = np.reshape(trainX, (trainX.shape[0], 1, trainX.shape[1]))
      testX = np.reshape(testX, (testX.shape[0], 1, testX.shape[1]))print(trainX.shape)
      print(testX.shape)


      四、LSTM模型构建

      LSTM是一个处理时间序列数据的强大工具。我们将使用LSTM来预测电池的健康状态。以下是LSTM模型定义部分。

      import torch
      import torch.nn as nn
      import torch.optim as optimclass MyLSTMModel(nn.Module):def __init__(self, input_size, hidden_size, output_size):super(MyLSTMModel, self).__init__()self.lstm = nn.LSTM(input_size, hidden_size, batch_first=True)self.fc = nn.Linear(hidden_size, output_size)def forward(self, x):lstm_out, _ = self.lstm(x)output = self.fc(lstm_out[:, -1, :])  # 使用最后一个时间步的输出return output
      
      • LSTM:LSTM层用于处理输入的时间序列数据,input_size为每个时间步的特征数量,hidden_size为LSTM层的隐藏单元数量。
      • Linear:全连接层,用于将LSTM层的输出映射到目标变量(电池健康状态)的预测值。

      五、模型训练

      我们使用PyTorch训练LSTM模型,采用Adam优化器和L1损失函数(Mean Absolute Error,MAE)来优化模型。

      # 定义训练循环
      model = MyLSTMModel(input_size=1, hidden_size=64, output_size=1)
      criterion = nn.L1Loss()  # L1损失函数(MAE)
      optimizer = optim.Adam(model.parameters())# 转换为PyTorch张量
      trainX_tensor = torch.tensor(trainX, dtype=torch.float32)
      trainY_tensor = torch.tensor(trainY, dtype=torch.float32)# 训练模型
      num_epochs = 566  # 训练566个epoch
      history = {'train_loss': [], 'val_loss': []}for epoch in range(num_epochs):model.train()optimizer.zero_grad()# 假设trainX_tensor是一个三维形状张量(batch_size,sequence_length,input_size)output = model(trainX_tensor)# 假设trainY_tensor是PyTorch张量loss = criterion(output.squeeze(), trainY_tensor)loss.backward()optimizer.step()history['train_loss'].append(loss.item())print(f'Epoch [{epoch + 1}/{num_epochs}], Train Loss: {loss.item():.4f}')
      • optimizer.zero_grad():在每个训练周期开始时清除梯度。
      • model.train():将模型设置为训练模式。
      • loss.backward():反向传播计算梯度。
      • optimizer.step():更新模型参数。

      plt.plot(history['train_loss'], label='train')
      plt.xlabel('Epoch')
      plt.ylabel('Loss')
      plt.legend()
      plt.show()


      六、模型评估

      训练完成后,我们使用测试集对模型进行评估,并计算其预测的RMSEMAE

      • model.eval():将模型设置为评估模式,关闭dropout等操作。
      • mean_absolute_errormean_squared_error:计算模型预测的平均绝对误差(MAE)均方根误差(RMSE),用来评估模型性能。
      from sklearn.metrics import mean_absolute_error, mean_squared_error
      import torch
      import math# 假设“model”是你训练的PyTorch模型
      # 假设'testX'、'trainX'、'testY'、'trainY'是您的数据# 将“testX”和“trainX”转换为PyTorch张量
      testX_tensor = torch.tensor(testX, dtype=torch.float32)
      testY_tensor = torch.tensor(testY, dtype=torch.float32)# 将模型设置为评估模式
      model.eval()# 使用PyTorch进行预测
      with torch.no_grad():yhat_test = model(testX_tensor)yhat_test_torch = yhat_test.numpy()# 假设'testY'和'yhat_test_torch'是numpy数组或PyTorch张量
      # 如果'testY'是PyTorch张量,则将其转换为numpy数组
      testY = testY.numpy() if torch.is_tensor(testY) else testY# 计算误差
      rmse = math.sqrt(mean_squared_error(testY, yhat_test_torch))
      mae = mean_absolute_error(testY, yhat_test_torch)print(f'Test RMSE: {rmse:.3f}')
      print(f'Test MAE: {mae:.3f}')
      

        七、保存预测结果

        我们将预测结果保存到Excel文件中,以便后续分析。

        • 使用pandas.DataFrame()创建一个包含真实值和预测值的表格,然后将其保存为Excel文件。
        import pandas as pddef save_to_excel(origin_y_true, origin_y_pred):data_dict = {'真实值': origin_y_true, '预测值': origin_y_pred}df = pd.DataFrame(data_dict)output_excel_path = "output_predictions.xlsx"with pd.ExcelWriter(output_excel_path) as writer:df.to_excel(writer)save_to_excel(testY, yhat_test_torch)
        

          结论:

          1. 本项目基于LSTM模型成功地对电池的健康状态进行了预测,验证了LSTM在时间序列预测中的有效性。

          2. 通过对不同电池单元的SOH进行比较,我们发现不同电池有不同的退化模式。

          3. 在未来的工作中,可以通过加入更多的特征和优化模型结构进一步提高预测准确性。


          http://www.ppmy.cn/news/1565107.html

          相关文章

          【20】Word:小许-质量管理-论文❗

          目录 题目​ NO1.2.3.4.5 NO6.7 NO8 NO9 NO10.11 题目 NO1.2.3.4.5 另存为“Word.docx”文件在考生文件夹下,F12Fn是另存为的作用布局→页面设置对话框→纸张:大小A4→页边距:上下左右不连续ctrl选择除表格外的所有内容→开始→字体对…

          Ubuntu 22.04 TLS 忘记root密码,重启修改的解决办法

          1.想办法进入这个界面,我这里是BIOS引导的是按Esc按一下就行,UEFI的貌似是按Shift不得而知,没操作过。下移到Advanced options for Ubuntu,按enter 2.根据使用的内核版本,选择带「recovery mode」字样的内核版本&#…

          【C++指南】类和对象(九):内部类

          💓 博客主页:倔强的石头的CSDN主页 📝Gitee主页:倔强的石头的gitee主页 ⏩ 文章专栏:《C指南》 期待您的关注 引言 在 C 编程中,内部类(也称为嵌套类)是一个定义在另一个类作用域内…

          【mybatis】基本操作:详解Spring通过注解和XML的方式来操作mybatis

          mybatis 的常用配置 配置数据库连接 #驱动类名称 spring.datasource.driver-class-namecom.mysql.cj.jdbc.Driver #数据库连接的url spring.datasource.urljdbc:mysql://127.0.0.1:3306/mybatis_test? characterEncodingutf8&useSSLfalse #连接数据库的⽤⼾名 spring.dat…

          2024最新版本idea SpringBoot创建web项目(详细介绍如何搭建和配置spring boot web,以及写出一个简单的前后端交互界面)

          1.创建springboot项目: 新建项目 -> Spring Boot ->自定义写你的项目名称、项目位置等、语言java、类型选择maven,最后选择JDK版本,这里推荐17以上,对应Java也一样,最后选jar包 -> next 首先选择springboot版本&#xff…

          蓝桥杯 单词重排

          问题描述 解题思路 这个问题可以通过计算排列数来解决。由于字符串 "LANQIAO" 由7个不同的字母组成,我们可以使用排列公式 P(n,n)n! 来计算,其中 n 是字母的数量。但是,由于字符串中存在重复的字母,我们需要对重复的字…

          人工智能核心知识:AI Agent的四种关键设计模式

          导读:AI Agent是指能够在特定环境中自主执行任务的人工智能系统,不仅接收任务,还自主制定和执行工作计划,并在过程中不断自我评估和调整,类似于人类在创造性任务中的思考和修正过程。AI Agent的四种关键设计模式是实现…

          C 语言雏启:擘画代码乾坤,谛观编程奥宇之初瞰

          大家好啊,我是小象٩(๑ω๑)۶ 我的博客:Xiao Xiangζั͡ޓއއ 很高兴见到大家,希望能够和大家一起交流学习,共同进步。* 这一课主要是让大家初步了解C语言,了解我们的开发环境,main函数,库…