| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485 |
- import numpy as np
- import pandas as pd
- import pvlib
- def night_mask(
- df,
- lat=None,
- lon=None,
- time_col="time",
- elev_min=0.0,
- ssrd_col=None,
- hour_window=None,
- ):
- """
- 判断夜间点,返回 bool 数组:
- True = 夜间
- False = 白天
- 优先级:
- 1. lat/lon 均存在 -> 根据太阳高度角判断
- 2. ssrd_col 存在 -> 辐照 <= 0 判为夜间
- 3. hour_window 存在 -> 窗口外判为夜间
- """
- # 1. 根据太阳高度角判断
- times = pd.to_datetime(df[time_col], errors="coerce")
- # 如果时间没有时区,这里按 UTC 处理
- if times.dt.tz is None:
- times = times.dt.tz_localize("UTC")
- else:
- times = times.dt.tz_convert("UTC")
- solar_position = pvlib.solarposition.get_solarposition(
- time=times,
- latitude=float(lat),
- longitude=float(lon),
- )
- elevation = solar_position["apparent_elevation"].to_numpy()
- return elevation <= float(elev_min)
- # 2. 没有经纬度时,可根据太阳辐照判断
- if ssrd_col is not None and ssrd_col in df.columns:
- ssrd = pd.to_numeric(df[ssrd_col], errors="coerce")
- return (ssrd <= 0).fillna(False).to_numpy()
- # 3. 根据小时范围粗略判断
- if hour_window is not None:
- start_hour, end_hour = hour_window
- times = pd.to_datetime(df[time_col], errors="coerce")
- hours = times.dt.hour
- if start_hour <= end_hour:
- daytime = (hours >= start_hour) & (hours <= end_hour)
- else:
- daytime = (hours >= start_hour) | (hours <= end_hour)
- return (~daytime).fillna(False).to_numpy()
- raise ValueError(
- "无法判断昼夜:请提供 lat/lon、ssrd_col 或 hour_window"
- )
- def solor_processed_power(df, n, power_col="v1-Dlinear-288", *, lat=None, lon=None,
- elev_min=0.0, clip_negative=True, ssrd_col=None,
- hour_window=None, time_col="time"):
- """只对前 n 行: 夜间置 0(按太阳高度角判定) + 负值置 0。"""
- processed = df.copy()
- m = min(int(n), len(processed))
- if m <= 0:
- return processed
- head = processed.iloc[:m]
- night = night_mask(head, lat=lat, lon=lon, time_col=time_col, elev_min=elev_min,
- ssrd_col=ssrd_col, hour_window=hour_window)
- p = pd.to_numeric(head[power_col], errors="coerce")
- bad = np.asarray(night, dtype=bool)
- if clip_negative:
- bad |= (p < 0).fillna(False).to_numpy()
- if bad.any():
- processed.loc[processed.index[:m], power_col] = p.mask(bad, 0.0).to_numpy()
- return processed
|