| 123456789101112131415161718192021222324252627282930313233343536373839404142 |
- # -*- coding: utf-8 -*-
- """TCM 设计层: 功率档 (WPS-ActivePower 7 分箱) × mask 阈值 (黄/红) × 趋势. 只复现外壳, 不重造受保护公式."""
- import numpy as np
- import pandas as pd
- from src.windcms.config import HIGH_BIN, BIN_ORDER
- from src.windcms.data import mask_key # windcms 侧数据件(未随迁)
- def bin_label(key):
- return key.replace('WPS-ActivePower ', '').rstrip(',') + ' kW'
- def trend(scalars, masks, farm_prefix, turbine, sensor, meas, bin_key=HIGH_BIN):
- q = scalars[(scalars.turbine == turbine) & (scalars.sensor_name == sensor) & (scalars.meas_name == meas) & (scalars.condition_key == bin_key)]
- q = q.sort_values('trigger_time')[['trigger_time', 'scalar_value', 'window', 'alarm_type']].reset_index(drop=True)
- th = masks.get((mask_key(farm_prefix, turbine, sensor, meas), bin_key), {})
- return q, th
- def fleet_ref(scalars, sensor, meas, bin_key=HIGH_BIN):
- q = scalars[(scalars.sensor_name == sensor) & (scalars.meas_name == meas) & (scalars.condition_key == bin_key)]
- per = q.groupby('turbine').scalar_value.median()
- 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)))
- def status_table(scalars, masks, farm_prefix, bin_key=HIGH_BIN, window=None):
- """每 (台,测点,标量) 末窗中位 vs mask 阈值 → Green/Yellow/Red/NoMask; 外加 ×fleet."""
- q = scalars[scalars.condition_key == bin_key]
- if window:
- q = q[q.window == window]
- else:
- last = q.groupby('turbine').window.max()
- q = q[q.window == q.turbine.map(last)]
- g = q.groupby(['turbine', 'sensor_name', 'meas_name']).scalar_value.agg(['median', 'max', 'size']).reset_index()
- fm = q.groupby(['sensor_name', 'meas_name']).scalar_value.median().rename('fleet_median')
- g = g.merge(fm, on=['sensor_name', 'meas_name'], how='left')
- g['x_fleet'] = g['median'] / g['fleet_median']
- def st(r):
- th = masks.get((mask_key(farm_prefix, r.turbine, r.sensor_name, r.meas_name), bin_key))
- if not th or not np.isfinite(th.get('red', np.nan)):
- return 'NoMask'
- if r['median'] >= th['red']: return 'Red'
- if r['median'] >= th['yellow']: return 'Yellow'
- return 'Green'
- g['mask_status'] = g.apply(st, axis=1)
- return g
|