init docs

This commit is contained in:
cloud
2026-07-14 09:10:06 +08:00
parent a9b6b1218a
commit abebd2a683
21 changed files with 374 additions and 0 deletions
+226
View File
@@ -0,0 +1,226 @@
import sys
print("Python 解释器路径:", sys.executable)
print("已安装的包路径:", sys.path)
import data
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from pathlib import Path
# ----------------------
# 配置参数
# ----------------------
RAW_DATA_PATH = Path(r'D:\经手项目\数据分析项目\哈萨克斯坦项目\CHUZHIBAO\T01\T01 原始数据.xlsx')
CLEANED_DATA_PATH = Path(r'D:\经手项目\数据分析项目\哈萨克斯坦项目\CHUZHIBAO\T01\T01cleaned_scada_data.xlsx')
#中间保存路径
AFTER_LIMIT_POWER_PATH = Path(r'D:\经手项目\数据分析项目\哈萨克斯坦项目\CHUZHIBAO\T01\T01after_limit_power_cleaning.xlsx')
AFTER_TIP_SPEED_PATH = Path(r'D:\经手项目\数据分析项目\哈萨克斯坦项目\CHUZHIBAO\T01\T01after_tip_speed_cleaning.xlsx')
AFTER_SPEED_POWER_PATH = Path(r'D:\经手项目\数据分析项目\哈萨克斯坦项目\CHUZHIBAO\T01\T01after_speed_power_cleaning.xlsx')
RESULT_TABLE_PATH = Path(r'F:\风速区间功率均值表.xlsx')
RESULT_PLOT_PATH = Path(r'F:\风速功率曲线.png')
RATED_POWER = 4800 # 额定功率
RATED_WIND_SPEED = 18# 额定风速
POWER_STEP = 5
WIND_SPEED_STEP = 0.25 # 风速区间步长
WIND_SPEED_CHANGE_THRESHOLD = 1
#TIME_THRESHOLD = pd.Timedelta(hours=2)
IQR_MULTIPLIER1 = 1.8
IQR_MULTIPLIER2 = 2
MINIMUM_GENERATOR_SPEED = 1
K = 0.9 # k值:删除小于k倍最小发电机转速的点
# ----------------------
# 工具函数:定义保存数据
def save_intermediate_data(data,file_path,step_name):
"""保存中间数据的专用函数,仅做保存"""
try:
if data.empty:
print(f"⚠️{step_name}为空,不保存")
return
#创建目录(如果不存在)
file_path.parent.mkdir(parents=True, exist_ok=True)
#保存数据
data.to_excel(file_path, index=False,engine='openpyxl')
print(f"{step_name}已保存({len(data)}条)至:{file_path}")
except Exception as e:
print(f"❌ 保存{step_name}失败:{str(e)}")
# ----------------------
# 数据清洗函数
# ----------------------
def load_data(file_path):
try:
if not file_path.exists():
raise FileNotFoundError(f"文件不存在: {file_path}")
data = pd.read_excel(file_path, engine='openpyxl')
print(f"成功读取数据,共{len(data)}条记录")
return data
except Exception as e:
print(f"数据读取错误: {str(e)}")
return None
def clean_scada_data(raw_data):
if raw_data is None or raw_data.empty:
print("无数据可清洗")
return None
data = raw_data.copy()
# 1. 基础过滤:删除停机数据
initial_count = len(data)
data = data[data['平均有功功率'] > 0].copy()
#1.5 删除小于最小发电机转速的点
if not data.empty and '平均发电机转速' in data.columns:
# 计算阈值:k倍最小发电机转速
speed_threshold = K * MINIMUM_GENERATOR_SPEED
# 过滤数据
data = data[data['平均发电机转速'] >= speed_threshold].copy()
removed_count = initial_count - len(data)
print(f"发电机转速过滤后保留 {len(data)} 条数据(移除{removed_count}条低转速数据,阈值: {speed_threshold:.2f}")
initial_count = len(data)
# 2. 时间列处理
if '时间' not in data.columns:
print("警告:数据中未找到'时间'列,无法进行限功率点识别")
return data
data['时间'] = pd.to_datetime(data['时间'], errors='coerce')
time_invalid_count = data['时间'].isna().sum()
data = data.dropna(subset=['时间'])
print(f"时间处理后保留 {len(data)} 条数据(移除{time_invalid_count}条无效时间数据)")
# 3. 识别并移除限功率点
if not data.empty:
min_power = data['平均有功功率'].min()
power_intervals = np.arange(min_power, RATED_POWER, POWER_STEP)
limit_power_points = []
for interval in power_intervals:
mask = (data['平均有功功率'] >= interval) & (data['平均有功功率'] < interval + POWER_STEP)
interval_data = data[mask]
if interval_data.empty:
continue
grouped = interval_data.groupby(interval_data['时间'].dt.date)
for date, group in grouped:
group_sorted = group.sort_values('时间')
wind_speed_range = group_sorted['平均风速'].max()-group_sorted['平均风速'].min()
if wind_speed_range > WIND_SPEED_CHANGE_THRESHOLD:
limit_power_points.extend(group_sorted.index)
data = data.drop(limit_power_points,errors='ignore')
print(f"限功率识别后保留{len(data)}条数据(移除{len(limit_power_points)}条限功率数据)")
save_intermediate_data(data,AFTER_LIMIT_POWER_PATH,"限功率清洗后的数据")
# 4. 计算并清洗叶尖速比
if not data.empty and '平均风速' in data.columns :
data = data[data['平均风速'] > 0].copy()
print(f"移除风速为0的数据后保留 {len(data)} 条数据")
data['叶尖速比'] =data['平均发电机转速']*3.14*162*78*30/data['平均风速']
#data['叶尖速比']= data['叶轮转速']*100/data['平均风速']
if not data.empty:
wind_speed_min = data['平均风速'].min()
wind_speed_max = data['平均风速'].max()
wind_speed_intervals = np.arange(wind_speed_min, wind_speed_max, WIND_SPEED_STEP)
cleaned_data_list = []
for interval in wind_speed_intervals:
mask = (data['平均风速'] >= interval) & (data['平均风速'] < interval + WIND_SPEED_STEP)
interval_data = data[mask]
if len(interval_data) >= 4:
q1 = interval_data['叶尖速比'].quantile(0.25)
q3 = interval_data['叶尖速比'].quantile(0.75)
iqr = q3 - q1
lower = q1 - IQR_MULTIPLIER1 * iqr
upper = q3 + IQR_MULTIPLIER2 * iqr
interval_cleaned = interval_data[(interval_data['叶尖速比'] >= lower) &
(interval_data['叶尖速比'] <= upper)]
else:
interval_cleaned = interval_data
cleaned_data_list.append(interval_cleaned)
data = pd.concat(cleaned_data_list)
print(f"叶尖速比清洗后保留 {len(data)} 条数据")
save_intermediate_data(data,AFTER_TIP_SPEED_PATH,"叶尖速比清洗后的数据")
# 5. 风速-功率关系清洗
if not data.empty and '平均风速' in data.columns and '平均有功功率' in data.columns:
wind_speed_min = data['平均风速'].min()
wind_speed_max = data['平均风速'].max()
wind_speed_intervals = np.arange(wind_speed_min, wind_speed_max, WIND_SPEED_STEP)
final_cleaned_list = []
for interval in wind_speed_intervals:
mask = (data['平均风速'] >= interval) & (data['平均风速'] < interval + WIND_SPEED_STEP)
interval_data = data[mask]
if len(interval_data) >= 4:
q1 = interval_data['平均有功功率'].quantile(0.25)
q3 = interval_data['平均有功功率'].quantile(0.75)
iqr = q3 - q1
lower_limit = q1 - IQR_MULTIPLIER1 * iqr
upper_limit = q3 + IQR_MULTIPLIER2 * iqr
interval_cleaned = interval_data[(interval_data['平均有功功率'] >= lower_limit) &
(interval_data['平均有功功率'] <= upper_limit)]
else:
interval_cleaned = interval_data
final_cleaned_list.append(interval_cleaned)
data = pd.concat(final_cleaned_list)
print(f"风速-功率清洗后保留 {len(data)} 条数据")
save_intermediate_data(data, AFTER_SPEED_POWER_PATH, "风速功率清洗后的数据")
# 6. 高风速区二次过滤
#if not data.empty and '平均风速' in data.columns:
#high_wind_mask = data['平均风速'] >= RATED_WIND_SPEED
#high_wind_data = data[high_wind_mask]
#if len(high_wind_data) > 0:
#robust_mean = high_wind_data['平均有功功率'].median()
#high_wind_filtered = high_wind_data[
#(high_wind_data['平均有功功率'] >= robust_mean * 0.98) &
#(high_wind_data['平均有功功率'] <= robust_mean * 1.02)
#]
#low_wind_data = data[~high_wind_mask]
#data = pd.concat([low_wind_data, high_wind_filtered])
#print(f"高风速区二次过滤后保留 {len(data)} 条数据")
return data
# ----------------------
# 主程序:执行数据清洗并保存结果
# ----------------------
if __name__ == "__main__":
# 加载原始数据
raw_data = load_data(RAW_DATA_PATH)
# 清洗数据
cleaned_data = clean_scada_data(raw_data)
# 保存清洗后的数据到指定路径
if cleaned_data is not None and not cleaned_data.empty:
try:
# 创建保存目录(如果不存在)
CLEANED_DATA_PATH.parent.mkdir(parents=True, exist_ok=True)
# 保存为Excel文件
cleaned_data.to_excel(CLEANED_DATA_PATH, index=False, engine='openpyxl')
print(f"清洗后的数据已成功保存到: {CLEANED_DATA_PATH}")
except Exception as e:
print(f"保存数据时出错: {str(e)}")
else:
print("没有可保存的清洗后数据")
@@ -0,0 +1,148 @@
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from pathlib import Path
# ----------------------
# 配置参数
# ----------------------
RAW_DATA_PATH = Path(r'H:\尽调项目\和展清云洛阳项目\6#\6 处理后.xlsx')
RESULT_TABLE_PATH = Path(r'H:\尽调项目\和展清云洛阳项目\6#\6风速区间功率均值表.xlsx')
RESULT_PLOT_PATH = Path(r'H:\尽调项目\和展清云洛阳项目\6#\6风速功率曲线.png')
RATED_POWER = 6700 # 额定功率
RATED_WIND_SPEED = 18 # 额定风速
POWER_STEP = 5
WIND_SPEED_STEP = 0.5 # 风速区间步长
WIND_SPEED_CHANGE_THRESHOLD = 1
#TIME_THRESHOLD = pd.Timedelta(hours=2)
IQR_MULTIPLIER = 1.5
MIN_DATA_COUNT = 3
def load_data(file_path):
try:
if not file_path.exists():
raise FileNotFoundError(f"文件不存在: {file_path}")
data = pd.read_excel(file_path, engine='openpyxl')
print(f"成功读取数据,共{len(data)}条记录")
return data
except Exception as e:
print(f"数据读取错误: {str(e)}")
return None
def clean_scada_data(raw_data):
if raw_data is None or raw_data.empty:
print("无数据可清洗")
return None
data = raw_data.copy()
# ----------------------
# 区间功率均值计算与可视化(核心修改部分)
# ----------------------
def calculate_interval_power_mean(raw_data, wind_speed_step=0.5):
"""按风速区间计算功率平均值,区间采用左开右闭形式 (start, end]"""
if raw_data is None or raw_data.empty:
print("无清洗后的数据可计算均值")
return None
# 确定风速区间范围
wind_min = 1 - wind_speed_step*0.5
wind_max = 25 + wind_speed_step*0.5
# 生成区间起点
wind_intervals = np.arange(wind_min, wind_max, wind_speed_step)
# 计算每个区间的平均功率(核心修改:使用左开右闭区间 (start, end]
result = []
for interval_start in wind_intervals:
interval_end = interval_start + wind_speed_step
# 关键修改:左边界>,右边界≤
mask = (raw_data['平均风速'] > interval_start) & (raw_data['平均风速'] <= interval_end)
interval_data = raw_data[mask]
if not interval_data.empty:
wind_mid = (interval_start + interval_end) / 2 # 区间中点
power_mean = interval_data['平均有功功率'].mean()
result.append({
'风速区间起点': interval_start,
'风速区间终点': interval_end,
'风速': wind_mid,
'实际功率': power_mean,
'区间数据量': len(interval_data),
})
# 转换为DataFrame并按风速排序
result_df = pd.DataFrame(result).sort_values('风速').reset_index(drop=True)
print(f"已计算{len(result_df)}个风速区间的功率平均值(左开右闭区间)")
return result_df
def plot_power_curve(result_df, rated_power, rated_wind_speed, save_path):
"""绘制风速-功率曲线并保存图片"""
if result_df is None or result_df.empty:
print("无数据可绘制曲线")
return False
plt.style.use('seaborn-v0_8-talk')
fig, ax = plt.subplots(figsize=(12, 6))
# 绘制功率曲线
ax.plot(result_df['风速'], result_df['实际功率'],
color='#2c7fb8', linewidth=2.5, marker='o', markersize=5,
label='实际功率曲线')
# 绘制额定功率参考线
ax.axhline(y=rated_power, color='#e41a1c', linestyle='--', linewidth=1.5,
label=f'额定功率 ({rated_power}kW)')
# 绘制额定风速参考线
ax.axvline(x=rated_wind_speed, color='#4daf4a', linestyle='-.', linewidth=1.5,
label=f'额定风速 ({rated_wind_speed}m/s)')
# 设置坐标轴标签和标题
ax.set_xlabel('风速 (m/s)', fontsize=12)
ax.set_ylabel('功率 (kW)', fontsize=12)
ax.set_title('风速-功率曲线(左开右闭区间平均值)', fontsize=14, pad=20)
# 添加网格和图例
ax.grid(alpha=0.3)
ax.legend(fontsize=10)
# 调整布局并保存
plt.tight_layout()
plt.savefig(save_path, dpi=300, bbox_inches='tight')
plt.close()
print(f"功率曲线已保存至 {save_path}")
return True
# ----------------------
# 主程序执行
# ----------------------
if __name__ == "__main__":
# 1. 读取并清洗数据
raw_data = load_data(RAW_DATA_PATH)
# 2. 计算风速区间功率平均值(左开右闭区间)
interval_power_df = calculate_interval_power_mean(raw_data, wind_speed_step=WIND_SPEED_STEP)
# 3. 保存结果表格
if interval_power_df is not None:
try:
RESULT_TABLE_PATH.parent.mkdir(parents=True, exist_ok=True)
interval_power_df.to_excel(RESULT_TABLE_PATH, index=False)
print(f"风速区间功率均值表已保存至 {RESULT_TABLE_PATH}")
except Exception as e:
print(f"保存表格失败:{str(e)}")
# 4. 绘制并保存功率曲线图片
if interval_power_df is not None:
plot_power_curve(interval_power_df, RATED_POWER, RATED_WIND_SPEED, RESULT_PLOT_PATH)