Bohrium
robot
新建

空间站广场

论文
Notebooks
比赛
课程
Apps
镜像市场
实验室
Uni-Lab
我的主页
我的Notebooks
我的知识库
我的足迹

我的工作空间

任务
节点
镜像
文件
数据集
项目
数据库
公开
基于简单电化学特征的全频段EIS预测
报告
报告
微信用户fCSA
微信用户7sxQ
AllanKay
WeChat Useracd0
微信用户BZOc
微信用户DiH0
更新于 2024-12-27
推荐镜像 :Basic Image:ubuntu:22.04-py3.10-cuda12.1
推荐机型 :c32_m64_cpu
4
摘要
1 背景介绍
1.1 电化学阻抗谱(EIS)介绍
1.2 EIS原理
1.3 机器学习预测EIS的意义
1.4 机器学习预测EIS预测的方法
1.4.1 基于特征频率预测EIS
1.4.2 基于短脉冲响应预测EIS
1.4.3 基于充电曲线预测EIS
2 模型讨论
CNN模型原理
ANN模型原理
LSTM模型
Transformer模型原理
3 基于特征频率的EIS图谱预测
3.1 CNN模型实现四个特征频率下的阻抗预测全频段EIS
3.1.1 数据加载模块
3.1.2 数据预处理模块
3.1.3 模型定义模块
3.1.4 训练与验证模块
3.1.5 推理与可视化模块
3.1.6 主函数入口
结果输出与分析
3.2 引入ResNet的双参数预测EIS的CNN优化模型构建
3.2.1 模块 1:特征提取
3.2.2 模块 2:数据归一化
3.2.3 模块 3:数据加载与处理
3.2.4 模块 4:训练与验证
3.2.5 模块 5:主函数
结果输出与分析
3.3 改进CNN模型的整体分析与优势
3.3.1 数据加载和处理的优化
3.3.2 模型架构的增强
3.3.3 训练和验证的改进
3.3.4. 可视化的增强
3.3.5 错误处理与调试
3.3.6 平均R²和RMSE的计算与展示
3.3.7 训练轮次的调整
改进总结
4 基于短脉冲响应的EIS图谱预测
4.1 经典ANN模型测试
4.2 实验结果
5 基于充电曲线的EIS图谱预测
5.1 数据处理
5.2 模型的构建、训练与优化
5.2.1 基于LSTM的Seq2Seq模型
5.2.2 基于LSTM的Seq2Seq模型的优化
5.2.2.1 超参数手动调优
5.2.2.2 引入脉冲电流特征以增强模型预测能力
5.2.2.3 采用粒子群优化算法寻得的最优超参数
5.3 实验结果分析
5.3.1 基于LSTM的Seq2Seq模型的复现
5.3.2 超参数手动寻优过程
5.3.3 优化后的基于LSTM的Seq2Seq模型
5.3.4 不同压力范围内的模型评估
5.3.5 Transformer模型
5.3.5.1 Transformer模型的构建
5.3.5.2 典型的报错与Debug
5.3.5.3 训练过程及分析
5.3.5.4 预测结果展示与分析
6 总结
7 参考文献
8 组内分工

摘要

电化学阻抗谱(EIS)是评估锂离子电池健康状态与动态行为的重要工具。然而,传统EIS测量方法受限于设备成本高、操作复杂和实验耗时长等问题。为此,本研究利用了基于特征频率、脉冲响应、充电曲线这三种电化学特征,通过机器学习对EIS进行来有效地预测。我们分别利用卷积神经网络(CNN)、人工神经网络(ANN)、基于长短时记忆网络(LSTM)的端对端模型(Seq2Seq)模型和Transformer模型,实现了对阻抗谱的高效预测。本研究展示了机器学习在EIS预测中的应用潜力,不仅降低了实验成本和复杂性,还为电池健康监测、性能评估与老化行为分析提供了一种有效的解决方案。这些方法具备广泛的适用性,为锂离子电池领域的发展提供了新的研究方向。

Abstract

Electrochemical Impedance Spectroscopy (EIS) is a critical tool for evaluating the health status and dynamic behavior of lithium-ion batteries. However, traditional EIS measurement methods are constrained by high equipment costs, operational complexity, and time-consuming experiments. To address these limitations, this study employs three electrochemical features—characteristic frequency, short-term pulses, and charging curves—to effectively predict EIS through machine learning. We employed Convolutional Neural Networks (CNN), Artificial Neural Networks (ANN), Sequence to Sequence (Seq2Seq) architectures based on Long Short-Term Memory (LSTM) networks, and Transformer models to enable precise and efficient prediction of impedance spectra. The potential of machine learning in EIS prediction is demonstrated through its ability to reduce experimental costs and complexity, while offering an effective solution for battery health monitoring, performance evaluation, and aging behavior analysis. These methods exhibit broad applicability and offer a new research approach for the characterization of lithium-ion batteries.

代码
文本

1 背景介绍

1.1 电化学阻抗谱(EIS)介绍

锂离子电池(LIB)因其高能量密度、长使用寿命和环境友好性等显著优势,在电动汽车和便携式电子设备中得到了广泛应用1。然而,随着锂离子电池的老化,其在存储和使用过程中的安全性面临巨大挑战,这促使了电池预测技术的发展和应用2。EIS作为一种非破坏性方法,被广泛用于表征电池健康状态、电池内部阻抗以及锂离子(Li-ions)的动态扩散过程3。通过揭示锂离子电池内部的动态电极动力学过程,EIS对于监测电池的状态、老化和安全性至关重要,以确保其在各种应用中的可靠性和性能。同时该技术能够提供电化学系统的电阻、电容、电感等参数,这些参数对于理解电化学过程至关重要。图1

其原理可以直观地从上图获得:通过波形发生器产生小幅正弦电势信号,再通过恒电位仪施加到电化学系统上。将输出的电势/电流信号经过转换,最后利用锁相放大器、频谱分析仪输出阻抗模量、相位角与频率关系等(正弦波的频率不断变化)。我们可以将电化学系统看作是一个等效电路。该电路由电阻(R)、电感(L)、和电容(C)等通过串并联的方式组成。利用EIS的结果可以分析出各个等效电路原件的阻抗值等大小,并分析其含义4,有助于测试者对所测的电化学系统做出判断(电化学系统的结构和电极过程的性质),或进行结果的得出或电化学系统的改进。

代码
文本

1.2 EIS原理

EIS是一种分析技术,它通过向电化学系统施加小振幅的交流信号并测量其响应来研究系统的频率依赖性。EIS能够提供关于电极过程、电荷传递反应和扩散过程的详细信息。在EIS测试中,系统的阻抗被表示为一个复数,其中实部代表电阻,虚部代表电抗,这两者共同描述了系统对交流信号的响应特性。 EIS的核心在于测量系统在不同频率下的阻抗,以构建阻抗谱5。这个谱通常在奈奎斯特图(Nyquist图)中表示,其中Nyquist图显示阻抗的实部和虚部,如下图所示:

alt

代码
文本

阻抗谱可以通过等效电路模型来解释,这些模型由电阻、电容和电感等基本元件组成,它们以不同的方式连接以模拟电化学过程。例如,一个简单的RC电路可以表示为 其中R是电阻,C是电容,ω是角频率。更复杂的系统可能需要多个这样的元件串联或并联来准确描述。

EIS测试的实施涉及施加一个已知频率和振幅的交流信号到电池,并测量电池的电压或电流响应。然后,通过傅里叶变换将这些响应从时间域转换到频率域,从而得到阻抗谱。通过分析这些数据,研究人员可以提取出关于电池内部状态的重要信息,并预测其性能和寿命。

代码
文本

1.3 机器学习预测EIS的意义

传统EIS测量需要覆盖宽频率范围(如从毫赫兹到千赫兹),对实验设备性能提出了较高要求。例如,便携式单通道电化学工作站(如Vertex.C.EIS)的价格可高达约8万元,这在一定程度上增加了实验室研究的经济负担,同时限制了EIS在大规模工业应用中的可行性。 alt

传统EIS测量的过程不仅复杂,还需要较长的采样时间,特别是在低频区域,对设备的精度和稳定性有更高要求。这些技术和经济上的限制使得EIS在广泛应用中的实际操作难度较高。因此,发展一种更加高效、低成本的替代方法成为当前研究的重点方向。 基于机器学习的EIS预测技术为这一问题提供了创新性的解决方案。通过数据驱动的建模方法,可以利用少量数据,或使用一般频率设备数据,来预测宽频率范围内的完整阻抗谱,从而减少对高性能设备的依赖。这种方法在以下几个方面展现出重要意义:

1. 简化频率采样

机器学习技术可以通过采集少量关键频率的阻抗数据,或使用一般频率(如1 Hz)的脉冲响应数据,来准确预测完整的EIS图谱。这显著降低了测量时间和设备需求,提高了测试效率。

2. 降低实验成本

采用机器学习模型进行EIS预测,不再需要覆盖全频率范围的高性能设备,能够有效减少实验成本,尤其适合资源有限的实验室和工业应用场景。

3. 实现数据智能化处理

机器学习模型不仅能够预测阻抗谱,还能从数据中提取电化学体系的关键动力学信息,例如识别界面特性和评估电池健康状态,为进一步研究提供数据支持。

4. 具有普适性与适应性

机器学习预测方法适用于不同类型的电化学体系(如锂电池、燃料电池等),并且能够根据不同的实验条件和应用需求灵活调整,提高了其实际应用的广泛性和可操作性。

代码
文本

1.4 机器学习预测EIS预测的方法

1.4.1 基于特征频率预测EIS

特征频率预测方法通过测量关键特征频率处的阻抗数据来推导电池的关键动力学信息。

图一

研究表明,在荷电状态(SOC)恒定的条件下,电池的循环寿命和健康状态(SOH)对EIS的高频和中频区域具有显著影响,这些区域主要反映了电池内部的接触极化和固态电解质界面(SEI)生长过程。(上图的参考文献) 相比之下,其他频率区域对电池整体状态的影响较小,这些区域通常与电荷转移和扩散过程相关。 在电池老化过程中,特征频率对应的时间常数没有明显变化,但特征频率处的峰、谷和峰面积有所不同,这使得基于电池老化过程中特征频率的预测方法具有可行性。 因此,仅依赖关键特征频率处的阻抗信息,即可有效预测EIS曲线和分布弛豫时间(DRT)曲线。

Li课题组在2023年6提出了一种使用卷积神经网络获取阻抗谱的新方法,该方法使用在几个特征频率下测得的阻抗作为输入。通过确定特征频率,可以基于接触极化和SEI生长过程中的时间常数来预测EIS。

alt

1.4.2 基于短脉冲响应预测EIS

短脉冲响应方法受混合脉冲功率特性测试(Hybrid Pulse Power Characterization, HPPC)的启发,如下图所示: alt HPPC方法通过施加短时电流脉冲并记录电压响应数据,捕捉电池内部的动力学行为和阻抗特性。与此类似,短脉冲响应也能反映电池的电化学特性。电池在不同状态下的短脉冲响应会表现出不同的特征,这与EIS反映的电化学特性相似。 alt 通过分析这些短脉冲响应数据,可以间接获得电池的电化学行为,进而反映EIS图谱中的关键特性。因此,短脉冲响应和EIS之间可以通过物理和数学建模建立有效的关联,并通过机器学习技术实现对完整EIS图谱的预测。

alt

1.4.3 基于充电曲线预测EIS

充电曲线和 EIS 曲线广泛用于电池健康诊断和退化量化。Sun等人在7提出锂离子电池的充电曲线与电池的内部阻抗和动态锂离子扩散有关。充电曲线的变化可以反映电池老化状态,如界面阻抗的增加和活性材料的损失。这些变化与EIS中观察到的等效电路模型(ECM)参数变化相关联,因此可以通过充电曲线来预测EIS。 Xiong等人年提出了一种基于深度学习的方法8,使用卷积神经网络(CNN)来预测锂离子电池在充满电和放空电状态下的EIS。该方法仅需要恒流充电过程中收集的电压和电流数据作为输入,通过训练一个包含多个卷积层、池化层和全连接层的CNN模型,实现了对电池阻抗谱的准确预测。

alt

代码
文本

2 模型讨论

CNN模型原理

卷积神经网络(CNN)是一种深度学习模型,它在图像和视觉识别任务中表现出色。CNN通过模拟人类视觉系统的工作原理,能够识别和理解图像内容。CNN的关键特性包括局部连接、权重共享和池化操作。

卷积层(Convolutional Layer)

卷积层是CNN中的基本构建块,它通过卷积操作提取输入数据的局部特征。卷积操作可以用以下公式表示:

其中,W是卷积核,X是输入数据,b是偏置项,Z是输出特征图。

激活函数(Activation Function)

激活函数引入非线性因素,使得CNN能够学习和执行更复杂的任务。常用的激活函数是ReLU(Rectified Linear Unit):

池化层(Pooling Layer)

池化层用于降低特征图的空间维度,减少计算量,同时保持重要的特征信息。最大池化是一个常用的池化操作:

其中,P是池化后的输出,Z是池化前的特征图。

全连接层(Fully Connected Layer)

在CNN的最后,全连接层将前面层提取的特征映射到输出空间,通常用于分类任务。全连接层的输出可以表示为: 其中,W是权重矩阵,X是输入特征向量,b是偏置项,Y是输出向量。

alt

上图展示了一个典型的CNN架构,包括卷积层、激活函数、池化层和全连接层。

代码
文本

ANN模型原理

人工神经网络 (Artificial Neural Network, ANN) 是一种受生物神经网络启发而设计的计算模型,用于处理复杂的模式识别和非线性问题。ANN由多个互联的节点(称为“神经元”)组成,这些神经元按照层级组织,包括以下部分:

输入层 (Input Layer)

接收原始数据输入,每个节点对应一个输入特征。

隐藏层 (Hidden Layers)

通过权重和激活函数对输入数据进行非线性变换。隐藏层的数量和神经元的配置决定了模型的复杂性和表达能力。

输出层 (Output Layer)

生成模型的最终输出,通常对应于分类概率、回归值等。

ANN的基本工作原理是模拟大脑神经元的信号处理方式:

  1. 加权求和 (Weighted Sum):每个神经元接收前一层神经元的输出,乘以权重,并加上偏置值。

  2. 激活函数 (Activation Function):通过激活函数引入非线性,如 ReLU、Sigmoid、Tanh 等,使网络能够学习复杂的映射关系。

  3. 前向传播 (Forward Propagation):输入数据逐层传递,直到输出层生成结果。

  4. 误差计算 (Error Calculation):比较预测输出和真实标签,计算误差(如均方误差或交叉熵)。

  5. 反向传播 (Backpropagation):通过链式法则将误差从输出层传播回输入层,并调整权重和偏置值,目标是最小化误差函数。

虽然ANN是深度学习的基础,但它的表现受限于浅层结构,无法有效处理高度复杂的任务。因此,深度神经网络(DNN)和卷积神经网络(CNN)在此基础上得以发展,显著提升了性能。ANN是一个灵活而强大的工具,但其效果依赖于设计经验和计算资源。

代码
文本

LSTM模型

长短期记忆网络(Long Short-Term Memory, LSTM)是一种特殊的循环神经网络(RNN),设计用来解决标准RNN在处理长序列数据时的梯度消失或梯度爆炸问题。LSTM通过引入门控机制(包括输入门、遗忘门和输出门)来控制信息的流动,从而能够学习到长期依赖关系。 LSTM因其在处理时间序列数据方面的优势而被广泛应用于语言模型、语音识别、时间序列预测等领域。

基于LSTM的Seq2Seq

Seq2Seq模型是一种特殊的循环神经网络(RNN),它由两个主要部分组成:编码器(Encoder)和解码器(Decoder)。

alt

Seq2Seq模型能够捕捉这种时间上的依赖关系,因为它在编码器中处理输入序列,在解码器中生成输出序列。此外,电压与EIS阻抗谱之间的关系可能是非线性的。Seq2Seq模型,特别是当它使用LSTM时,能够学习复杂的非线性关系。

LSTM的核心原理包括三个门控结构:遗忘门决定哪些信息应该从细胞状态中遗忘,输入门和输出门则分别控制新信息的存储和旧信息的读取。细胞状态作为信息的载体,允许LSTM在序列的不同时间点之间传递信息,而隐藏状态则作为网络的输出,携带前一时间步的信息并传递到下一个时间步。这些门控操作都是通过带有参数的激活函数来实现的,参数在训练过程中被学习优化。

代码
文本

LSTM的结构中,代表记忆细胞,是隐藏状态,图中的是遗忘门,Sigmoid函数是得到一个0-1之间的值,是更新门,是输出门。 alt

遗忘门(Forget Gate):

更新门(Input Gate):

细胞状态更新(Cell State):

细胞状态更新(Cell State Update):

输出门(Output Gate):

隐藏状态更新(Hidden State Update):

alt

LSTM模型的输出计算:最终计算得到最终的 ,这个 有两个流向,一个是继续向前传播(图中黑色的),一个就是直接输出(图中紫色的):

上图展示了LSTM网络的结构和这些变量之间的关系。其中 是输出层的权重矩阵,是当前时间步的隐藏状态,是输出层的偏置项。

代码
文本

Transformer模型原理

Transformer模型由编码器和解码器组成,每个部分都包含多个层,每层都包括自注意力和前馈神经网络两个子层。其核心原理基于自注意力机制,这种机制允许模型在处理序列的任意位置时都能够考虑到序列中的所有其他位置,从而有效地捕捉序列内部的长距离依赖关系。Transformer通过计算序列中每个元素对其他元素的注意力权重来捕捉序列内部的依赖关系。这种机制不依赖于序列中元素的绝对位置,使得模型能够更灵活地处理长距离依赖。 其中,Q、K、V分别代表查询(queries)、键(keys)和值(values),是键向量的维度。

alt

这张图展示了一个基于Transformer架构的Seq2Seq模型,通常用于机器翻译、文本摘要或其他自然语言处理任务。Transformer模型由编码器(Encoder)和解码器(Decoder)两部分组成,它们通过自注意力(Self-Attention)机制来处理输入数据。相比于基于LSTM的Seq2Seq模型,Transformer模型提供了一种全新的序列处理方法,它在处理长序列和复杂依赖关系方面优于传统的LSTM模型。

如果将该技术应用于预测EIS,Transformer模型可以利用其强大的序列处理能力来分析电池充放电过程中的动态变化。通过学习充放电曲线与阻抗谱之间的关系,Transformer模型能够预测不同状态下的阻抗谱,这对于电池状态监测和健康评估非常有用。

代码
文本

3 基于特征频率的EIS图谱预测

3.1 CNN模型实现四个特征频率下的阻抗预测全频段EIS

本部分基于已有公开模型电化学阻抗谱EIS预测 —— 使用四个特征频率下的阻抗预测全频段EIS做出实验复现。 以下是对代码进行模块化的重构,同时对每个模块的功能进行了详细介绍和解析。

模块化后的代码结构 代码被划分为以下六个模块:

  1. 数据加载模块: 读取和处理原始数据。

  2. 数据预处理模块: 生成训练和验证数据集。

  3. 模型定义模块: 构建卷积神经网络。

  4. 训练与验证模块: 完成模型的训练与验证。

  5. 推理与可视化模块: 测试模型性能并生成可视化结果。

  6. 主函数入口: 协调各模块运行。

代码
文本

3.1.1 数据加载模块

功能:从指定目录中加载 CSV 文件,将数据按周期分组并提取 EIS 数据。

代码
文本
[11]
import os
import pandas as pd
import torch

def load_data(data_path, char_frequencies):
"""
加载 EIS 数据,并按周期分组。

Parameters:
- data_path (str): 数据文件路径
- char_frequencies (list): 特征频率

Returns:
- EIS_data (list): 包含样本名、频率、Re(Z)、-Im(Z) 的数据
"""
EIS_data = []
for file in os.listdir(data_path):
if file.endswith('.csv'):
sample_name = file.split('_')[-1].split('.')[0]
data = pd.read_csv(os.path.join(data_path, file))
cycle = sorted(set(data['cycle number']))
data_cycle = [[f'{sample_name}-cyc{i}', data[data['cycle number'] == i]] for i in cycle]
data_eis = [(i[0],
torch.tensor(i[1]['freq/Hz'].to_numpy()),
torch.tensor(i[1]['Re(Z)/Ohm'].to_numpy()),
torch.tensor(i[1]['-Im(Z)/Ohm'].to_numpy())) for i in data_cycle]
EIS_data += data_eis
return EIS_data

代码
文本

3.1.2 数据预处理模块

功能:根据指定特征频率生成输入和输出数据,划分训练集与验证集。

代码
文本
[12]
import random
from torch.utils.data import DataLoader, TensorDataset

def preprocess_data(EIS_data, char_frequencies, split_ratio=0.2, seed=414):
"""
数据预处理与划分。

Parameters:
- EIS_data (list): 原始 EIS 数据
- char_frequencies (list): 特征频率
- split_ratio (float): 验证集比例
- seed (int): 随机种子

Returns:
- train_data, valid_data: 划分好的训练集和验证集
"""
random.seed(seed)
random.shuffle(EIS_data)
split_idx = int(len(EIS_data) * split_ratio)
valid_data, train_data = EIS_data[:split_idx], EIS_data[split_idx:]

def dataset_gen(dataset):
data_name, data_input, data_output = [], [], []
for name, freq, re, im in dataset:
data_name.append(name)
char_r = [re[torch.abs(freq - f).argmin()] for f in char_frequencies]
char_i = [im[torch.abs(freq - f).argmin()] for f in char_frequencies]
data_input.append(torch.stack([torch.tensor(char_r), torch.tensor(char_i)], dim=-1))
data_output.append(torch.stack([re, im], dim=-1))
return data_name, data_input, data_output

train_name, train_src, train_tgt = dataset_gen(train_data)
valid_name, valid_src, valid_tgt = dataset_gen(valid_data)

return (train_name, train_src, train_tgt), (valid_name, valid_src, valid_tgt)

代码
文本

3.1.3 模型定义模块

功能:构建一个卷积神经网络,用于处理复数数据。

代码
文本
[13]
import torch.nn as nn

class EISConvNet(nn.Module):
def __init__(self):
super(EISConvNet, self).__init__()
self.conv1 = nn.Conv1d(2, 16, kernel_size=2, stride=1, padding=1)
self.pool1 = nn.MaxPool1d(2)
self.conv2 = nn.Conv1d(16, 32, kernel_size=2, stride=1, padding=1)
self.pool2 = nn.MaxPool1d(2)
self.conv3 = nn.Conv1d(32, 16, kernel_size=2, stride=1, padding=1)
self.global_pool = nn.AdaptiveMaxPool1d(1)
self.fc1 = nn.Linear(16, 120)
self.dropout = nn.Dropout(0.1)
self.fc2 = nn.Linear(120, 120)
self.relu = nn.ReLU()

def forward(self, x):
x = x.permute(0, 2, 1) # [batch, 4, 2] -> [batch, 2, 4]
x = self.relu(self.conv1(x))
x = self.pool1(x)
x = self.relu(self.conv2(x))
x = self.pool2(x)
x = self.relu(self.conv3(x))
x = self.global_pool(x)
x = x.view(x.size(0), -1)
x = self.relu(self.fc1(x))
x = self.dropout(x)
x = self.fc2(x)
return x

代码
文本

3.1.4 训练与验证模块

功能:进行模型训练和验证,记录损失。

代码
文本
[14]
import torch.optim as optim
from torch.utils.data import DataLoader, TensorDataset

def train_model(model, train_loader, valid_loader, device, max_epoch=1000, lr=0.001, batch_size=32):
"""
模型训练与验证。

Parameters:
- model: 定义好的模型
- train_loader: 训练数据加载器
- valid_loader: 验证数据加载器
- device: 运行设备
"""
criterion = nn.MSELoss()
optimizer = optim.Adam(model.parameters(), lr=lr)
scheduler = optim.lr_scheduler.ReduceLROnPlateau(optimizer, mode='min', factor=0.4, patience=30, verbose=True)

train_loss_list, valid_loss_list = [], []

for epoch in range(max_epoch):
# 训练模式
model.train()
train_loss = 0.0
for batch_input, batch_output in train_loader:
batch_input, batch_output = batch_input.to(device), batch_output.to(device)
optimizer.zero_grad()
output = model(batch_input)
loss = criterion(output, batch_output)
loss.backward()
optimizer.step()
train_loss += loss.item() * batch_input.size(0)
train_loss /= len(train_loader.dataset)
train_loss_list.append(train_loss)

# 验证模式
model.eval()
valid_loss = 0.0
with torch.no_grad():
for batch_input, batch_output in valid_loader:
batch_input, batch_output = batch_input.to(device), batch_output.to(device)
output = model(batch_input)
loss = criterion(output, batch_output)
valid_loss += loss.item() * batch_input.size(0)
valid_loss /= len(valid_loader.dataset)
valid_loss_list.append(valid_loss)

scheduler.step(valid_loss)

if (epoch + 1) % 50 == 0:
print(f"Epoch [{epoch+1}/{max_epoch}], Train Loss: {train_loss:.6f}, Valid Loss: {valid_loss:.6f}")

return model

代码
文本

3.1.5 推理与可视化模块

功能:对测试数据进行推理并可视化结果。

代码
文本
[15]
import matplotlib.pyplot as plt
import numpy as np

def inference(model, data_loader, device):
model.eval()
predictions = []
with torch.no_grad():
for batch_input, _ in data_loader:
batch_input = batch_input.to(device)
predictions.append(model(batch_input).cpu().numpy())
return np.concatenate(predictions, axis=0)

def plot_predictions(true_values, predictions, valid_names, num_samples_to_plot=4):
plt.figure(figsize=(10, 12))
for i in range(num_samples_to_plot):
plt.subplot(num_samples_to_plot, 2, i + 1)
plt.plot(true_values[i][:60], true_values[i][60:], 'o', label='True EIS', markersize=4)
plt.plot(predictions[i][:60], predictions[i][60:], 'o', label='Predicted EIS', markersize=4)
plt.legend()
plt.xlabel('Re(Ω)')
plt.ylabel('Im(Ω)')
plt.title(f'{valid_names[i]} - EIS')
plt.tight_layout()
plt.show()

代码
文本

3.1.6 主函数入口

功能:协调运行各模块。

代码
文本
[ ]
if __name__ == "__main__":
# 数据路径与特征频率
data_path = '/personal/EIS review/EIS review11.27/public_data_camb/'
CHAR_F = [115.78, 35.93, 7.76, 1.42]

# 加载数据
EIS_data = load_data(data_path, CHAR_F)

# 预处理数据
(train_name, train_src, train_tgt), (valid_name, valid_src, valid_tgt) = preprocess_data(EIS_data, CHAR_F)

# 转为 DataLoader
train_dataset = TensorDataset(torch.stack(train_src), torch.stack(train_tgt))
valid_dataset = TensorDataset(torch.stack(valid_src), torch.stack(valid_tgt))
train_loader = DataLoader(train_dataset, batch_size=32, shuffle=True, num_workers=4)
valid_loader = DataLoader(valid_dataset, batch_size=32, num_workers=4)

# 定义模型
device = "cuda:0" if torch.cuda.is_available() else "cpu"
model = EISConvNet().to(device)

# 训练模型
model = train_model(model, train_loader, valid_loader, device)

# 推理与可视化
predictions = inference(model, valid_loader, device)
true_values = [tgt.numpy() for tgt in valid_tgt]
plot_predictions(true_values, predictions, valid_name)
代码
文本

结果输出与分析

代码
文本

CNN模型的结果均在6~7mΩ左右,这个结果略好于参考文章中公开数据集的最优结果。考虑到参考文章是在第一个数据集上预训练后transfer learning到公开数据集,这样的结果也还算合理。值得一提的是RMSE的值,由于EIS虚部在高频段可能非常接近与0,所以百分比误差在这里会出现爆炸的情况,这也是为什么用百分比误差衡量EIS预测不太合理的地方。

代码
文本

alt

代码
文本

选择几个验证集中的数据绘图展示。可以看到,拟合的精度还是很好的。

代码
文本

alt

代码
文本

3.2 引入ResNet的双参数预测EIS的CNN优化模型构建

本项目旨在优化和改进现有的EIS预测模型,灵感来源于《Journal of Power Sources》中的研究以及公开的Data-driven EIS Prediction模型。改进后的代码在模块化、鲁棒性以及模型设计和评估指标的丰富性方面都有显著提升。整个流程被设计为以下五个核心模块:

  1. 特征提取模块: 此模块逻辑独立,专注于从选定的频率点提取关键特征。采用argmin方法精确匹配离散频率点,确保特征提取的准确性。

  2. 数据标准化模块: 同样逻辑独立,支持对数据进行归一化处理,以适应不同的数据范围。模块提供min_val和max_val参数,允许用户对数据执行一致性归一化,这在处理跨批次数据时尤其有用。

  3. 数据加载与处理模块: 该模块整合了特征提取和标准化步骤,通过调用extract_features和normalize_data函数实现。它确保在normalize=True的情况下,输入数据已经过标准化处理,为后续的模型训练和评估打下坚实基础。

  4. 训练与验证模块: 分别定义了训练和验证过程,支持批量训练和模型评估,确保模型的泛化能力和在未见数据上的表现。

  5. 主函数模块: 作为流程的入口,使用调整后的数据加载模块,简化了主函数的逻辑结构。提供了一个清晰的工作流程,包括数据加载、数据分割、模型训练以及结果的可视化,使得整个预测过程直观且易于管理。

通过这些模块的协同工作,本项目不仅提升了EIS预测的准确性和效率,还增强了模型对不同电池状态和类型适应性,为电池管理系统提供了一个强大、灵活且用户友好的工具。

代码
文本

3.2.1 模块 1:特征提取

提取指定频率点的特征,包括阻抗的实部 (Re) 和虚部 (Im)。 从原始数据中精确定位接近目标频率点的数据,返回一个统一格式的特征张量

逻辑拆解:

  1. 张量化: 将频率和阻抗数据从 Pandas 转换为 PyTorch 张量,方便后续的高效操作。

  2. 频率点近似匹配: 使用 torch.abs(freq - f).argmin() 找到离目标频率最近的索引。

  3. 堆叠特征: 将 Re 和 Im 的特征值堆叠为 [2, len(freqs)] 格式,支持后续输入到模型。

代码
文本
[ ]
import os
import pandas as pd
import torch
import torch.nn as nn
import torch.optim as optim
from torch.utils.data import DataLoader, TensorDataset
import matplotlib.pyplot as plt
import seaborn as sns
from sklearn.metrics import mean_squared_error, r2_score
import random

def extract_features(data, char_freqs):
"""
提取指定频率点的特征。
Parameters:
- data: 每个样本的数据(DataFrame)。
- char_freqs: 指定的频率点列表。

Returns:
- 特定频率点的特征,包含 Re(Z) 和 Im(Z) 两部分。
"""
# 将频率和阻抗数据转换为 PyTorch 的张量
freq = torch.tensor(data['freq/Hz'].to_numpy(), dtype=torch.float32)
re = torch.tensor(data['Re(Z)/Ohm'].to_numpy(), dtype=torch.float32)
im = torch.tensor(data['-Im(Z)/Ohm'].to_numpy(), dtype=torch.float32)

# 提取每个指定频率点的 Re(Z) 和 Im(Z) 数据
char_r = [re[torch.abs(freq - f).argmin()] for f in char_freqs]
char_i = [im[torch.abs(freq - f).argmin()] for f in char_freqs]

# 将实部和虚部堆叠成一个张量,返回格式 [2, len(freqs)]
char_features = torch.stack([torch.tensor(char_r), torch.tensor(char_i)], dim=0)
return char_features

代码
文本

3.2.2 模块 2:数据归一化

对输入数据进行归一化,将其压缩到 [0, 1] 范围。 支持用户指定的最小值和最大值,也可自动计算。

逻辑拆解:

  1. 自动计算最小值和最大值: 如果未提供 min_val 和 max_val,从数据中计算。

  2. 计算范围: 避免除以零的情况,通过设置一个很小的数值 1e-8。

  3. 归一化: 将数据调整为 [0, 1],公式为 (data - min_val) / range_val。

代码
文本
[ ]
def normalize_data(data, min_val=None, max_val=None):
"""
对输入数据进行归一化处理。

Parameters:
- data: 输入的张量(Tensor)。
- min_val: 最小值,用于归一化。如果为 None,则从数据中计算。
- max_val: 最大值,用于归一化。如果为 None,则从数据中计算。

Returns:
- 归一化后的数据。
"""
# 如果未指定 min_val 和 max_val,则从数据中计算
if min_val is None:
min_val = torch.min(data, dim=1, keepdim=True).values
if max_val is None:
max_val = torch.max(data, dim=1, keepdim=True).values
# 计算范围,避免除以零的情况
range_val = max_val - min_val
range_val[range_val == 0] = 1e-8

# 归一化公式
return (data - min_val) / range_val, min_val, max_val

代码
文本

3.2.3 模块 3:数据加载与处理

从目录中加载原始数据。调用 extract_features 提取指定频率点的特征。

根据需求调用 normalize_data 对特征进行归一化处理。

逻辑拆解:

  1. 遍历文件: 检查目录下所有 .csv 文件并加载。

  2. 按周期提取特征: 对每个 cycle 分别调用 extract_features。

  3. 可选归一化: 如果 normalize=True,调用 normalize_data 进行归一化。

代码
文本
[ ]
def load_and_process_data(data_path, char_freqs, normalize=True):
"""
从目录中加载数据,提取特征并进行归一化处理。

Parameters:
- data_path: 数据目录路径。
- char_freqs: 指定的频率点列表。
- normalize: 是否对特征进行归一化。

Returns:
- EIS_data: 包含样本名称和特征的列表。
"""
EIS_data = []
for file in os.listdir(data_path):
if file.endswith('.csv'):
file_path = os.path.join(data_path, file)
sample_name = file.split('_')[-1].split('.')[0]
data = pd.read_csv(file_path)
cycles = sorted(set(data['cycle number']))
for cycle in cycles:
# 提取一个周期内的特征
cycle_data = data[data['cycle number'] == cycle]
features = extract_features(cycle_data, char_freqs)
# 归一化处理
if normalize:
features, _, _ = normalize_data(features)
# 添加样本名称和特征
EIS_data.append((f"{sample_name}_cyc{cycle}", features))
return EIS_data
代码
文本

3.2.4 模块 4:训练与验证

分别定义训练过程和验证过程,支持批量训练与评估。

逻辑拆解:

  1. 训练过程: 前向传播、计算损失、反向传播、参数更新。

  2. 验证过程: 仅执行前向传播和损失计算,记录预测值和真实值。

代码
文本
[ ]
def train_epoch(model, train_loader, optimizer, criterion, device):
"""
单轮训练过程。
"""
model.train()
total_loss = 0.0
for batch_input, batch_output in train_loader:
batch_input, batch_output = batch_input.to(device), batch_output.to(device)
optimizer.zero_grad()
output = model(batch_input)
loss = criterion(output, batch_output)
loss.backward()
optimizer.step()
total_loss += loss.item() * batch_input.size(0)
return total_loss / len(train_loader.dataset)

def validate_epoch(model, valid_loader, criterion, device):
"""
单轮验证过程。
"""
model.eval()
total_loss = 0.0
predictions, targets = [], []
with torch.no_grad():
for batch_input, batch_output in valid_loader:
batch_input, batch_output = batch_input.to(device), batch_output.to(device)
output = model(batch_input)
loss = criterion(output, batch_output)
total_loss += loss.item() * batch_input.size(0)
predictions.append(output.cpu())
targets.append(batch_output.cpu())
return total_loss / len(valid_loader.dataset), torch.cat(predictions), torch.cat(targets)

代码
文本

3.2.5 模块 5:主函数

组织数据加载、特征处理、训练与验证的整体流程。

代码
文本
[ ]
def normalize_data(data, min_val=None, max_val=None):
"""
对输入数据进行归一化处理。

Parameters:
- data: 输入的张量(Tensor)。
- min_val: 最小值,用于归一化。如果为 None,则从数据中计算。
- max_val: 最大值,用于归一化。如果为 None,则从数据中计算。

Returns:
- 归一化后的数据。
"""
if min_val is None:
min_val = torch.min(data, dim=1, keepdim=True).values
if max_val is None:
max_val = torch.max(data, dim=1, keepdim=True).values
# 避免除以零的情况
range_val = max_val - min_val
range_val[range_val == 0] = 1e-8

return (data - min_val) / range_val, min_val, max_val

代码
文本

结果输出与分析

代码
文本

1.epoch=200

代码
文本

alt

代码
文本

alt

代码
文本

2.epoch=300

代码
文本

alt

代码
文本

alt

代码
文本

alt

代码
文本

3.epoch=500

代码
文本

alt

代码
文本

alt

代码
文本

alt

代码
文本

3.3 改进CNN模型的整体分析与优势

3.3.1 数据加载和处理的优化

改动内容

  • 重构了load_data函数:
    • 从指定频率点(CHAR_F)提取Re(Z)-Im(Z)特征。
    • 使用torch.stack高效地将特征组合成具有明确维度的张量。
  • 增加cycle number 作为模型输入特征,能够显著提升模型的表现与结果解释能力。

优点

  • 模块化改进
    • 数据加载、预处理和特征提取的逻辑分离,更清晰、更易维护。
  • 动态特征提取
    • 支持从指定频率点灵活提取特征,便于适配不同任务需求。 -cycle number(循环次数)作为特征
    • 能显著提高模型的预测能力、泛化能力及物理解释性。 -它能够帮助模型捕捉实验的时间序列关系,减少误差,并提供更丰富的分析维度,使结果更贴近实验实际情况 -对于动态变化明显的实验数据,cycle number** 是一个关键且不可忽略的输入特征。

3.3.2 模型架构的增强

改动内容

  • 引入了残差块ResidualBlock类)。
  • 使用自适应池化层和卷积层代替简单的全连接层(EISConvNet类)。

优点

  • 残差学习
    • 解决深层网络中的梯度消失问题,提高模型在深层架构下的性能。
  • 更好地处理序列数据
    • 自适应池化允许模型处理不同长度的输入序列,同时保持输出的一致性。
  • 可扩展性
    • 模型设计更加灵活,可以轻松增加深度和宽度。

3.3.3 训练和验证的改进

改动内容

  • 增加了独立的训练函数train_epoch和验证函数validate_epoch
  • 在训练过程中动态计算并记录RMSE

优点

  • 代码可读性
    • 将训练和验证逻辑独立出来,提高代码的逻辑清晰度。
  • 更全面的评估
    • 同时记录R²和RMSE,为模型的预测能力提供更全面的评估指标。

3.3.4. 可视化的增强

改动内容

  • 增加了以下绘图函数:
    • 损失曲线plot_loss):标题中显示平均R²和RMSE。
    • 真实值与预测值的散点图plot_predictions_scatter)。
    • 残差分析plot_residual_analysis),包括残差分布图和QQ图。

优点

  • 更好的分析能力
    • 通过多种可视化图表,更清晰地了解模型的行为和性能。
  • 视觉效果改进
    • 使用透明度(alpha)和网格线(grid)提升了图表的美观性和可读性。

3.3.5 错误处理与调试

改动内容

  • 增加了对空数据集的检查(if len(EIS_data) == 0)。
  • 使用pad_or_truncate函数动态地对输入数据进行填充或截断。

优点

  • 更高的鲁棒性
    • 确保当数据集为空或格式错误时,及时抛出异常。
  • 更好的适配性
    • 对于不同长度的输入序列,自动填充或截断以保证维度一致性。

3.3.6 平均R²和RMSE的计算与展示

改动内容

  • 在所有epoch结束后,计算并展示平均R²RMSE
  • 将这些平均值直接标注在损失曲线图上。

优点

  • 总结性指标
    • 提供训练过程的整体表现,为模型选择提供依据。

3.3.7 训练轮次的调整

改动内容

  • 将训练循环扩展为200/300/500轮,并每10轮输出一次结果。

优点

  • 更充分的优化
    • 增加训练轮次,确保模型能够充分收敛。
  • 定期输出
    • 每10轮输出一次结果,避免日志过于冗长,同时保持训练过程的可跟踪性。

改进总结

  • 模块化设计
    • 数据加载、训练、验证、绘图等功能独立封装,便于扩展与维护。
  • 模型架构优化
    • 残差块和自适应池化提升了深层网络的学习能力。
  • 多样化的可视化
    • 通过预测值与真实值散点图、残差分析等图表,直观地展示模型性能。
  • 全面的指标评估
    • 同时记录并展示R²和RMSE,为模型性能提供多维度衡量。
  • 训练流程更加完善
    • 增加epoch轮次并定期输出,进一步提升模型训练的收敛性和可视化能力。
代码
文本

4 基于短脉冲响应的EIS图谱预测

4.1 经典ANN模型测试

基于所给数据集,我们使用经典的ANN模型给出了对应结果,对实验数据的本征相关性进行了测试。 在ANN模型当中,构建了以电压数据为基础的输入函数,使用EIS的实部与虚部作为目标函数,调试了对ANN模型中batch size和epoch对实验RMSE的影响。

代码
文本
[ ]
# 定义输入函数
def input_mlp(datasets, mode):
input_data = []
soc_lst = [f'{i*2}%SOC' for i in range(49)]
for i in datasets:
pulse_data = pickle.load(data, encoding='bytes')# 输入数据载入
for soc in soc_lst:
Vol = pulse_data[soc]['Voltage'] # 选取电压数据单独保存
tensor_vol = torch.tensor(Vol).view(1,99,1)
input_data.append(tensor_vol) #构建以充放电曲线为基础的输入函数
return input_data
代码
文本
[ ]
#测试模型epoch的大小对RMSE的影响
train_losses = [] # 记录每个epoch的训练损失
for epoch in range(num_epochs):
epoch_loss = 0.0
train_size = len(input_train)
for batch_idx in range(0, train_size, batch_size):
batch_input = torch.cat(input_train[batch_idx:batch_idx+batch_size], dim=0)
batch_target = torch.cat(target_train[batch_idx:batch_idx+batch_size], dim=0)

optimizer.zero_grad()

outputs = model(batch_input)
loss = criterion(outputs, batch_target)
loss.backward()
optimizer.step()
epoch_loss += loss.item() * batch_input.shape[0]

scheduler.step(epoch_loss / (train_size / batch_size))
train_losses.append(epoch_loss / (train_size / batch_size))
if (epoch + 1) % 50 == 0:
mean_mse = epoch_loss / (train_size / batch_size)
rmse = mean_mse ** 0.5
print(f"Epoch [{epoch + 1}/{num_epochs}] | Loss: {mean_mse:.4f} | RMSE: {rmse:.4f}")
代码
文本
[ ]
# 定义目标函数
def target_mlp(datasets, mode):
target_data = []
soc_lst = [f'{i*2}%SOC' for i in range(49)]
EIS_list = []
for k in datasets:
eis_data = pickle.load(data, encoding='bytes')# 目标函数输入数据载入
for soc in soc_lst:
EIS_tot = [[],[]]
re = eis_data[soc]['Real']# EIS实部构建
im = eis_data[soc]['Imaginary']# EIS虚部构建
EIS_tot[0] = re
EIS_tot[1] = im
EIS_list.append(EIS_tot)
EIS_list = [np.array(t).squeeze().T for t in EIS_list]
target_data = [torch.tensor(t).float().view(1, 51, 2) for t in EIS_list]# 构建以EIS实部虚部构成的张量
return target_data
代码
文本

4.2 实验结果

alt alt

代码
文本

5 基于充电曲线的EIS图谱预测

5.1 数据处理

代码
文本

首先,数据来源于公开数据集https://zenodo.org/records/3633835 ,而由于数据集中有些数据EIS存在异常点,因此我们这里只选用其中的部分进行训练和预测。 其中我们只取编号是C02,C03,C04,C06,C07以及C08的电池进行数据提取,其中循环序号这一数据取自数据集中的第二列cycle number,电压这一数据取自数据集中的第四列Ewe/V。

代码
文本
[ ]
baty_lst = [2,3,4,6,7,8]
for i in baty_lst:
CC_data = pd.read_csv(f"/personal/Capacity data/Data_Capacity_25C0{i}.csv")#用于导入不同电池批次的数据
cycle_num = CC_data.iloc[:, 1:2]["cycle number"].tolist()# .iloc 是用来基于行和列的位置进行索引选择的方法,导入第二行循环次数 cycle number 的数据,并把 Dataframe 数据转换为列表
vol_all = CC_data.iloc[:, 3:4]['Ewe/V'].tolist()# .iloc 是用来基于行和列的位置进行索引选择的方法,导入第四行电压 Ewe/V 的数据, Dataframe 数据转换为列表
代码
文本

这里定义了两种数据分割函数split_list_by_value以及split_list_by_length,其中split_list_by_value是将非0的、不是最后一个元素的且与下一元素不同的添加到结果列表 result中,而split_list_by_length则是通过特定的长度进行数据的分割。

代码
文本
[ ]
#如果是非0元素且不是最后一个元素且与下一元素不同的添加到结果列表 result 中
def split_list_by_value(lst):
result = []
temp = []
for i in range(len(lst)):
if lst[i] != 0:
temp.append(lst[i])
if i == len(lst)-1 or lst[i] != lst[i+1]:#检查是否到达列表的最后一个元素且是否与前一个元素相同
result.append(temp)
temp = []
return result
#将长度为 length 的子列表添加到结果列表 result 中
def split_list_by_lengths(lst, lengths):
result = []
start = 0
for length in lengths:
result.append(lst[start:start+length])
start += length
return result
代码
文本

这里利用split_list_by_value分割循环序号这组数据,让每个电池的每个循环都变为一个子列表,然后提出cyc中每个子列表的长度,按照该长度去分割电压数据vol,得到vol_list数据。

代码
文本
[ ]
cyc = split_list_by_value(cycle_num)#分割循环次数,每个电池的循环都变成 cycle_num 列表中的一个子列表
cyc_len.append(len(cyc))
lengths = [len(sublist) for sublist in cyc]#计算 cyc 中每个子列表的长度
vol_list = split_list_by_lengths(vol_all, lengths)#按照 cyc 中每个子列表的长度去分割电压数据
代码
文本

处理EIS的数据,这里导入了不同pihao电池的不同SOC下的EIS数据,经过相关处理后,得到的EIS_list是一个三位列表,含有222个元素(即所有电池输入的数据点的总数,6个电池的循环数的总和),222个元素中每个元素是一个包含两个子列表(实部和虚部)的列表,每个子列表有240个元素(每个电池每个循环的EIS有60个点,每个电池每个循环有四个SOC state,一共240个),用于存储所有电池的EIS数据。这里画出EIS_state_{1}_25C0{2}号电池第一个循环下的EIS阻抗谱,来验证EIS数据的成功导入。

代码
文本
[ ]
decoder_input = []
decoder_target = []
cyc_tot = 0
#创建一个三维列表,用于存储电化学阻抗谱( EIS )数据.其 shape 为(222, 240, 2).第一维包含222个元素,代表四个电池的总循环次数,每个元素是一个包含两个子列表(实部和虚部)的列表,每个子列表有240个元素(每个电池每个循环的 EIS 有60个点,每个电池每个循环有四个 state ,一共240个)
EIS_list = [[[0 for i in range(240)] for j in range(2)] for r in range(222)]
lst = [1, 4, 5, 9]
for k in baty_lst:
EIS_tot = []
for i in lst:
EIS = pd.read_csv(f"/personal/EIS data/EIS_state_{i}_25C0{k}.csv")#导入不同批次电池不同电池soc状态的EIS数据
cyc_n = cyc_len[baty_lst.index(k)]
#print(cyc_n)
EIS_tot.append(EIS.iloc[:, 3:7][" Re(Z)/Ohm"].tolist()[0:60 * cyc_n])#选择第四列 Re(Z)/Ohm 实部数据
EIS_tot.append(EIS.iloc[:, 4:7][" -Im(Z)/Ohm"].tolist()[0:60 * cyc_n])#选择第五列 -Im(Z)/Ohm 虚部数据
cyc_tot += cyc_n
EIS_totm = [[e2 for e2 in e1] for e1 in EIS_tot]#扁平化嵌套列表
print(np.array(EIS_totm).shape, cyc_tot)
lengths = [60 for i in range(cyc_n)]
# print(lengths)
for i in range(4):
EIS_R = split_list_by_lengths(EIS_totm[2 * i], lengths)#将 EIS 数据的实部按照每个电池的循环次数分割成多个子列表
EIS_I = split_list_by_lengths(EIS_totm[2 * i + 1], lengths)#将 EIS 数据的虚部按照每个电池的循环次数分割成多个子列表
for j in range(cyc_tot - cyc_n, cyc_tot, 1):#这个循环遍历当前电池的 EIS 数据
EIS_list[j][0][60 * i:60 * (i + 1)] = EIS_R[j - cyc_tot + cyc_n]#将实部数据 EIS_R 中的第 j - cyc_tot + cyc_n 个元素(即当前电池的实部数据)赋值给 EIS_list 的相应位置. 60 * i:60 * (i + 1) 确定了在 EIS_list 中的起始和结束索引
EIS_list[j][1][60 * i:60 * (i + 1)] = EIS_I[j - cyc_tot + cyc_n]
EIS_list = [np.array(t).squeeze().T for t in EIS_list]#每个电池的EIS数据都被整理成一个二维数组,其中行代表不同的 SOC 状态,列代表不同的数据点
print(np.array(EIS_list)[0].shape)
代码
文本

alt

让数据标准化,利用MinMaxScaler将数据控制在(0,1)之间,分别将输入数据与输出的EIS数据均进行标准化。

代码
文本
[ ]
scaler = MinMaxScaler(feature_range=(0, 1))
CC_input_scaled = []
for data in CC_input:
data = np.array(data).squeeze() # 转换为数组并去除多余的维度
scaled_data = scaler.fit_transform(data.reshape(-1, 1))# 将数据重新形状为(-1, 1)使其适应 MinMaxScaler 的输入格式
CC_input_scaled.append(torch.tensor(scaled_data).view(1, -1, 1))# 将标准化后的数据转换为 Tensor 并添加到列表中
EIS_scaled = []
for i in range(len(EIS_list)):
EIS_data = EIS_list[i] # 获取 EIS 数据
# 使用 MinMaxScaler 对每个 EIS 数据进行标准化
scaled_EIS = scaler.fit_transform(EIS_data) # 将数据标准化到[0, 1]
EIS_scaled.append(torch.tensor(scaled_EIS).float()) # 转换为 Tensor 并添加到列表中
print("Standardized EIS data:", np.array(EIS_scaled).shape)
代码
文本

引入shuffle,将传入的indices打乱顺序,将训练集和测试集打乱顺序。这有助于防止学习到数据集中的特定顺序,防止模型对训练数据的特定排列产生依赖,从而提高模型的泛化能力,此外还可以帮助模型更快地收敛到最优解,提高运行效率。这是因为打乱后的数据可以提供更多样化的梯度信息,有助于避免陷入局部最小值。

代码
文本
[ ]
indices = list(range(len(CC_input)))
random.shuffle(indices)# shuffle 是 random 模块中的一个函数,用于将传入的 indices 就地打乱顺序
train_indices = indices[:train_size]#打乱训练集索引
test_indices = indices[train_size:]#打乱测试集索引
代码
文本

处理encoder输入数据以及decoder的输入和输出数据,将decoder的输入和输出数据都重塑为形状为(1, 240, 2)的三维张量,其中1表示批量大小,240可能是序列长度,2表示每个时间步的特征数量,以此来满足模型的数据输入和输出维度要求。

代码
文本
[ ]
encoder_input_train=[CC_input_scaled[i] for i in train_indices]
encoder_input_test=[CC_input_scaled[i] for i in test_indices]
decoder_target = [torch.tensor(t).float().view(1,240, 2) for t in EIS_scaled]#转换为张量并重塑张量的形状为 (1, 240, 2),其中1表示批量大小,240是列表长度,2 表示每个时间步的特征数(实部和虚部)
decoder_input = [torch.ones(1,240,2) for t in EIS_scaled]#初始化为全是1的张量将作为模型的输入数据,通常在训练开始时用于启动解码过程
decoder_input_train = [decoder_input[i] for i in train_indices]
decoder_target_train = [decoder_target[i] for i in train_indices]
decoder_input_test = [decoder_input[i] for i in test_indices]
decoder_target_test = [decoder_target[i] for i in test_indices]
代码
文本
双击即可修改
代码
文本

5.2 模型的构建、训练与优化

5.2.1 基于LSTM的Seq2Seq模型

首先构建了基于LSTM的Seq2Seq模型中的编码 编码器(Encoder)部分,Encoder基于 PyTorch 框架实现,核心采用了双层堆叠的长短时记忆网络(LSTM)结构,用于对时间序列数据进行特征提取和编码。该 LSTM 的输入特征维度为 1,隐藏状态的维度设置为 256,能够在高维空间中有效表征输入数据的时序特征。为了提高模型的表达能力,LSTM 的层数设置为 2,并在层间引入了 50% 的 Dropout,以减少过拟合风险并提升泛化能力。此外,通过设置 batch_first=True,确保输入和输出张量的第一维为批量大小(batch size),输入形状为 (batch_size, seq_len, feature_dim),便于与常见的数据格式兼容。在前向传播过程中,编码器接收输入序列并输出隐藏状态(h_n)和细胞状态(c_n),为后续的解码器(Decoder)提供丰富的上下文信息,从而实现对时间序列的高效编码。

代码
文本
[ ]
# define encoder
class Encoder(nn.Module):
def __init__(self):
super(Encoder, self).__init__()
self.lstm = nn.LSTM(1, 256, batch_first=True, num_layers=2, dropout=0.5)# batch_first=True 是指定输入和输出张量的第一个维度为批次大小, lstm 层数是2, dropout 率为0.5,防止过拟合

def forward(self, x):
_, (h_n, c_n) = self.lstm(x)
return h_n, c_n
代码
文本

解码器(Decoder)的实现同样基于 PyTorch 框架,核心结构由一个单层长短时记忆网络(LSTM)和一个全连接层(Linear Layer)组成,旨在将编码器输出的高维特征解码为目标数据格式。解码器的输入特征维度为 2,对应阻抗数据的特征(实部和虚部),隐藏状态的维度被设置为 256,以捕捉时序信息中的潜在模式。在前向传播过程中,LSTM 层接收输入数据以及隐状态 hidden,生成时序特征后,经过一个全连接层(输入维度为 256,输出维度为 2)进行线性变换,最终生成解码输出。通过这样的结构设计,解码器能够将高维隐藏状态映射为目标数据的输出特征,从而实现从隐空间到实际阻抗数据的有效转换。

代码
文本
[ ]
class Decoder(nn.Module):
def __init__(self):
super(Decoder, self).__init__()
self.lstm = nn.LSTM(2, 256, batch_first=True, num_layers=2) # 增加单元数
self.dense = nn.Linear(256, 2) # 输出维度为2

def forward(self, x, hidden):#前向传播的为输入数据和隐藏 state
x, _ = self.lstm(x, hidden)
x = self.dense(x)#将 LSTM 层的输出传递给全连接层,得到最终的输出
return x
代码
文本

Encoder-Decoder部分由一个Encoder和一个Decoder组成,使用模块化的设计以增强灵活性和可扩展性。在前向传播中,该模型接收三个主要输入:编码器输入(encoder_input)、解码器输入(decoder_input)以及是否启用教师强制(use_teacher_forcing)的标志。首先,编码器输入通过编码器生成隐藏状态(hidden),隐状态捕获了输入序列的全局时序信息。随后,启用教师强制(teacher forcing),解码器直接使用解码器输入(decoder_input)与隐藏状态进行一次性计算,输出整个序列。这种方法有助于加速训练过程,因为模型可以直接从正确的输出中学习。然而,过度依赖教师强制可能会使模型在推理时表现不佳,因为它没有学会从自己的错误中恢复。通过逐渐减少教师强制的使用比例,模型可以逐渐学会更好地依赖自己的预测。最终,解码器生成的输出张量被返回,表示整个时间序列的预测结果。通过这种设计,编码器-解码器模型能够根据实际任务需求,灵活切换解码方式,并结合自回归机制完成高效的时间序列建模。

代码
文本
[ ]
# define Encoder-Decoder model
class EncoderDecoder(nn.Module):
def __init__(self, encoder, decoder):
super(EncoderDecoder, self).__init__()
self.encoder = encoder
self.decoder = decoder

def forward(self, encoder_input, decoder_input, use_teacher_forcing):#模型的前向传播函数,接受三个参数: encoder_input (编码器的输入), decoder_input (解码器的输入),和 use_teacher_forcing (一个布尔值,决定是否使用教师强制)
hidden = self.encoder(encoder_input)

if use_teacher_forcing:
output = self.decoder(decoder_input, hidden)
else:
batch_size, seq_len, _ = decoder_input.size()
output = torch.zeros_like(decoder_input)#创建一个与解码器输入形状相同的零张量 output ,用于存储解码器的输出
decoder_input_t = decoder_input[:, 0, :]#初始化解码器在时间步 t=0 的输入
for t in range(seq_len):
decoder_output_t = self.decoder(decoder_input_t.unsqueeze(1), hidden)
output[:, t, :] = decoder_output_t.squeeze(1)
decoder_input_t = decoder_output_t.squeeze(1)

return output
代码
文本

训练过程的实现,首先定义loss function以及优化器,使用均方误差和Adam优化器(通过结合动量与自适应学习率方法,提高了梯度下降的效率与收敛速度)。因为数据量的原因,这里我们把epoch的数量设为1500,batch size设为4。 每轮训练中,模型对编码器输入、解码器输入和目标值进行批量处理,并通过前向传播生成预测结果。随后,计算预测值与目标值之间的均方误差,并利用反向传播(Backpropagation)算法对梯度进行计算,通过优化器更新模型参数。在此过程中,通过 optimizer.zero_grad() 清空梯度,避免累积影响后续计算。同时,记录每轮的平均损失(epoch loss),并在每 20 个轮次打印一次训练日志,包括平均损失(MSE)和均方根误差(RMSE),以直观评估模型的训练效果。此训练框架通过动态调整教师强制比例与批量处理策略,有效提升了模型的学习能力和泛化性能,满足了时间序列预测任务的需求。

代码
文本
[ ]
criterion = nn.MSELoss().to (device)
optimizer = optim.Adam(model.parameters(), lr=0.001)
num_epochs = 1500
batch_size = 4
train_losses = [] # 记录每个 epoch 的训练损失
for epoch in range(num_epochs):
epoch_loss = 0.0#初始化一个变量 epoch_loss 为 0.0,用于累积当前训练周期的总损失
# Scheduled sampling probability
#使用了教师强制
teacher_forcing_ratio = max(0.5 * (1 - epoch / num_epochs), 0.0)#计算教师强制( Teacher Forcing )的比例,这个比例随着训练周期的增加而减少,从0.5 开始,直到最后一个周期降到0
# use_teacher_forcing = torch.rand(1).item() < teacher_forcing_ratio
use_teacher_forcing = True
for batch_idx in range(0, train_size, batch_size):#开始一个循环,用于遍历训练数据的批次,batch_idx 从0开始,以 batch_size 为步长,直到 train_size
#使用torch.cat将编码器和解码器的输入以及解码器的目标数据按批次大小进行拼接
batch_encoder_input = torch.cat(encoder_input_train[batch_idx:batch_idx + batch_size], dim=0).to (device)
batch_decoder_input = torch.cat(decoder_input_train[batch_idx:batch_idx + batch_size], dim=0).to (device)
batch_decoder_target = torch.cat(decoder_target_train[batch_idx:batch_idx + batch_size], dim=0).to (device)

optimizer.zero_grad()#清空优化器的梯度,为反向传播做准备
outputs = model(batch_encoder_input, batch_decoder_input, use_teacher_forcing).to (device)
loss = criterion(outputs, batch_decoder_target)#计算模型输出和解码器目标之间的损失
loss.backward()#反向传播
optimizer.step()#更新模型参数
epoch_loss += loss.item()#将当前批次的损失添加到 epoch_loss

train_losses.append(epoch_loss / (train_size / batch_size))#将当前周期的平均损失添加到train_losses列表中
if (epoch + 1) % 20 == 0:#每20周期轮次输出一次 loss
mean_mse = epoch_loss / (train_size / batch_size)#平均平方误差
rmse = mean_mse ** 0.5#均方根误差
print(f"Epoch [{epoch + 1}/{num_epochs}], Loss: {mean_mse:.8f}, RMSE: {rmse}")
代码
文本

我们将训练过程中的MSE随着训练轮次的变化画出来,发现loss主要在0.0016-0.05之间,且不是特别稳定。

alt

代码
文本

5.2.2 基于LSTM的Seq2Seq模型的优化

由于上述模型复现出的结果,其loss较大,且ground state与预测的结果之间仍有较大提升空间,因此在此基础上进行了优化。

5.2.2.1 超参数手动调优

第一个优化点,我们通过手动调参,去调整learning rate,batch_size,以及num_epochs这些超参数。先是保持batch_size=5以及learning rate=0.001不变,调整学习轮次(分别取250,500,600,700,1000,1500),如果Epochs设置得太少,模型可能无法充分学习数据集中的特征,导致欠拟合;而如果Epochs设置得太多,模型可能会记住训练数据中的噪声,导致过拟合,不同学习轮次对应的Loss随着学习轮次的变化如下图所示。随着epochs的增加,模型稳定性受到一定影响,因此最优应在500-700之间。

代码
文本

alt alt alt alt alt alt

代码
文本

再保持batch_size=5以及num_epochs=1000不变,调整learning rate(分别取0.01,0.001,00005,0.0001),如果学习率设置得太高,模型可能会在最优解附近震荡,导致无法收敛;如果学习率太低,模型的收敛速度会很慢,甚至可能陷入局部最优解,因此需要找到最优学习率。不同学习率对应的训练过程如下图所示,可以发现,当learning rate在0.0005附近时,训练过程的loss波动明显减小。

代码
文本

alt alt alt alt

代码
文本

最后保持num_epochs=500,learning rate=0.001不变,改变batch_size(设置为5,10,15,20,30),较大的batch_size可能需要较大的内存和计算资源,在训练集上表现较好,但是泛化能力可能较差。而较小的batch_size有助于模型更频繁地更新权重,这可以提高模型对数据中噪声的适应性,从而可能获得更好的泛化性能,但是可能导致训练过程中的不稳定性,使得模型权重更新更加随机。不同batch_size对应的训练过程如下图所示。可以发现,随着batch_size的增加,初始损失降低,波动变小,模型稳定性增加,但是过大时,可能影响模型的泛化能力,导致后续预测性能变差。因此最优batch_size在10-20之间.

代码
文本

alt alt alt alt alt

代码
文本
5.2.2.2 引入脉冲电流特征以增强模型预测能力
代码
文本

第二个优化点,让模型多学习了一个脉冲电流的特征,脉冲电流和其对应的电压的举例(0-4循环)如下图所示。在电化学系统中,电压和电流是相互依赖的物理量。电压通常是输入信号,而电流则反映了系统的响应。仅使用电压特征可能会忽视电流对阻抗的影响,导致模型预测的精度下降。增加电流特征可以让模型同时学习电压和电流对阻抗的共同作用,从而提高模型对系统的理解和预测能力,提高模型的预测精度以及鲁棒性。

代码
文本
[ ]
cur_all=CC_data.iloc[:,4:5][' I/mA'].tolist()#这里多学习一个特征,即脉冲电流数据,让模型预测的更准
cur_list= split_list_by_lengths(cur_all, lengths)
tensor_cur = [torch.tensor(sublist).view(-1, 1) for sublist in cur_list] # [N, 1]
padded_cur = pad_sequence(tensor_cur, batch_first=True, padding_value=0) # [batch_size, max_len, 1]
combined_features = torch.cat((padded_vol, padded_cur), dim=-1)#将每个时间步的电压和电流数据被组合在一起,形成一个新的张量
代码
文本

alt

代码
文本
5.2.2.3 采用粒子群优化算法寻得的最优超参数
代码
文本

第三个优化点则是添加了粒子群优化(PSO)算法,其能够有效寻找高维空间中的最优或近似最优解。基于LSTM的Seq2Seq模型有许多超参数需要优化,如学习率、批量大小、隐藏层单元数、LSTM层数等,这些超参数通常有复杂的相互作用,人工调整难度较大。粒子群优化通过模拟粒子的群体行为,可以高效探索这个高维的超参数空间,自动寻找最佳组合。进而可以提高模型的精度,并防止过拟合。

代码
文本
[ ]
# def optimize_function(params):
# hidden_size = int(params[0]) # 隐藏层单元数
# learning_rate = params[1] # 学习率
# encoder = Encoder(hidden_size=hidden_size).to(device)
# decoder = Decoder(hidden_size=hidden_size).to(device)
# model = EncoderDecoder(encoder, decoder).to(device)
# optimizer = optim.Adam(model.parameters(), lr=learning_rate)
# criterion = nn.MSELoss().to(device)
# num_epochs = 1500
# batch_size = 4
# train_losses = [] # 记录每个epoch的训练损失
# for epoch in range(num_epochs):
# epoch_loss = 0.0

# teacher_forcing_ratio = max(0.5 * (1 - epoch / num_epochs), 0.0)
# use_teacher_forcing = True
# for batch_idx in range(0, train_size, batch_size):
# batch_encoder_input = torch.cat(encoder_input_train[batch_idx:batch_idx + batch_size], dim=0).to (device)
# batch_decoder_input = torch.cat(decoder_input_train[batch_idx:batch_idx + batch_size], dim=0).to (device)
# batch_decoder_target = torch.cat(decoder_target_train[batch_idx:batch_idx + batch_size], dim=0).to (device)

# optimizer.zero_grad()
# outputs = model(batch_encoder_input, batch_decoder_input, use_teacher_forcing).to (device)
# loss = criterion(outputs, batch_decoder_target)
# if torch.isnan(loss).any() or loss is None or loss == float('inf'):
# print(f"Invalid loss at epoch {epoch}, batch {batch_idx}")
# return float('inf') # Avoid passing None or invalid loss to PSO
# loss.backward()
# optimizer.step()
# epoch_loss += loss.item()

# train_losses.append(epoch_loss / (train_size / batch_size))
# if (epoch + 1) % 20 == 0:
# mean_mse = epoch_loss / (train_size / batch_size)
# rmse = mean_mse ** 0.5
# print(f"Epoch [{epoch + 1}/{num_epochs}], Loss: {mean_mse:.8f}, RMSE: {rmse}")
# return mean_mse if mean_mse is not None else float('inf')
# #scheduler.step(epoch_loss)
# lb = [128, 1e-5] # 下边界 [隐藏层单元数,学习率]
# ub = [512, 1e-2] # 上边界 [隐藏层单元数,学习率]
# # 使用PSO优化
# best_params, _ = pso(optimize_function, lb, ub, swarmsize=5, maxiter=10)
# # 输出最优的超参数
# best_hidden_size = int(best_params[0])
# best_lr = best_params[1]

# print(f"Optimized hidden size: {best_hidden_size}")
# print(f"Optimized learning rate: {best_lr}")
代码
文本

引入脉冲电流特征以及经过PSO优化的模型的训练过程以及训练Loss随着学习轮次的变化如下图所示。从图中可以看到模型在初始阶段(前50轮)损失迅速下降,表明模型能够有效捕捉数据中的模式。此外,整体趋势显示损失在逐渐减小并趋于稳定,表明模型能够有效收敛。尽管存在波动,整体损失曲线最终趋于较低值且未出现持续上升,表明训练过程较为稳定。

代码
文本

alt

代码
文本

5.3 实验结果分析

代码
文本

5.3.1 基于LSTM的Seq2Seq模型的复现

模型复现采取的batch_size是4,学习轮数为1500,而lr设置的是0.001,均不符合分析出的最优的超参数,因此其预测的结果仍有提升空间,预测MSE是0.0071,RMSE是0.0845。下图为4种SCOC状态下测试集预测结果与target value对比(四种SOC合起来与分开来看)。分析发现,预测结果在整体形状,相位一致性以及趋势一致性上表现较好,且四种SOC在高频区域预测精度很高,几乎与target value重合,但在中低频区域精度还有待提升。

alt

alt

这是复现模型的R2图,可以发现实部与虚部的R2分别达到了0.9712和0.8893,相关性较好,但右上方的离群点表明模型在处理某些特定值时可能还有改进的空间。

alt alt

代码
文本

5.3.2 超参数手动寻优过程

首先是观察num_epochs对预测loss的影响,如下图所示,可以发现在epochs在500-700之间,模型预测精度更高。再观察batch_size对预测精度的影响,如下图所示,可以发现batch_size在10-20之间时,loss更低。最后再分析learning rate对预测loss的影响,如下图所示,可以看到,lr在0.0005附近时,预测的误差最小。

alt alt alt

5.3.3 优化后的基于LSTM的Seq2Seq模型

在优化后,测试的mse误差为0.0014,RMSE是0.0378,4种SCOC状态下测试集预测结果与target value对比(四种SOC合起来与分开来看)如下图所示 alt alt

优化后的模型的R2得到了较大提升,分别是0.9885和0.9843,表明优化后的模型在预测EIS数据的实部和虚部方面都表现出色。

alt alt

代码
文本

5.3.4 不同压力范围内的模型评估

代码
文本

不同电压范围下的训练过程及预测的MSE和RMSE如下图所示,可以发现,随着voltage范围的增大,MSE和RMSE逐步减小,说明学习更多电压信息的模型预测的表现更好。但是在较窄的电压范围内,例如3.8-4.0V时,依旧有0.0025的MSE和0.0503的RMSE。说明部分电压的充电曲线可以代表整个充电曲线的位移特性,该工作有助于选择既能提供电化学解释又能具有较高预测性能的局部电压范围。

代码
文本

alt alt

代码
文本

5.3.5 Transformer模型

代码
文本
5.3.5.1 Transformer模型的构建
代码
文本

Transformer模型的构建通过定义一个TransformerModel类实现。在初始化过程中,模型创建了编码器和解码器层,分别用于处理输入序列和生成输出序列。编码器和解码器都配置了指定数量的层和注意力头(num_heads),以及隐藏层维度(hidden_dim)。此外,模型还包括一个线性层(self.fc_out)用于将解码器的输出映射到目标输出空间,以及一个用于将输入特征维度(feature_dim)映射到隐藏层维度的嵌入层(self.embedding)。在前向传播(forward)方法中,输入数据首先通过嵌入层,然后通过编码器生成记忆(memory),接着根据是否使用教师强制(use_teacher_forcing)来决定解码过程。如果使用,解码器直接使用目标序列作为输入;如果不使用,解码器采用自回归方式,逐步生成输出。最终,解码器的输出通过线性层转换为最终的输出维度(output_dim)。模型参数包括输入特征维度、隐藏层维度、注意力头数、层数和输出维度,这些参数在实例化模型时被设置,并根据需要转移到计算设备上。

代码
文本
[ ]
# Transformer Encoder
class TransformerEncoder(nn.Module):
def __init__(self, input_dim, model_dim, num_layers, num_heads, ff_dim, dropout=0.1):
super(TransformerEncoder, self).__init__()
self.embedding = nn.Linear(input_dim, model_dim)
self.positional_encoding = nn.Parameter(torch.zeros(1, 1654, model_dim)) # 最大序列长度1654
self.encoder_layers = nn.TransformerEncoderLayer(d_model=model_dim, nhead=num_heads, dim_feedforward=ff_dim, dropout=dropout)
self.encoder = nn.TransformerEncoder(self.encoder_layers, num_layers=num_layers)

def forward(self, x):
x = self.embedding(x) # 形状 (batch_size, seq_len, model_dim)
x += self.positional_encoding[:, :x.size(1), :]
return self.encoder(x.permute(1, 0, 2)) # 形状 (seq_len, batch_size, model_dim)

# Transformer Decoder
class TransformerDecoder(nn.Module):
def __init__(self, output_dim, model_dim, num_layers, num_heads, ff_dim, dropout=0.1):
super(TransformerDecoder, self).__init__()
self.embedding = nn.Linear(output_dim, model_dim)
self.positional_encoding = nn.Parameter(torch.zeros(1, 1654, model_dim)) # 最大序列长度1654
self.decoder_layers = nn.TransformerDecoderLayer(d_model=model_dim, nhead=num_heads, dim_feedforward=ff_dim, dropout=dropout)
self.decoder = nn.TransformerDecoder(self.decoder_layers, num_layers=num_layers)
self.fc_out = nn.Linear(model_dim, output_dim)

def forward(self, x, memory):
x = self.embedding(x) # 形状 (batch_size, seq_len, model_dim)
x += self.positional_encoding[:, :x.size(1), :]
x = self.decoder(x.permute(1, 0, 2), memory)
return self.fc_out(x.permute(1, 0, 2)) # 形状 (batch_size, seq_len, output_dim)

# Define Transformer Model
class TransformerSeq2Seq(nn.Module):
def __init__(self, encoder, decoder):
super(TransformerSeq2Seq, self).__init__()
self.encoder = encoder
self.decoder = decoder

def forward(self, encoder_input, decoder_input, use_teacher_forcing):
memory = self.encoder(encoder_input)
output = self.decoder(decoder_input, memory)
return output


# 设置模型参数
input_dim = 1 # 输入数据的特征维度,电压数据
output_dim = 2 # 输出维度(阻抗数据:实部和虚部)
model_dim = 256 # 隐藏层维度
num_layers = 2 # 编码器和解码器的层数
num_heads = 8 # 多头注意力的头数
ff_dim = 512 # 前馈层维数
dropout = 0.1


# 实例化模型并转移到设备
encoder = TransformerEncoder(input_dim, model_dim, num_layers, num_heads, ff_dim, dropout).to(device)
decoder = TransformerDecoder(output_dim, model_dim, num_layers, num_heads, ff_dim, dropout).to(device)
model = TransformerSeq2Seq(encoder, decoder).to(device)
print(model)
代码
文本
5.3.5.2 典型的报错与Debug
代码
文本

Debug:该模型运行过程中遇到了较多报错,更多的是数据维度不匹配,比如下面这行报错,我们通过引入embedding层来使得输入数据的维度满足模型要求。另外,transformer严格要求输入数据维度需要是(seq_len, batch_size, model_dim),而经过处理后的batch_encoder_input,batch_decoder_input等维度是 (batch_size, seq_len, model_dim),这个问题也困扰我们很久,最终利用permute(1, 0, 2)来调整数据的输入维度。

代码
文本
[ ]
AssertionError: was expecting embedding dimension of 1, but got 2
代码
文本
5.3.5.3 训练过程及分析
代码
文本

训练过程如下图所示,可以发现训练过程loss变化更小,且随着训练轮次的增加,loss总体呈下降趋势,不像Seq2Seq那样波动,模型相比与Seq2Seq更加稳定。此外,transformer由于其自注意力机制允许并行计算所有的时间步,这使得Transformer在训练过程中大大加速,因此与Seq2Seq相比,其训练效率大幅提升.

代码
文本

alt

代码
文本
5.3.5.4 预测结果展示与分析
代码
文本

LSTM虽然在理论上能够捕捉长期依赖,但是在面对长序列时,由于梯度消失或爆炸的问题,LSTM往往不能有效捕捉序列中较远的依赖关系。而Transformer的自注意力机制则不受此限制,可以时关注输入序列中的多个不同部分,捕捉到数据中的多种特征和规律。电压数据和阻抗图之间的关系又是非线性且复杂的,因此Transformer能够更好地建模这种复杂关系。

代码
文本

我们可以看到,利用transformer模型预测的结果,其预测MSE仅为0.0013,RMSE仅为0.036,并且从以下四个随机取样的对比中发现,其预测的EIS图谱在中低高频与target value重合度非常高,实现了在基于LSTM的Seq2Seq基础上的进一步提升。

代码
文本

alt alt alt alt

代码
文本

对比R2来看,实部的R2高达0.9994,虚部的也高达0.9953,与Seq2Seq相比,得到了进一步的提升.

代码
文本

alt alt

代码
文本

6 总结

此次报告中,我们运用了三种方法来预测EIS,分别是基于特征频率预测,基于脉冲响应预测以及基于充电曲线来预测EIS。

在基于特征频率预测EIS中,我们采用了CNN模型,CNN模型特别适合处理具有网格状拓扑结构的数据,如图像和序列数据。在EIS预测中,CNN模型能够捕捉频率数据中的空间相关性。该模型通过卷积层实现参数共享,减少了模型的参数数量,有助于降低过拟合的风险。其次,CNN的层次化结构能够自动提取输入数据的特征,从低级到高级特征逐步抽象。它对输入数据的平移、旋转等变换具有一定程度的不变性。用已有EIS来预测更高精度的EIS图谱,基于等效电路模型的DRT方法,以四个特征频率为输入参数,有效地捕捉时间序列中的局部依赖关系,同时加入cycle number(循环次数)作为第二特征,这是对于动态变化明显的实验数据的关键且不可忽略的输入特征,它能够帮助模型捕捉实验的时间序列关系,减少误差,并提供更丰富的分析维度,使结果更贴近实验实际情况。因此,本模型基于征频率和循环次数两个参数,通过引入ResNet来优化CNN模型,这对于预测电池的动态行为和老化过程,理解电池内部电化学过程至关yinci重要。

在基于短脉冲响应预测EIS中,ANN模型可以用于学习和模拟输入数据与输出结果之间的复杂非线性关系,适用于多种预测任务,包括EIS预测。其结构灵活,可以通过调整隐藏层的数量和每层的神经元数量来适应不同的任务。经过适当的训练,ANN能够对未见数据进行有效的预测。

在基于充电曲线预测EIS中,电压数据通常具有时间序列特性,即当前的电压值可能与前一刻的电压值有关。在电池状态预测中,LSTM可以用来捕捉电池充放电过程中的动态变化,为电池状态的准确预测提供支持。基于LSTM的Seq2Seq模型适用于电压数据预测EIS阻抗谱,复现的模型其预测的MSE为0.0071,RMSE为0.0845,R2为,效果较好,引入电流数据以及PSO优化后的模型得到了明显改善,不仅训练过程中更加稳定,MSE和RMSE缩小至0.0014和0.0378,R2增大至,且可以从EIS可视化对比图中明显看出在中高低频都有更好的预测表现。且通过不同范围的电压输入,验证了该模型的电化学可解释性和较强的泛化能力Transformer模型则可以利用其强大的序列处理能力,即自注意力机制*,来分析电池充放电过程中的动态变化。通过学习充放电曲线与阻抗谱之间的关系,Transformer模型能够预测不同状态下的阻抗谱,这对于电池状态监测和健康评估非常有用。

在EIS预测中,Transformer模型比基于LSTM的Seq2Seq模型更好,因为Transformer的自注意力机制能够更有效地捕捉充放电曲线中的复杂动态和长距离依赖关系,这对于预测电池的内部电化学过程和老化行为至关重要。此外,Transformer的并行处理能力和灵活性使其在处理大规模和复杂的电池数据集时更加高效和适应性强。

代码
文本

7 参考文献

代码
文本
  1. Vadhva, P., et al., Electrochemical Impedance Spectroscopy for All-Solid-State Batteries: Theory, Methods and Future Outlook. ChemElectroChem, 2021. 8(11): p. 1930-1947.
  2. Dees, D., et al., Electrochemical Modeling of Lithium-Ion Positive Electrodes during Hybrid Pulse Power Characterization Tests. Journal of The Electrochemical Society, 2008. 155(8): p. A603.
  3. Engineeringlaboratory, E.I.N., FreedomCAR Battery Test Manual For Power-Assist Hybrid Electric Vehicles. 2003.
  4. Vivier, V. and M.E. Orazem, Impedance Analysis of Electrochemical Systems. CHEMICAL REVIEWS, 2022. 122(12).
  5. Irvine, J.T.S., D.C. Sinclair, and A.R. West, Electroceramics: Characterization by Impedance Spectroscopy. Advanced Materials, 1990. 2(3): p. 132-138.
  6. Lu, Y., et al., The timescale identification decoupling complicated kinetic processes in lithium batteries. Joule, 2022. 6(6): p. 1172-1198.
  7. Chen, X., et al., Detection of lithium plating in lithium-ion batteries by distribution of relaxation times. Journal of Power Sources, 2021. 496: p. 229867.
  8. Duan, Y., et al., Deep neural network battery impedance spectra prediction by only using constant-current curve. Energy Storage Materials, 2021. 41: p. 24-31.
  9. Sun, Y., et al., Deep neural network based battery impedance spectrum prediction using only impedance at characteristic frequencies. Journal of Power Sources, 2023. 580: p. 233414.
  10. Guo, J., et al., Battery impedance spectrum prediction from partial charging voltage curve by machine learning. Journal of Energy Chemistry, 2023. 79: p. 211-221.
  11. Tian, J., et al., Simultaneous prediction of impedance spectra and state for lithium-ion batteries from short-term pulses. Electrochimica Acta, 2023. 449: p. 142218.
  12. Zhou, X. and J. Huang, Impedance-Based diagnosis of lithium ion batteries: Identification of physical parameters using multi-output relevance vector regression. Journal of Energy Storage, 2020. 31: p. 101629.
  13. Li, Y., et al., Evolution of aging mechanisms and performance degradation of lithium-ion battery from moderate to severe capacity loss scenarios. Chemical Engineering Journal, 2024. 498: p. 155588.
代码
文本

8 组内分工

  1. 代洁宇
  • 代码组成员,完成ANN模型复现与优化部分的【数据集+模型+代码】全流程并参与小组讨论。 1.代码部分:ANN for EIS prediction 2.报告部分:参与小组讨论,参与报告对应部分撰写与修改(第4部分)
  1. 杨子涵:
  • 代码组成员,完成LSTM模型复现与优化部分的【数据集+模型+代码】全流程并参与小组讨论。 1.代码部分:产出三个notebook。 Seq2Seq复现Seq2Seq优化Transformer。2.报告部分:参与小组讨论,参与报告对应部分撰写与修改(第5部分)
  1. 刘泽凯:
  1. 谢玉婷
  • 报告组成员,整理代码部分,完成每个部分的重点梳理,全流程参与小组讨论,并撰写报告。重点完成EIS的介绍与原理部分,国内外文献总结,模型原理讨论与总结部分。
  1. 狄龙邦
  • 报告组成员,全流程参与小组讨论,理清每个代码基于什么来预测EIS,并撰写报告。重点完成机器学习预测EIS的意义与方法。
  1. 刘家彤
  • 报告组成员,报告组成员,全流程参与小组讨论,并辅助报告撰写。重点完成摘要攥写并完成汇报PPT制作与演讲。
代码
文本

备注:报告中代码无法完整运行,完整代码见组内分工处notebook链接。

代码
文本
报告
报告
点个赞吧
{/**/}