tcm.py 2.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142
  1. # -*- coding: utf-8 -*-
  2. """TCM 设计层: 功率档 (WPS-ActivePower 7 分箱) × mask 阈值 (黄/红) × 趋势. 只复现外壳, 不重造受保护公式."""
  3. import numpy as np
  4. import pandas as pd
  5. from src.windcms.config import HIGH_BIN, BIN_ORDER
  6. from src.windcms.data import mask_key # windcms 侧数据件(未随迁)
  7. def bin_label(key):
  8. return key.replace('WPS-ActivePower ', '').rstrip(',') + ' kW'
  9. def trend(scalars, masks, farm_prefix, turbine, sensor, meas, bin_key=HIGH_BIN):
  10. q = scalars[(scalars.turbine == turbine) & (scalars.sensor_name == sensor) & (scalars.meas_name == meas) & (scalars.condition_key == bin_key)]
  11. q = q.sort_values('trigger_time')[['trigger_time', 'scalar_value', 'window', 'alarm_type']].reset_index(drop=True)
  12. th = masks.get((mask_key(farm_prefix, turbine, sensor, meas), bin_key), {})
  13. return q, th
  14. def fleet_ref(scalars, sensor, meas, bin_key=HIGH_BIN):
  15. q = scalars[(scalars.sensor_name == sensor) & (scalars.meas_name == meas) & (scalars.condition_key == bin_key)]
  16. per = q.groupby('turbine').scalar_value.median()
  17. return dict(fleet_median=float(per.median()) if len(per) else np.nan, fleet_p90=float(per.quantile(.9)) if len(per) else np.nan, n_turbines=int(len(per)))
  18. def status_table(scalars, masks, farm_prefix, bin_key=HIGH_BIN, window=None):
  19. """每 (台,测点,标量) 末窗中位 vs mask 阈值 → Green/Yellow/Red/NoMask; 外加 ×fleet."""
  20. q = scalars[scalars.condition_key == bin_key]
  21. if window:
  22. q = q[q.window == window]
  23. else:
  24. last = q.groupby('turbine').window.max()
  25. q = q[q.window == q.turbine.map(last)]
  26. g = q.groupby(['turbine', 'sensor_name', 'meas_name']).scalar_value.agg(['median', 'max', 'size']).reset_index()
  27. fm = q.groupby(['sensor_name', 'meas_name']).scalar_value.median().rename('fleet_median')
  28. g = g.merge(fm, on=['sensor_name', 'meas_name'], how='left')
  29. g['x_fleet'] = g['median'] / g['fleet_median']
  30. def st(r):
  31. th = masks.get((mask_key(farm_prefix, r.turbine, r.sensor_name, r.meas_name), bin_key))
  32. if not th or not np.isfinite(th.get('red', np.nan)):
  33. return 'NoMask'
  34. if r['median'] >= th['red']: return 'Red'
  35. if r['median'] >= th['yellow']: return 'Yellow'
  36. return 'Green'
  37. g['mask_status'] = g.apply(st, axis=1)
  38. return g