Files
Enelix-EMS/services/netplan-v4/acceptance/forecast-src/shared_utils.py
T

94 lines
3.1 KiB
Python

import math
def as_float(value, default=0.0):
try:
if value is None:
return default
return float(value)
except Exception:
return default
def roof_kwp(roof):
return as_float(roof.get("kwp", roof.get("leistung", roof.get("pv_kwp", 0.0))), 0.0)
def roof_azimuth_deg(roof):
return as_float(roof.get("azimut", roof.get("azimuth", roof.get("ausrichtung", 180.0))), 180.0)
def roof_tilt_deg(roof):
return as_float(roof.get("neigung", roof.get("tilt", 30.0)), 30.0)
def roof_features(config):
roofs = config.get("daecher", []) or []
if not roofs:
roofs = [{"kwp": as_float(config.get("ac_leistung", 0.0), 0.0), "azimut": 180.0, "neigung": 30.0}]
total_kwp = sum(roof_kwp(r) for r in roofs)
if total_kwp <= 0:
total_kwp = as_float(config.get("ac_leistung", 0.0), 0.0)
weighted_az = 0.0
weighted_tilt = 0.0
south_factor = 0.0
for roof in roofs:
w = roof_kwp(roof) / total_kwp if total_kwp > 0 else 0.0
az = roof_azimuth_deg(roof)
tilt = roof_tilt_deg(roof)
weighted_az += w * az
weighted_tilt += w * tilt
south_factor += w * max(0.0, math.cos(math.radians(az - 180.0)))
return {
"pv_kwp_total": total_kwp,
"roof_azimuth_sin": math.sin(math.radians(weighted_az)),
"roof_azimuth_cos": math.cos(math.radians(weighted_az)),
"roof_tilt_avg": weighted_tilt,
"roof_south_factor": south_factor,
}
def calc_pure_math_pv(config, dt):
ac_limit = as_float(config.get("ac_leistung", 10.0), 10.0) * 1000.0
roofs = config.get("daecher", []) or []
if not roofs:
roofs = [{"kwp": as_float(config.get("ac_leistung", 0.0), 0.0), "neigung": 30.0, "azimut": 180.0}]
day = dt.timetuple().tm_yday
hour = dt.hour + dt.minute / 60.0
lat = math.radians(as_float(config.get("latitude", 47.0), 47.0))
decl = math.radians(23.45 * math.sin(math.radians(360.0 * (day - 81) / 365.0)))
hour_angle = math.radians(15.0 * (hour - 12.0))
sin_alt = math.sin(lat) * math.sin(decl) + math.cos(lat) * math.cos(decl) * math.cos(hour_angle)
sun_alt = math.asin(max(-1.0, min(1.0, sin_alt)))
if sun_alt <= 0.0:
return 0.0
sun_az = math.atan2(
math.sin(hour_angle),
math.cos(hour_angle) * math.sin(lat) - math.tan(decl) * math.cos(lat),
)
total = 0.0
for roof in roofs:
kwp = roof_kwp(roof)
if kwp <= 0:
continue
tilt = math.radians(roof_tilt_deg(roof))
az = math.radians(roof_azimuth_deg(roof))
cos_inc = math.sin(sun_alt) * math.cos(tilt) + math.cos(sun_alt) * math.sin(tilt) * math.cos(sun_az - az)
if cos_inc > 0:
total += kwp * 1000.0 * cos_inc
return max(0.0, min(total, ac_limit))
def calc_pure_math_load(dt):
hour = dt.hour + dt.minute / 60.0
base = 650.0
morning = 220.0 * math.exp(-((hour - 7.0) ** 2) / 5.0)
evening = 380.0 * math.exp(-((hour - 19.0) ** 2) / 8.0)
weekend = 1.12 if dt.weekday() >= 5 else 1.0
return max(0.0, (base + morning + evening) * weekend)