Daily sensor-quality grading of wind-turbine temperature signals. Lives in bazeanalytics.wind.data_preparation.temperature_evaluation.

Two algorithms, split by physics:

Class Scope Signal Used by
AmbientTempCheck Nacelle ambient temperature (slow-varying, atmospheric) WNAC_AMBIENT_TEMP Step 4_1 Wind Sensor Check, sub-step 4c
ComponentTempCheck Drive-train components (fast-varying, load-dependent) Configured per instance from wind_schema.COMPONENT_TEMP_SIGNALS when present in the DQ table Step 4_1 Wind Sensor Check, sub-step 4d

AmbientTempCheck builds one wide ambient-temperature DataFrame, DQ-masks WNAC_AMBIENT_TEMP, optionally adds satellite ambient from Step 1_5, computes daily metrics, and returns an ObjectTimeSeriesCollection.

ComponentTempCheck is a thin wrapper around PeerSensorCheck. It validates the configured component signal, then delegates to PeerSensorCheck with Celsius output suffixes, require_running=True, and the running, pitch-control, and torque-control operation-state codes.

Output (per turbine, per day)

Step 4_1 writes these daily ratings to fact_wtg_sensor_rating_1d.

Ratings use map_sch.WIND_SENSOR_RATING_* codes:

Code Meaning
0 normal
1 suspect
2 failed
3 insufficient_data

AmbientTempCheck

Point Description
AmbientTempPeerBiasC Daily mean of T_turbine - median(T_site_turbines) when at least min_peer_count turbine values exist at the timestamp
AmbientTempSatBiasC Daily mean of T_turbine - T_satellite using Step 1_5 satellite TEMP_AMBIENT reindexed nearest within 30 minutes; NaN when satellite ambient is absent
AmbientTempPeerZScore Daily maximum absolute population MAD z-score across turbines
AmbientTempRating 0 normal, 1 suspect, 2 failed, or 3 insufficient_data

Default thresholds and guards:

Setting Default Effect
peer_bias_suspect_c 2.0 abs(AmbientTempPeerBiasC) >= 2.0 sets suspect
peer_bias_fail_c 5.0 abs(AmbientTempPeerBiasC) >= 5.0 sets failed
sat_bias_suspect_c 5.0 abs(AmbientTempSatBiasC) >= 5.0 sets suspect
peer_zscore_suspect 3.5 AmbientTempPeerZScore >= 3.5 sets suspect
min_peer_count 3 Peer bias and z-score are masked below this per-timestamp fleet count
min_daily_samples 72 Fewer valid 10-minute samples per day sets insufficient_data

ComponentTempCheck

Point names use the per-signal output_prefix from wind_schema.COMPONENT_TEMP_SIGNALS so multiple component-temperature checks coexist in one output table.

Point Description
{prefix}PeerBiasC Daily mean of T_turbine - median(T_site_turbines) after DQ masking and the running operation-state gate
{prefix}PeerZScore Daily maximum absolute population MAD z-score across turbines
{prefix}DailyStdC Daily within-turbine standard deviation of the signal
{prefix}Rating 0 normal, 1 suspect, 2 failed, or 3 insufficient_data

Default thresholds and guards:

Setting Default Effect
peer_bias_suspect_c 5.0 abs({prefix}PeerBiasC) >= 5.0 sets suspect
peer_bias_fail_c 12.0 abs({prefix}PeerBiasC) >= 12.0 sets failed
peer_zscore_suspect 4.0 {prefix}PeerZScore >= 4.0 sets suspect
stuck_std_min_c 0.5 {prefix}DailyStdC <= 0.5 sets suspect
min_peer_count 3 Peer bias and z-score are masked below this per-timestamp fleet count
min_daily_samples 36 Fewer valid 10-minute running samples per day sets insufficient_data

Design notes

This module replaces the legacy TemperatureSensorFlagger pattern with two BaseAlgorithm classes and no BaseFlaggingAlgorithm, compute_flag indirection, or priority-merge plumbing.

Deliberately dropped (with rationale): - Hard min/max thresholds: range checks belong in DQ. - Naive forecaster trend residuals: load transitions create legitimate jumps that confound real sensor faults. - Operating-mode filter for ambient: ambient is outside the nacelle and independent of pitch/torque control. - 7-code flag taxonomy with priority merging: replaced by one numeric rating plus diagnostic columns. - Two parallel implementations (*_collection vs *_from_df): keep one run path per algorithm.

Kept (with rationale): - Fleet median + bias + population MAD z-score: strongest sensor-health signal for both ambient and component temperatures. - Daily aggregation with a minimum-sample floor to avoid partial-day noise. - Operating-mode mask only for ComponentTempCheck: load-dependent signals require it; ambient does not. - Stuck-sensor daily-standard-deviation floor in ComponentTempCheck.

Pipeline placement

  • Step 4_1 Wind Sensor Check runs AmbientTempCheck as sub-step 4c using DQ-cleaned turbine data from fact_wtg_dq_10m (Step 3_2) and optional satellite ambient from fact_windfarm_sat_input_10m (Step 1_5).
  • Step 4_1 Wind Sensor Check runs ComponentTempCheck as sub-step 4d, once per (signal_category, output_prefix) in wind_schema.COMPONENT_TEMP_SIGNALS whose signal is present in the DQ table, and only when the Step 4_0 operation-state composite is available.

Related 10-minute temperature-anomaly pipeline:

  • Step 1_6 Wind Temperature Tag Discovery writes dim_wind_temperature_tags. The default per-point config sets normal_behavior.enabled to False, normal_behavior.feature_tags to ["ActivePower", "AmbientTemperature", "GeneratorSpeed"], both training dates to None, peer_comparison.enabled to True, and min/max threshold values to None.
  • Step 7_3 Wind Temperature Model Builder reads dim_wind_temperature_tags, trains only normal-behavior-enabled points with both training dates set, and stores per-turbine, per-target models in dim_wind_temperature_models. Its rebuild signature includes the training window and feature tags; absolute thresholds are not part of the signature.
  • Step 7_4 Wind Temperature Anomaly Scorer loads the portal copy of those models and writes <point>Model.10m and <point>Anom.10m to fact_wtg_temperature_anomaly_10m.
  • Step 7_5 Wind Temperature Peer Comparison scores peer-enabled points without a stored model and writes <point>PeerZ.10m, <point>PeerAnom.10m, <point>PeerMedian.10m, and <point>PeerCount.10m to fact_wtg_temperature_peer_10m. Defaults are k=3.0, min_population_percent=80.0, min_absolute_count=3, min_abs_delta=2.0, and median_delta_fraction=0.05. A peer anomaly requires both abs(Z) > k and abs(value - median) > max(min_abs_delta, median_delta_fraction * abs(median)).