Anemometers are critical wind-speed sensors, but they can be affected by weather, icing, and miscalibration. Step 4_1 Wind Sensor Check runs two anemometer-related checks:
- Step 4a:
InterTurbineWindspeedAnomalyFlagging, a 10-minute peer-population anomaly flag written tofact_wtg_anemometer_anomaly_10m(WIND_WTG_ANEMOMETER_ANOMALY_TABLE). - Step 4b:
AnemometerCheck, a daily rating that combines the Step 4a peer flag roll-up with an optional power-curve self-check and writes tofact_wtg_sensor_rating_1d(WIND_WTG_SENSOR_RATING_TABLE).
Inter-Turbine Anemometer Anomaly Detection
Purpose: Detect abnormal nacelle wind-speed patterns by comparing turbine measurements across a peer population.
Implemented by InterTurbineWindspeedAnomalyFlagging
(wind/flagging/inter_turbine_windspeed_anomaly_flagging.py), run as
Step 4a of Step 4_1 Wind Sensor Check.py.
Required Signals
Sensors:
- WindSpeed (WNAC_WIND_SPEED) - nacelle anemometer wind-speed measurement,
with the corresponding Step 3_2 DQ flag available.
Population Requirements
- Minimum turbines: 3 (configurable via
min_absolute_count) - Minimum population coverage: 80% (configurable via
min_population_percent) - Terrain mode: default
complex_terrain=Falseuses the whole-site population. Whencomplex_terrain=True, each turbine is compared only against its configuredreferenceTurbinespool, including itself; turbines with no sufficient reference pool are skipped and left normal (0).
Filtering
- Data quality only - bad-quality
WindSpeedsamples are discarded before the population Z-score is computed.
Compute Logic
Uses population-based Z-score analysis:
1. Build a combined turbine dataframe for WindSpeed.
2. Remove bad-quality samples.
3. Compute population Z-scores across all turbines at each timestamp
(complex_terrain=False), or per turbine against its referenceTurbines
pool (complex_terrain=True).
4. Set raw flags to 1 when abs(zscore) > k, 0 otherwise, and -1 when
the Z-score cannot be computed.
5. For each turbine, apply the rolling temporal rule: within a
consecutive_hours_threshold hour window, flag a timestamp as abnormal only
when all valid points in the window are anomalous and at least
consecutive_hours_threshold valid points are present.
Output: Categorical 10-minute flag AnemometerFlag
(POINT_NAME_ANEMOMETER_ANOMALY) with signal category
InterTurbineWindSpeedAnomality (WTUR_INTER_TURBINE_WINDSPEED_ANOMALY),
written to fact_wtg_anemometer_anomaly_10m.
- 1: Abnormal wind speed (anomaly detected)
- 0: Normal operation
- -1: Bad quality or Z-score could not be computed
Algorithm Parameters
k: Z-score threshold (default: 3.0) - sensitivity controlconsecutive_hours_threshold: rolling window length in hours and minimum valid-point count for flagging (default: 2)min_population_percent: minimum percentage of turbines (default: 80.0)min_absolute_count: minimum absolute number of turbines (default: 3)complex_terrain: use per-turbinereferenceTurbinespools instead of the whole-site population (default: False)
Key Advantage: Unlike ARR and parameter estimation algorithms, inter-turbine anemometer detection requires no training data. It operates on the current data chunk directly using population statistics. This means even short observation windows (hours to days) can be analyzed without prior historical context, making it useful for real-time anomaly detection on new turbines or after maintenance.

Figure: Population-based wind speed anomaly detection across turbine fleet
Anemometer Self-Check (daily grading)
Purpose: Catch an anemometer that drifts or under-reads, for example due to miscalibration or icing bias, using the turbine's own physics. This covers a blind spot of the inter-turbine method, which cannot see a fleet-wide bias or a fault masked by similar neighbours.
Implemented by AnemometerCheck
(wind/data_preparation/anemometer_evaluation.py), run as Step 4b of
Step 4_1 Wind Sensor Check.py. It emits one daily row per turbine to
fact_wtg_sensor_rating_1d (WIND_WTG_SENSOR_RATING_TABLE) - the unified daily
sensor-rating table shared with 4c/4d/4e/4f/4g.
Two complementary anchors
- Self bias (
AnemometerSelfBiasMs) - daily mean ofv_measured - v_expected, wherev_expectedis the wind speed implied by the turbine's ownActivePowerinverted through its reference contractual power curve from Step 2_1 (DIM_WIND_CONTRACTUAL_CURVE_TABLE). - The inversionpower -> wind speedis only well-posed on the monotonic Region II of the curve. The rated plateau (Region III) is degenerate and near-zero power is flat and noisy, so samples are gated to a[region2_low_frac, region2_high_frac]fraction-of-rated window and the curve is restricted to below its knee (find_knee_point). - Peer flag fraction (
AnemometerPeerFlagFrac) - daily roll-up (fraction of valid 10-minute samples flagged anomalous) of the Step 4a inter-turbine flag (AnemometerFlag). Flag value-1is excluded from the denominator. This keeps a single source of truth for the population comparison: 4a stays the 10-minute primitive consumed by sensor selection, while 4b only summarises it daily.
Rating (AnemometerRating)
Reuses the shared WIND_SENSOR_RATING_* codes (0 normal, 1 suspect, 2
failed, 3 insufficient_data), self-check first then peer:
- abs(self bias) >= self_bias_suspect_ms -> SUSPECT
- peer_flag_frac >= peer_flag_frac_suspect -> SUSPECT
- abs(self bias) >= self_bias_fail_ms -> FAILED
- INSUFFICIENT_DATA (3) where neither anchor has data that day, for example
fewer than min_daily_samples Region-II samples and no valid Step 4a peer
flags. The daily metrics can be NaN while the rating is
INSUFFICIENT_DATA; if there is no raw wind-speed daily index, no daily
anemometer rows are emitted.
Algorithm Parameters (schemas/algorithm_defaults.py)
self_bias_suspect_ms(default 1.0),self_bias_fail_ms(default 2.0)peer_flag_frac_suspect(default 0.2)min_daily_samples(default 36 = 6 h of Region-II samples)region2_low_frac(default 0.05),region2_high_frac(default 0.85)
Either anchor is optional: a turbine without a reference power curve is graded on the peer anchor alone; with no Step 4a flag it is graded on the self-check alone. The algorithm input validation requires at least one of these anchors.