diff --git a/docs/基于风电机组控制原理的风功率数据识别与清洗方法.pdf b/docs/基于风电机组控制原理的风功率数据识别与清洗方法.pdf new file mode 100644 index 0000000..1000d63 Binary files /dev/null and b/docs/基于风电机组控制原理的风功率数据识别与清洗方法.pdf differ diff --git a/docs/大于4行时保留数据.py b/docs/大于4行时保留数据.py new file mode 100644 index 0000000..75c9f83 --- /dev/null +++ b/docs/大于4行时保留数据.py @@ -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("没有可保存的清洗后数据") \ No newline at end of file diff --git a/docs/完整年数据/01_2024-09-01_14-00-00-2025-09-01_14-00-00_风机历史数据.xls b/docs/完整年数据/01_2024-09-01_14-00-00-2025-09-01_14-00-00_风机历史数据.xls new file mode 100644 index 0000000..7d48a5d Binary files /dev/null and b/docs/完整年数据/01_2024-09-01_14-00-00-2025-09-01_14-00-00_风机历史数据.xls differ diff --git a/docs/完整年数据/02_2024-09-01_14-00-00-2025-09-01_14-00-00_风机历史数据.xls b/docs/完整年数据/02_2024-09-01_14-00-00-2025-09-01_14-00-00_风机历史数据.xls new file mode 100644 index 0000000..8cc4823 Binary files /dev/null and b/docs/完整年数据/02_2024-09-01_14-00-00-2025-09-01_14-00-00_风机历史数据.xls differ diff --git a/docs/完整年数据/03_2024-09-01_14-00-00-2025-09-01_14-00-00_风机历史数据.xls b/docs/完整年数据/03_2024-09-01_14-00-00-2025-09-01_14-00-00_风机历史数据.xls new file mode 100644 index 0000000..d5a2e5f Binary files /dev/null and b/docs/完整年数据/03_2024-09-01_14-00-00-2025-09-01_14-00-00_风机历史数据.xls differ diff --git a/docs/完整年数据/04_2024-09-01_14-00-00-2025-09-01_14-00-00_风机历史数据.xls b/docs/完整年数据/04_2024-09-01_14-00-00-2025-09-01_14-00-00_风机历史数据.xls new file mode 100644 index 0000000..dd87131 Binary files /dev/null and b/docs/完整年数据/04_2024-09-01_14-00-00-2025-09-01_14-00-00_风机历史数据.xls differ diff --git a/docs/完整年数据/05_2024-09-01_14-00-00-2025-09-01_14-00-00_风机历史数据.xls b/docs/完整年数据/05_2024-09-01_14-00-00-2025-09-01_14-00-00_风机历史数据.xls new file mode 100644 index 0000000..0942fd9 Binary files /dev/null and b/docs/完整年数据/05_2024-09-01_14-00-00-2025-09-01_14-00-00_风机历史数据.xls differ diff --git a/docs/完整年数据/06_2024-09-01_14-00-00-2025-09-01_14-00-00_风机历史数据.xls b/docs/完整年数据/06_2024-09-01_14-00-00-2025-09-01_14-00-00_风机历史数据.xls new file mode 100644 index 0000000..f9222a0 Binary files /dev/null and b/docs/完整年数据/06_2024-09-01_14-00-00-2025-09-01_14-00-00_风机历史数据.xls differ diff --git a/docs/完整年数据/07_2024-09-01_14-00-00-2025-09-01_14-00-00_风机历史数据.xls b/docs/完整年数据/07_2024-09-01_14-00-00-2025-09-01_14-00-00_风机历史数据.xls new file mode 100644 index 0000000..009d4b1 Binary files /dev/null and b/docs/完整年数据/07_2024-09-01_14-00-00-2025-09-01_14-00-00_风机历史数据.xls differ diff --git a/docs/完整年数据/08_2024-09-01_14-00-00-2025-09-01_14-00-00_风机历史数据.xls b/docs/完整年数据/08_2024-09-01_14-00-00-2025-09-01_14-00-00_风机历史数据.xls new file mode 100644 index 0000000..90a8e1e Binary files /dev/null and b/docs/完整年数据/08_2024-09-01_14-00-00-2025-09-01_14-00-00_风机历史数据.xls differ diff --git a/docs/完整年数据/09_2024-09-01_14-00-00-2025-09-01_14-00-00_风机历史数据.xls b/docs/完整年数据/09_2024-09-01_14-00-00-2025-09-01_14-00-00_风机历史数据.xls new file mode 100644 index 0000000..aa083e9 Binary files /dev/null and b/docs/完整年数据/09_2024-09-01_14-00-00-2025-09-01_14-00-00_风机历史数据.xls differ diff --git a/docs/完整年数据/10_2024-09-01_14-00-00-2025-09-01_14-00-00_风机历史数据.xls b/docs/完整年数据/10_2024-09-01_14-00-00-2025-09-01_14-00-00_风机历史数据.xls new file mode 100644 index 0000000..b9dfd6b Binary files /dev/null and b/docs/完整年数据/10_2024-09-01_14-00-00-2025-09-01_14-00-00_风机历史数据.xls differ diff --git a/docs/完整年数据/11_2024-09-01_14-00-00-2025-09-01_14-00-00_风机历史数据.xls b/docs/完整年数据/11_2024-09-01_14-00-00-2025-09-01_14-00-00_风机历史数据.xls new file mode 100644 index 0000000..e836889 Binary files /dev/null and b/docs/完整年数据/11_2024-09-01_14-00-00-2025-09-01_14-00-00_风机历史数据.xls differ diff --git a/docs/完整年数据/12_2024-09-01_14-00-00-2025-09-01_14-00-00_风机历史数据.xls b/docs/完整年数据/12_2024-09-01_14-00-00-2025-09-01_14-00-00_风机历史数据.xls new file mode 100644 index 0000000..bce1237 Binary files /dev/null and b/docs/完整年数据/12_2024-09-01_14-00-00-2025-09-01_14-00-00_风机历史数据.xls differ diff --git a/docs/完整年数据/13_2024-09-01_14-00-00-2025-09-01_14-00-00_风机历史数据.xls b/docs/完整年数据/13_2024-09-01_14-00-00-2025-09-01_14-00-00_风机历史数据.xls new file mode 100644 index 0000000..5b53f5b Binary files /dev/null and b/docs/完整年数据/13_2024-09-01_14-00-00-2025-09-01_14-00-00_风机历史数据.xls differ diff --git a/docs/完整年数据/14_2024-09-01_14-00-00-2025-09-01_14-00-00_风机历史数据.xls b/docs/完整年数据/14_2024-09-01_14-00-00-2025-09-01_14-00-00_风机历史数据.xls new file mode 100644 index 0000000..fe6222f Binary files /dev/null and b/docs/完整年数据/14_2024-09-01_14-00-00-2025-09-01_14-00-00_风机历史数据.xls differ diff --git a/docs/完整年数据/15_2024-09-01_14-00-00-2025-09-01_14-00-00_风机历史数据.xls b/docs/完整年数据/15_2024-09-01_14-00-00-2025-09-01_14-00-00_风机历史数据.xls new file mode 100644 index 0000000..8926c1e Binary files /dev/null and b/docs/完整年数据/15_2024-09-01_14-00-00-2025-09-01_14-00-00_风机历史数据.xls differ diff --git a/docs/完整年数据/16_2024-09-01_14-00-00-2025-09-01_14-00-00_风机历史数据.xls b/docs/完整年数据/16_2024-09-01_14-00-00-2025-09-01_14-00-00_风机历史数据.xls new file mode 100644 index 0000000..1dadc9f Binary files /dev/null and b/docs/完整年数据/16_2024-09-01_14-00-00-2025-09-01_14-00-00_风机历史数据.xls differ diff --git a/docs/机组功率曲线测试方案(激光雷达)-武川.docx b/docs/机组功率曲线测试方案(激光雷达)-武川.docx new file mode 100644 index 0000000..e3000cf Binary files /dev/null and b/docs/机组功率曲线测试方案(激光雷达)-武川.docx differ diff --git a/docs/清洗完后直接生成功率曲线.py b/docs/清洗完后直接生成功率曲线.py new file mode 100644 index 0000000..80a8685 --- /dev/null +++ b/docs/清洗完后直接生成功率曲线.py @@ -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) + diff --git a/docs/郏县逐风风电场机组数据分析和资料审核报告 - 需补充Cp值.docx b/docs/郏县逐风风电场机组数据分析和资料审核报告 - 需补充Cp值.docx new file mode 100644 index 0000000..4fb48c4 Binary files /dev/null and b/docs/郏县逐风风电场机组数据分析和资料审核报告 - 需补充Cp值.docx differ