如何用Python检测电池电压数据循环且避免数据丢失?
电池电压循环检测方案
针对电池电压的循环检测,核心是基于电压的**趋势变化(上升/下降/平稳)**识别完整充放电周期,同时通过插值替代过滤来避免数据丢失。以下是具体实现步骤和代码:
步骤1:数据预处理(避免丢失数据)
先将时间列转为datetime类型,用线性插值填充缺失值,确保时间序列连续:
import pandas as pd import plotly.express as px import numpy as np # 读取数据 dfm = pd.read_excel(r"C:\Users\Desktop\range\Battery Voltage.xlsx") # 转换时间列并设置为索引,保证时序有序 dfm['date_time'] = pd.to_datetime(dfm['date_time']) dfm = dfm.set_index('date_time').sort_index() # 用线性插值填充缺失值(替代过滤,避免数据丢失) dfm['External Voltage'] = dfm['External Voltage'].interpolate(method='linear')
步骤2:计算电压趋势(上升/下降/平稳)
通过计算相邻时刻的电压差分,结合噪声阈值判断每个数据点的趋势:
# 计算电压差分(当前值-前一个值) dfm['voltage_diff'] = dfm['External Voltage'].diff() # 设置噪声阈值(根据数据实际波动调整,示例为0.01V) threshold = 0.01 # 标记每个点的趋势 dfm['trend'] = np.where(dfm['voltage_diff'] > threshold, '上升', np.where(dfm['voltage_diff'] < -threshold, '下降', '平稳')) # 处理第一个数据点的空值 dfm['trend'].fillna('平稳', inplace=True)
步骤3:合并连续的相同趋势段
将连续的相同趋势合并为区间,方便后续识别循环:
# 标记趋势段分组:趋势变化时分组编号+1 dfm['trend_group'] = (dfm['trend'] != dfm['trend'].shift(1)).cumsum() # 统计每个趋势段的关键信息 trend_segments = dfm.groupby('trend_group').agg( start_time=('date_time', 'first'), end_time=('date_time', 'last'), trend=('trend', 'first'), avg_voltage=('External Voltage', 'mean'), duration=('date_time', lambda x: (x.max() - x.min()).total_seconds()/3600) # 转换为小时 ).reset_index()
步骤4:识别完整充放电循环
根据趋势序列(比如下降→平稳→上升→平稳)判定完整循环,也可根据实际数据调整循环判定逻辑:
# 提取趋势序列 trend_sequence = trend_segments['trend'].tolist() # 检测符合"下降→平稳→上升→平稳"的完整循环 cycle_count = 0 cycle_intervals = [] for i in range(len(trend_sequence)-3): if (trend_sequence[i] == '下降' and trend_sequence[i+1] == '平稳' and trend_sequence[i+2] == '上升' and trend_sequence[i+3] == '平稳'): cycle_count += 1 cycle_intervals.append({ 'cycle_num': cycle_count, 'start_time': trend_segments.loc[i, 'start_time'], 'end_time': trend_segments.loc[i+3, 'end_time'], 'min_voltage': dfm.loc[trend_segments.loc[i, 'start_time']:trend_segments.loc[i+3, 'end_time'], 'External Voltage'].min(), 'max_voltage': dfm.loc[trend_segments.loc[i, 'start_time']:trend_segments.loc[i+3, 'end_time'], 'External Voltage'].max() }) # 转换为DataFrame查看结果 cycle_df = pd.DataFrame(cycle_intervals) print(f"检测到的循环数量:{cycle_count}") print(cycle_df)
步骤5:可视化循环标记
用Plotly在原始电压曲线上标记出每个循环区间:
# 绘制原始电压曲线 fig = px.line(dfm, x=dfm.index, y='External Voltage', title='电池电压与循环标记') # 为每个循环添加区间高亮和标注 for idx, row in cycle_df.iterrows(): fig.add_vrect( x0=row['start_time'], x1=row['end_time'], fillcolor=f'rgba(255, 0, 0, {0.1*(idx%5+1)})', annotation_text=f"循环{row['cycle_num']}", annotation_position="top left" ) fig.show()
关键说明
- 阈值调整:
threshold需根据数据实际波动情况修改,避免将噪声误判为趋势变化。 - 循环定义:若你的循环是其他模式(比如直接下降→上升无静置),可修改循环检测的条件。
- 数据保留:用线性插值替代过滤,最大程度保留原始数据的同时处理缺失值。
内容的提问来源于stack exchange,提问作者appu
相关产品推荐
相关产品推荐

