基于深度学习的电池健康状态预测(Python)

news2024/12/26 21:21:52

电池的故障预测和健康管理PHM是为了保障设备或系统的稳定运行,提供参考的电池健康管理信息,从而提醒决策者及时更换电源设备。不难发现,PHM的核心问题就是确定电池的健康状态,并预测电池剩余使用寿命。但是锂电池的退化过程影响因素众多,不仅受其本身工作模式的影响,外部环境的压力、温度等都会影响锂电池的退化。这些影响因素之间的相互耦合,导致锂电池的退化表现出很强的非线性及不确定性,这给SOH估计和RUL预测带来了很大的困难。

该项目代码较简单,主要包括Capacity predict,RUL predict,Trends predic,以Capacity predict为例,首先加载模块。

import torchimport torch.nn as nnimport torch.optim as optimimport torch.nn.functional as F from torch.utils.data import DataLoader, TensorDataset
import pandas as pdimport numpy as npimport osimport matplotlib.pyplot as pltimport warningswarnings.filterwarnings("ignore")device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")Debug = False

模型定义

# 定义LSTM模型class LSTMModel(nn.Module):    def __init__(self, conv_input, input_size, hidden_size, num_layers, output_size):        super(LSTMModel, self).__init__()        self.conv=nn.Conv1d(conv_input,conv_input,1)        self.lstm = nn.LSTM(input_size, hidden_size, num_layers, batch_first=True, bidirectional=True).to(device)                #self.fc1 = nn.Linear(hidden_size*2, hidden_size*2)        self.fc = nn.Linear(hidden_size, output_size)        self.num_layers = num_layers        self.hidden_dim = hidden_size        self.dropout = nn.Dropout(p=0.3)
    def forward(self, x):        x=self.conv(x)                h0 = torch.randn((self.num_layers, x.shape[0], self.hidden_dim)).to(device) # 初始化隐藏状态        c0 = torch.randn((self.num_layers, x.shape[0], self.hidden_dim)).to(device) # 初始化细胞状态                output, _ = self.lstm(x,(h0,c0))        output = self.dropout(output)        output = self.fc(output[:, -1, :])         return output

导入数据

# 创建一个空列表来存储读取的 DataFramesdataframes_Cap = []dataframes_EIS = []
# 使用循环读取文件并分配名称for i in range(1, 9):    # 构建文件名    file_name_cap= f"Capacity_data/Data_Capacity_25C{i:02}.txt"    file_name_EIS = f"EIS_data/EIS_state_V_25C{i:02}.txt"  # 使用状态V            if not os.path.isfile(file_name_cap):        print(f"Cap文件 {file_name_cap} 不存在,跳过...")        continue    elif not os.path.isfile(file_name_EIS):        print(f"EIS文件 {file_name_EIS} 不存在,跳过...")        continue
    # 读取文件并添加到列表    df_cap = pd.read_csv(file_name_cap, sep="\t")    df_EIS = pd.read_csv(file_name_EIS, sep="\t")    #print(df_cap.columns)        if i == 1 or i==5:        cap_number = 3    else:        cap_number = 5        #剔除表现不佳的电池    if i == 4 or i == 8:        continue    cycle = []    cap = []    eis = []    cycle_max = df_cap[df_cap.columns[1]].max()    cycle_max2 = df_EIS[df_EIS.columns[1]].max()    cycle_number = min(cycle_max,cycle_max2)        max_scale = df_cap[df_cap[df_cap.columns[1]]==0][df_cap.columns[cap_number]][:].max()    for i in range(1,int(cycle_number)+1):        temp = df_cap[df_cap[df_cap.columns[1]]==i][df_cap.columns[cap_number]][-1:].max()        temp_EIS_Re = np.array(df_EIS[df_EIS[df_EIS.columns[1]]==i][df_EIS.columns[3]][:])        temp_EIS_Im = np.array(df_EIS[df_EIS[df_EIS.columns[1]]==i][df_EIS.columns[4]][:])        cycle.append(i)        cap.append(temp)        eis.append(np.concatenate((temp_EIS_Re, temp_EIS_Im), axis=0))    dataframes_Cap.append(cap)    dataframes_EIS.append(eis)​​​​​
#将35数据读入
# 使用循环读取文件并分配名称for i in range(1, 3):    # 构建文件名    file_name_cap= f"Capacity_data/Data_Capacity_35C{i:02}.txt"    file_name_EIS = f"EIS_data/EIS_state_V_35C{i:02}.txt"  # 使用状态V            if not os.path.isfile(file_name_cap):        print(f"Cap文件 {file_name_cap} 不存在,跳过...")        continue    elif not os.path.isfile(file_name_EIS):        print(f"EIS文件 {file_name_EIS} 不存在,跳过...")        continue
    # 读取文件并添加到列表    df_cap = pd.read_csv(file_name_cap, sep="\t")    df_EIS = pd.read_csv(file_name_EIS, sep="\t")    cap_number = 3        cycle = []    cap = []    eis = []    cycle_max = df_cap[df_cap.columns[1]].max()    cycle_max2 = df_EIS[df_EIS.columns[1]].max()    cycle_number = min(cycle_max,cycle_max2)            #max_scale = df_cap[df_cap[df_cap.columns[1]]==1][df_cap.columns[cap_number]][-1:].max()    for i in range(1,int(cycle_number)+1):        temp = df_cap[df_cap[df_cap.columns[1]]==i][df_cap.columns[cap_number]][-1:].max()        temp_EIS_Re = np.array(df_EIS[df_EIS[df_EIS.columns[1]]==i][df_EIS.columns[3]][:])        temp_EIS_Im = np.array(df_EIS[df_EIS[df_EIS.columns[1]]==i][df_EIS.columns[4]][:])        #temp = temp/max_scale        cycle.append(i)        cap.append(temp)        eis.append(np.concatenate((temp_EIS_Re, temp_EIS_Im), axis=0))
    dataframes_Cap.append(cap)    dataframes_EIS.append(eis)
#将45数据读入for i in range(1, 3):    # 构建文件名    file_name_cap= f"Capacity_data/Data_Capacity_45C{i:02}.txt"    file_name_EIS = f"EIS_data/EIS_state_V_45C{i:02}.txt"  # 使用状态V            if not os.path.isfile(file_name_cap):        print(f"Cap文件 {file_name_cap} 不存在,跳过...")        continue    elif not os.path.isfile(file_name_EIS):        print(f"EIS文件 {file_name_EIS} 不存在,跳过...")        continue
    # 读取文件并添加到列表    df_cap = pd.read_csv(file_name_cap, sep="\t")    df_EIS = pd.read_csv(file_name_EIS, sep="\t")    #print(df_cap.columns)    cap_number = 3        cycle = []    cap = []    eis = []    cycle_max = df_cap[df_cap.columns[1]].max()    cycle_max2 = df_EIS[df_EIS.columns[1]].max()    cycle_number = min(cycle_max,cycle_max2)            #max_scale = df_cap[df_cap[df_cap.columns[1]]==1][df_cap.columns[cap_number]][-1:].max()    for i in range(1,int(cycle_number)+1):        temp = df_cap[df_cap[df_cap.columns[1]]==i][df_cap.columns[cap_number]][-1:].max()        temp_EIS_Re = np.array(df_EIS[df_EIS[df_EIS.columns[1]]==i][df_EIS.columns[3]][:])        temp_EIS_Im = np.array(df_EIS[df_EIS[df_EIS.columns[1]]==i][df_EIS.columns[4]][:])        #temp = temp/max_scale        cycle.append(i)        cap.append(temp)        eis.append(np.concatenate((temp_EIS_Re, temp_EIS_Im), axis=0))    dataframes_Cap.append(cap)    dataframes_EIS.append(eis)

​​​​​​​

X = []y = []for i in range(0,len(dataframes_Cap)):    for j in range(len(dataframes_Cap[i])):        X.append(dataframes_EIS[i][j])        y.append(dataframes_Cap[i][j])X = np.array(X)y = np.array(y)print(X.shape,y.shape)

​​​​​​​

# 将EIS的每个实部和每个虚部分别各自归一化remax = []immax = []data={}from sklearn.preprocessing import MinMaxScalerscaler = MinMaxScaler()y = y.reshape(-1,1)# 对标签也进行归一化y = scaler.fit_transform(y)# 将每份电池单独制作,便于交叉训练和验证, start = 0for i in range(len(dataframes_Cap)):    feature_name = f'EIS{i+1:02}'    target_name = f'Cap{i+1:02}'    n = len(dataframes_Cap[i])    X_r = X[start:start+n,:60].copy()#将实部整体进行归一化    X_r_flat = X_r.flatten()    #取第一个EIS的最大最小值进行归一    X_r_min = X_r_flat[:60].min()        X_r_max = X_r_flat[:60].max()    remax.append(X_r_flat[:].max()/X_r_max)    normalized_Xr_flat = ((X_r_flat.reshape(-1, 1))-X_r_min)/(X_r_max-X_r_min)    normalized_Xr_data = normalized_Xr_flat.reshape(X[start:start+n,:60].shape)    #将虚部进行归一化    X_i = X[start:start+n,60:]    X_i_flat = X_i.flatten()    X_i_min = X_i_flat[:60].min()    X_i_max = X_i_flat[:60].max()
    immax.append(X_i_flat[:].max()/X_i_max)    normalized_Xi_flat = ((X_i_flat.reshape(-1, 1))-X_i_min)/(X_i_max-X_i_min)    normalized_Xi_data = normalized_Xi_flat.reshape(X[start:start+n,60:].shape)    data[feature_name] = np.concatenate((normalized_Xr_data, normalized_Xi_data), axis=1)    data[feature_name] = data[feature_name].reshape(-1,2, 60)#将数据形式转换为(batch,60,2),实部和虚部作为一个整体特征    data[feature_name] = data[feature_name].transpose(0, 2, 1)    data[target_name] = y[start:start+n].reshape(-1,1)    start += n​​​​​​​
if Debug:    # 检查数据效果    for i in range(15,20):        x_plot = data["EIS01"][i][:60]        y_plot = data["EIS01"][i][60:]        plt.plot(x_plot, y_plot)    plt.show()

​​​​​​​

if Debug:    # 检查数据效果    for i in range(15,20):        x_plot = data["Cap02"][:]        plt.plot(x_plot)    plt.show()​​​​​​
start = 0for i in range(1,11):    if i == 1:        trainning_data = data[f"EIS{i:02}"][start:].copy()        trainning_target = data[f"Cap{i:02}"][start:].copy()    #剔除测试集    elif i!=4 and i!= 8 and i!= 10:    #else:        trainning_data = np.vstack((trainning_data,data[f"EIS{i:02}"][start:]))        trainning_target = np.vstack((trainning_target,data[f"Cap{i:02}"][start:]))

​​​​​​​

trainning_data = torch.tensor(trainning_data, dtype=torch.float32)trainning_target = torch.tensor(trainning_target, dtype=torch.float32)

开始训练

​​​​​​​

# 初始化模型、损失函数和优化器input_size = 2 # 特征数量hidden_size = 128num_layers = 5output_size = 1conv_input = 60batch_size = 128epochs = 1500n_splits = 5

from sklearn.model_selection import KFold
import gcdef gc_collect():    gc.collect()    torch.cuda.empty_cache()gc_collect()​​​​​​​
kf = KFold(n_splits=n_splits, shuffle=True)
model_number = 0for train_idx, val_idx in kf.split(trainning_data):      train_X, val_X = trainning_data[train_idx], trainning_data[val_idx]      train_y, val_y = trainning_target[train_idx], trainning_target[val_idx]      train_dataset = TensorDataset(train_X, train_y)      val_dataset = TensorDataset(val_X, val_y)      train_loader = DataLoader(train_dataset, batch_size=batch_size, shuffle=True)      val_loader = DataLoader(val_dataset, batch_size=batch_size, shuffle=False)      model = LSTMModel(conv_input, input_size, hidden_size, num_layers, output_size)     model = model.to(device)    criterion = nn.MSELoss()       optimizer = optim.Adam(model.parameters(), lr=0.0001,betas=(0.5,0.999))           for epoch in range(epochs):        model.train()         for i, (inputs, labels) in enumerate(train_loader):              inputs = inputs.to(device)            labels = labels.to(device)            optimizer.zero_grad()              outputs = model(inputs)              loss = criterion(outputs, labels)              loss.backward()              optimizer.step()          model.eval()        with torch.no_grad():            for inputs, labels in val_loader:                inputs = inputs.to(device)                labels = labels.to(device)                outputs = model(inputs)                  val_loss = criterion(outputs, labels)            if epoch%100 ==0:            print(f'Epoch [{epoch+1}/{epochs}], Loss: {loss.item()}, Validation Loss: {val_loss.item()}')     torch.save(model.state_dict(), f"model_weights/CNNBiLSTM/test{model_number}.pth")    model_number += 1

​​​​​​​

from sklearn.metrics import mean_squared_errorfrom sklearn.metrics import r2_scoreimport math
# 创建画布  fig, axs = plt.subplots(nrows=3, ncols=4, figsize=(15, 8))  ID = 1title_name = 1start = 0mean_RMSE_train = 0mean_RMSE_test = 0mean_R2_train = 0mean_R2_test = 0model = LSTMModel(conv_input, input_size, hidden_size, num_layers, output_size) model = model.to(device)
# 在每个小区域中绘制图像  for i in range(3):      for j in range(4):        result = []        x = torch.tensor(data[f"EIS{ID:02}"], dtype=torch.float32)        for k in range(n_splits):            model.load_state_dict(torch.load(f"model_weights/CNNBiLSTM/test{k}.pth",                                              map_location=torch.device(device)))            out = model(x.to(device))            out = out.cpu()            out = out.detach().numpy()            out = scaler.inverse_transform(out)            result.append(out)        result = np.array(result)        out = np.mean(result, axis=0)        out_upper = np.max(result, axis=0)        out_upper = np.squeeze(out_upper)        out_lower = np.min(result, axis=0)        out_lower = np.squeeze(out_lower)        true = data[f"Cap{ID:02}"]        true = scaler.inverse_transform(true)        MSE = mean_squared_error(out[start:], true[start:])         R2_result = r2_score(true[start:], out[start:])         RMSE_result = math.sqrt(MSE)        mean_RMSE_train += RMSE_result        mean_R2_train += R2_result        RMSE_str = "{:.4f}".format(RMSE_result)        R2_str = "{:.4f}".format(R2_result)        x = np.linspace(0,x.shape[0],x.shape[0])        axs[i, j].plot(x[start:], true[start:])        axs[i, j].plot(x[start:], out[start:])        axs[i, j].fill_between(x[start:], out_upper[start:], out_lower[start:], color='orange', alpha=0.5)        axs[i, j].set_title(f"25Cap{title_name:02}")        axs[i, j].text(0.95, 0.95, "RMSE: "+ RMSE_str, ha='right', va='top', fontsize=12, transform=axs[i, j].transAxes)        axs[i, j].text(0.95, 0.85, "R2: "+ R2_str, ha='right', va='top', fontsize=12, transform=axs[i, j].transAxes)         # 使用循环将数组中的每个元素写入文件        with open(f"data/Nature_Cap_train{title_name:02}", 'w') as file:            for item in range(out[start:].shape[0]):                out_number = round(float(out[start:][item].flatten()), 4)                #file.write(str(out_number) + '\t'+str(out_upper[start:][item])+ '\t'+str(out_lower[start:][item])+ '\n')                file.write(str(out_number)+'\n')        # 关闭文件        file.close()        ID += 1        title_name += 1        if ID == 11:            break


# 调整子图之间的距离  plt.tight_layout()plt.savefig('figure_results/cap_alltempalldata_test_5_10_12.png')print("train RMSE: ", mean_RMSE_train/8)print("train R2: ", mean_R2_train/8)  # 显示图像  plt.show()

图片

RUL预测结果:

图片

图片

图片

图片

Trends预测结果

图片

担任《Mechanical System and Signal Processing》《中国电机工程学报》《控制与决策》等期刊审稿专家,擅长领域:现代信号处理,机器学习,深度学习,数字孪生,时间序列分析,设备缺陷检测、设备异常检测、设备智能故障诊断与健康管理PHM等。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1814572.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Golang——gRPC认证

一. OpenSSL 1.1 介绍 OpenSSL是一个开放源代码的软件库包,用于支持网络通讯过程中的加密。这个库提供的功能包含了SSL和TLS协议的实现,并可用于生成密钥、证书、进行密码运算等。 其组成主要包括一下三个组件: openssl:多用途的命…

智能售货机的成功关键点

智能售货机的成功关键点 智能售货机的盈利水平是众多投资者关注的焦点。尽管常有人认为该行业利润丰厚,但实际上,智能售货机的利润率通常维持在一个相对适中的范围,大约在5%至15%之间。这一数据背后,涵盖了包括物流配送、日常运维…

Java---BigInteger和BigDecimal和枚举

1.简介 1.BigInteger可以支持任意长度的整数 2.BigDecimal可以支持任意精度的浮点数 3.用来做精确计算 2.创建方式 new BigInteger(); new BigInteger(参数1,进制):可以将不同进制转成10进制显示 new BigDecimal(); BigInteger.valueOf(); BigDecimal.valueOf();…

transformers之text generation解码策略

目录 参数TemperatureTop-p and Top-k1. 选择最上面的token:贪婪解码2. 从最上面的tokens中选择:top-k3. 从概率加起来为15%的top token中选择:top-pFrequency and Presence Penaltiestransformers库中的解码策略贪婪搜索对比搜索多项式采样beam搜索解码beam搜索多项式采样多样…

中国大模型站起来了!甚至被美国团队反向抄袭

一直以来,美国是公认的AI领域强者,我国AI技术虽然差不多,但始终落人一步。然而,近日斯坦福团队的AI模型却被指控抄袭中国AI模型,这下许多人都坐不住了。 被实锤抄袭的,是斯坦福大学AI团队,他们…

WWDC 2024及其AI功能的引入对中国用户和开发者的影响

WWDC(Apple Worldwide Developers Conference)是苹果公司一年一度的重要活动,吸引了全球开发者的关注。WWDC 2024引入了许多新技术和功能,尤其是AI功能的加入,引发了广泛讨论。本文将深入探讨中国开发者如何看待WWDC 2…

四川赤橙宏海商务信息咨询有限公司揭秘抖音电商新风口

在数字化浪潮席卷全球的今天,电商行业作为新时代经济的生力军,正以前所未有的速度发展。作为抖音电商服务的佼佼者,四川赤橙宏海商务信息咨询有限公司凭借其专业的服务团队和前瞻的市场洞察,不断刷新行业纪录,助力商家…

docker安装rabbitmq和延迟插件(不废话版)

1.下载镜像 docker pull rabbitmq:3.8-management 2.启动 docker run -e RABBITMQ_DEFAULT_USERlicoos -e RABBITMQ_DEFAULT_PASSlicoosrabbitmq -v mq-plugins:/plugins --name mq --hostname mq -p 15672:15672 -p 5672:5672 -d rabbitmq:3.8-management 3.下载对…

跨海交流丨台湾混凝土行业参访团与上海思伟软件共筑“智慧砼厂”梦 !

每一次跨越地域的握手 都是行业革新与智慧交融的序曲 台湾优质混凝土参访团 2024年5月29日,财团法人台湾营建研究院院长吕良正先生,率领着由61名行业精英组成的台湾商砼参访团,跨越海峡抵达上海,开展了一场连接两岸的学习交流活动…

苹果的股票都飙升7%了,谷歌仍在建议你往披萨上加胶水|TodayAI

最近,谷歌(Google)的人工智能再次引发了一场笑话。这次,它建议用户在披萨上添加胶水,引起了广泛关注和讨论。事情的起因源自一位互联网传奇人物Katie Notopoulos,她实际上制作并食用了一个胶水披萨&#xf…

【源码】2024最新陪诊小程序uniapp+thinkphp

20 2024最新陪诊小程序uniappthinkphp资源来源:52codes.cc 20最新陪诊小程序uniappthinkphp 简介:随着社会逐渐步进入老龄化越来越多的老年人或者不经常去医院的用户对于医院繁琐的流程很是苦劳于是陪诊这个行业开始兴起。小白陪诊开发理念&#xff0…

PS2045L-ASEMI低Low VF肖特基PS2045L

编辑:ll PS2045L-ASEMI低Low VF肖特基PS2045L 型号:PS2045L 品牌:ASEMI 封装:TO-277 最大平均正向电流(IF):20A 最大循环峰值反向电压(VRRM):45V 最大…

CVE-2019-20933-influxdb未授权访问-vulhub

1.原理 参考:https://blog.csdn.net/tqlisno1/article/details/109110644 InfluxDB 未授权访问 漏洞复现_influxdb未授权访问复现-CSDN博客 InfluxDB 是一个开源分布式时序、时间和指标数据库,使用 Go 语言编写,无需外部依赖。其设计目标是…

铝合金板件加工迎来3D视觉新时代

在制造业的浩瀚星空中,铝合金板件加工一直以其轻质、高强度、耐腐蚀的特性,扮演着举足轻重的角色。然而,随着市场竞争的加剧和产品需求的多样化,传统的加工方式已难以满足现代制造业对高效率、高精度的追求。在这个关键时刻&#…

【Java】解决Java报错:ArithmeticException during Division

文章目录 引言一、ArithmeticException的定义与概述1. 什么是ArithmeticException?2. ArithmeticException的常见触发场景3. 示例代码 二、解决方案1. 检查除数是否为零2. 使用异常处理3. 使用浮点数除法4. 使用自定义方法进行安全除法 三、最佳实践1. 始终检查除数…

RAG实操教程,LangChain + Llama2 | 创造你的个人LLM

本文将逐步指导您创建自己的RAG(检索增强生成)系统,使您能够上传自己的PDF文件并向LLM询问有关PDF的信息。本教程侧重于图中蓝色部分,即暂时不涉及Gradio(想了解已接入Gradio的,请参考官网)。相…

计算机网络-BGP路由优选原则四-优选AS_Path属性值最短的路由

一、优选AS_Path属性值最短的路由 AS_Path:这是BGP中最重要的属性之一,它记录了路由信息经过的所有自治系统。AS_Path属性帮助接收路由信息的路由器了解该路由的来源和路径。AS_Path由一系列的自治系统号组成,这些自治系统号代表了路由信息在…

SAP PP学习笔记17 - MTS(Make-to-Stock) 按库存生产 的策略70,策略59

上几章讲了几种策略,策略10,11,30,40。 SAP PP学习笔记14 - MTS(Make-to-Stock) 按库存生产(策略10),以及生产计划的概要-CSDN博客 SAP PP学习笔记15 - MTS(Make-to-St…

架构设计-跨域问题的根源及解决方式

前面文章《架构设计-web项目中跨域问题涉及到的后端和前端配置》中说明了处理跨域问题的一种方式,本文详细说明下产生跨域问题的原因及处理方式。 一、产生跨域问题的原因: 浏览器的同源策略:这是跨域问题的根本原因。同源策略是浏览器对Jav…

C语言 sizeof 和 strlen

目录 一、sizeof 和 strlen 的区别 a.sizeof b.strlen c.sizeof与strlen的区别 二、数组和指针笔试题解析(32位环境) a.一维数组( int a[ ] { 1 , 2 , 3 , 4 } ) b.字符数组 (char arr[ ] {a , b , c , d , e , f }) ( char arr[ …