GreenTransPowerCalculate/PV/pv_total.py

282 lines
12 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import pandas as pd
import math
from scipy.optimize import fsolve
# 默认文件路径
TILT_EXCEL_PATH = r"./peak_sunshine.xlsx" #各地区峰值小时数和倾角(注意城市名
PV_EXCEL_PATH = r"./pv_product.xlsx" #部分光伏组件数值
def calculate_pv_metrics(city, component_name, electricity_price, pv_number, q, longitude, latitude,
is_fixed=True, optimize=True, peak_load_hour=16, cost_per_kw=3.4, E_S=1.0, K=0.8):
"""
计算光伏项目的各项指标包括装机容量、年发电量、等效小时数、环境收益和内部收益率IRR
参数:
city (str): 城市名称,例如 "深圳"
component_name (str): 光伏组件名称,例如 "TWMHF-66HD715"
electricity_price (float): 电价(元/kWh
pv_number (int): 光伏组件数量
q (float): 运维成本占初始投资成本的比例(例如 0.02 表示 2%
is_fixed (bool): 是否为固定式支架True 为固定式False 为跟踪式
optimize (bool): 是否优化倾角和方位角
longitude (float): 经度
latitude (float): 纬度
peak_load_hour (int): 峰值负荷小时,默认 16
cost_per_kw (float): 每 kW 投资成本(元/kW默认 3.4 元/kW
E_S (float): 标准辐射量,默认 1.0
K (float): 系统效率,默认 0.8
返回:
dict: 包含以下结果的字典:
- city: 城市名称
- component_name: 组件名称
- tilt: 倾角 (度)
- azimuth: 方位角 (度)
- array_distance: 阵列间距 (米)
- max_power: 单组件最大功率 (Wp)
- capacity: 装机容量 (kW)
- peak_sunshine_hours: 峰值日照小时数 (小时/天)
- single_daily_energy: 一天单个组件发电量 (kWh)
- annual_energy: 年发电量 (kWh)
- equivalent_hours: 等效小时数 (小时)
- coal_reduction: 标准煤减排量 (kg)
- CO2_reduction: CO₂ 减排量 (kg)
- SO2_reduction: SO₂ 减排量 (kg)
- NOX_reduction: NOx 减排量 (kg)
- IRR: 内部收益率 (%)
"""
# 1. 获取城市的倾角和峰值日照小时数
def get_tilt_and_peak_hours(city, excel_path=TILT_EXCEL_PATH):
"""从Excel获取城市的倾角和峰值日照小时数"""
try:
df = pd.read_excel(excel_path)
if len(df.columns) < 5:
raise ValueError("Excel文件需包含至少5列城市、倾角、峰值日照小时数等")
row = df[df.iloc[:, 2] == city]
if row.empty:
raise ValueError(f"未找到城市:{city}")
return {"city": city, "tilt": row.iloc[0, 3], "peak_sunshine_hours": row.iloc[0, 4]}
except FileNotFoundError:
raise FileNotFoundError(f"未找到Excel文件{excel_path}")
except Exception as e:
raise Exception(f"读取Excel出错{e}")
# 2. 计算倾角和方位角
def get_tilt_and_azimuth(is_fixed=True, optimize=True, longitude=116, city=None, excel_path=TILT_EXCEL_PATH,
peak_load_hour=16):
"""计算光伏系统的倾角和方位角"""
if optimize and not city:
raise ValueError("优化模式下需提供城市名称")
if is_fixed:
if optimize:
tilt = get_tilt_and_peak_hours(city, excel_path)["tilt"]
azimuth = (peak_load_hour - 12) * 15 + (longitude - 116) # 方位角公式
azimuth = azimuth % 360 if azimuth >= 0 else azimuth + 360
else:
print("倾角0°(水平)-90°(垂直) | 方位角0°(正北)-180°(正南),顺时针")
tilt = float(input("请输入倾角(度)"))
azimuth = float(input("请输入方位角(度)"))
if not (0 <= tilt <= 90) or not (0 <= azimuth <= 360):
raise ValueError("倾角需在0-90°方位角需在0-360°")
else: # 跟踪式
azimuth = 180 # 固定朝南
if optimize:
tilt = get_tilt_and_peak_hours(city, excel_path)["tilt"]
else:
print("倾角0°(水平)-90°(垂直)")
tilt = float(input("请输入倾角(度)"))
if not (0 <= tilt <= 90):
raise ValueError("倾角需在0-90°")
return tilt, azimuth
# 3. 获取光伏组件信息
def get_pv_product_info(component_name, excel_path=PV_EXCEL_PATH):
try:
df = pd.read_excel(excel_path)
if len(df.columns) < 10:
raise ValueError("Excel文件需包含至少10列组件名称、尺寸、功率等")
row = df[df.iloc[:, 1] == component_name]
if row.empty:
raise ValueError(f"未找到组件:{component_name}")
return {
"component_name": component_name,
"max_power": row.iloc[0, 5],
"efficiency": row.iloc[0, 9],
"pv_size": row.iloc[0, 3]
}
except FileNotFoundError:
raise FileNotFoundError(f"未找到Excel文件{excel_path}")
except Exception as e:
raise Exception(f"读取Excel出错{e}")
# 4. 计算光伏阵列间距
def calculate_array_distance(L, tilt, latitude):
beta_rad = math.radians(tilt)
phi_rad = math.radians(latitude)
return (L * math.cos(beta_rad) +
L * math.sin(beta_rad) * 0.707 * math.tan(phi_rad) +
0.4338 * math.tan(phi_rad))
# 5. 计算等效小时数
def calculate_equivalent_hours(P, P_r):
if P_r == 0:
raise ValueError("额定功率不能为 0")
h = P / P_r # 单位换算
return h
# 6. 计算装机容量
def calculate_installed_capacity(max_power, num_components):
if max_power < 0 or num_components < 0 or not isinstance(num_components, int):
raise ValueError("功率和数量需为非负数,数量需为整数")
return (max_power * num_components) / 1000 # 单位kW
# 7. 计算年发电量
def calculate_annual_energy(peak_hours, capacity, E_S=E_S, K=K):
if any(x < 0 for x in [peak_hours, capacity]) or E_S <= 0 or not 0 <= K <= 1:
raise ValueError("输入参数需满足辐射量、容量≥0E_S>0K∈[0,1]")
return peak_hours * 365 * (capacity / E_S) * K # 单位kWh
# 8. 计算环境收益
def calculate_environmental_benefits(E_p_million_kwh):
if E_p_million_kwh < 0:
raise ValueError("年发电量需≥0")
return {
"coal_reduction": E_p_million_kwh * 0.404 * 10,
"CO2_reduction": E_p_million_kwh * 0.977 * 10,
"SO2_reduction": E_p_million_kwh * 0.03 * 10,
"NOX_reduction": E_p_million_kwh * 0.015 * 10
}
# 9. 计算净现值和内部收益率
def calculate_reference_yield(E_p, electricity_price, IC, q, n=25):
if E_p < 0 or electricity_price < 0 or IC <= 0 or not 0 <= q <= 1:
raise ValueError("发电量、电价≥0投资成本>0回收比例∈[0,1]")
def npv_equation(irr, p, w, ic, q_val, n=n):
term1 = (1 + irr) ** (-1)
term2 = irr * (1 + irr) ** (-1) if irr != 0 else float('inf')
pv_revenue = p * w * (term1 / term2) * (1 - (1 + irr) ** (-n))
pv_salvage = q_val * ic * (term1 / term2) * (1 - (1 + irr) ** (-n))
return pv_revenue - ic + pv_salvage
irr_guess = 0.1
irr = float(fsolve(npv_equation, irr_guess, args=(E_p, electricity_price, IC, q))[0])
if not 0 <= irr <= 1:
raise ValueError(f"IRR计算结果{irr:.4f}不合理,请检查输入")
npv = npv_equation(irr, E_p, electricity_price, IC, q)
return {"NPV": npv, "IRR": irr * 100}
# 主计算流程
try:
# 获取倾角和方位角
tilt, azimuth = get_tilt_and_azimuth(is_fixed, optimize, longitude, city)
# 获取组件信息
pv_info = get_pv_product_info(component_name)
width_mm = float(pv_info["pv_size"].split("×")[1])
L = (width_mm / 1000) * 4
array_distance = calculate_array_distance(L, tilt, latitude)
# 计算装机容量
max_power = pv_info["max_power"]
capacity = calculate_installed_capacity(max_power, pv_number) # 单位kW
# 获取峰值日照小时数
peak_hours = get_tilt_and_peak_hours(city)["peak_sunshine_hours"]
# 计算一天单个组件发电量
single_daily_energy = peak_hours * (capacity / pv_number) * K # 单位kWh
# 计算年发电量
E_p = calculate_annual_energy(peak_hours, capacity, E_S, K) # 单位kWh
# 计算等效小时数
h = calculate_equivalent_hours(E_p, capacity) # P_r 单位为 kWE_p 单位为 kWh
# 计算环境收益(转换为百万 kWh
E_p_million_kwh = E_p / 1000000 # 转换为百万 kWh
env_benefits = calculate_environmental_benefits(E_p_million_kwh)
# 计算初始投资成本
IC = capacity * cost_per_kw * 1000 # 单位:元
# 计算 IRR
ref_yield = calculate_reference_yield(E_p, electricity_price, IC, q)
# 返回结果
return {
"city": city,
"component_name": component_name,
"tilt": tilt,
"azimuth": azimuth,
"array_distance": array_distance,
"max_power": max_power,
"capacity": capacity,
"peak_sunshine_hours": peak_hours,
"single_daily_energy": single_daily_energy,
"annual_energy": E_p,
"equivalent_hours": h,
"coal_reduction": env_benefits["coal_reduction"],
"CO2_reduction": env_benefits["CO2_reduction"],
"SO2_reduction": env_benefits["SO2_reduction"],
"NOX_reduction": env_benefits["NOX_reduction"],
"IRR": ref_yield["IRR"]
}
except Exception as e:
raise Exception(f"计算过程中发生错误: {str(e)}")
# 示例用法
if __name__ == "__main__":
try:
# 输入
city = input("请输入城市:")
longitude = int(input("请城市经度:"))
latitude = int(input("请城市纬度:"))
component_name = input("请输入组件名称:")
electricity_price = float(input("请输入电价(元/kWh"))
pv_number = 1200 # 固定组件数量
q = 0.02 # 运维成本占初始投资成本的比例
choice = input("选择光伏支架(固定式/跟踪式):")
optimize = input("是否优化倾角和方位角(是/否):")
# 调用主函数
result = calculate_pv_metrics(
city=city,
component_name=component_name,
electricity_price=electricity_price,
pv_number=pv_number,
q=q,
is_fixed=(choice == "固定式"),
optimize=(optimize.lower() == ""),
longitude=longitude,
latitude=latitude
)
# 打印结果
print("\n")
print(f"城市:{result['city']}")
print(f"组件名称:{result['component_name']}")
print(f"倾角:{result['tilt']}° | 方位角:{result['azimuth']}°")
print(f"阵列间距:{result['array_distance']:.2f}")
print(f"单个组件最大功率Wp{result['max_power']}")
print(f"装机容量:{result['capacity']:.2f} kW")
print(f"峰值日照小时数:{result['peak_sunshine_hours']:.2f} 小时/天")
print(f"一天单个组件发电量:{result['single_daily_energy']:.2f} kWh")
print(f"年发电量:{result['annual_energy']:,.2f} kWh")
print(f"等效小时数:{result['equivalent_hours']:.2f} 小时")
print("环境收益:")
print(f"标准煤减排量:{result['coal_reduction']:,.2f} kg")
print(f"CO₂减排量{result['CO2_reduction']:,.2f} kg")
print(f"SO₂减排量{result['SO2_reduction']:,.2f} kg")
print(f"NOx减排量{result['NOX_reduction']:,.2f} kg")
print(f"内部收益率 IRR{result['IRR']:.2f}%")
except Exception as e:
print(f"错误:{e}")