This document describes the wind data quality implementation as it exists in code. The implementation uses the generic DataQuality algorithm and wind-specific object methods on Turbine, MetMast, and Site.
Files Created/Modified
1. bazeanalytics/wind/wind_schema.py
Wind signal category constants, category groups, DQ summary output point names, and wind table naming helpers.
Turbine signal categories include:
- Power: ActivePower, ActivePower_min, ActivePower_max, ActivePower_std, reactive_power, and reactive-power variants.
- Rotor and pitch: RotorSpeed, Blade_PitchAngle, pitch battery/capacitor/motor categories, and variants where defined.
- Converter, gearbox, main shaft, generator, nacelle, tower, wind measurement, setpoint, and communication-state categories.
MET mast signal categories use a wmet_ prefix:
- Wind speed: wmet_WindSpeed, wmet_WindSpeed_min, wmet_WindSpeed_max, wmet_WindSpeed_std, wmet_WindSpeed_avg_adc.
- Wind direction: wmet_WindDirection, wmet_WindDirection_min, wmet_WindDirection_max, wmet_WindDirection_std.
- Atmospheric: wmet_AmbientTemperature, wmet_atmospheric_pressure, wmet_air_density, wmet_relative_humidity, wmet_precipitation.
- Derived: wmet_turbulence_intensity.
Site signal categories include:
- SiteWindSpeed
- SiteActivePower
- AirDensity
- AtmosphericPressure
2. bazeanalytics/models/turbine.py
Turbine provides wind turbine data quality parameters.
Methods used by wind DQ:
- get_range_bounds(signal_category) - returns value bounds for range validation.
- get_stuck_value_tolerance(signal_category) - returns constant-value tolerance.
- get_min_consecutive_stuck(signal_category, sampling_interval) - converts configured stuck duration to sample count.
- get_stuck_value_min_threshold(signal_category) - returns lower value gate for stuck detection.
- get_stuck_value_max_threshold(signal_category) - returns upper value gate for stuck detection.
- get_corrupt_codes(signal_category) - returns corrupt-code overrides.
Range bounds:
- ActivePower, ActivePower_max: upper bound = 1.1 x turbine rated power; no lower bound.
- ActivePower_min: unbounded.
- GeneratorSpeed: 0 to 5000 RPM; _min lower bound only; _max upper bound only; _std unbounded.
- RotorSpeed: 0 to 100 RPM; _min lower bound only; _max upper bound only; _std unbounded.
- Blade_PitchAngle: -10 to 100 deg; _min lower bound only; _max upper bound only; _std unbounded.
- Gearbox, generator, main-shaft, nacelle, pitch, converter, and tower temperature categories listed in TEMPERATURE_CATEGORIES: component ranges only where explicitly present in RANGE_BOUNDS_MAP; unknown temperature categories are unbounded.
- Ambient temperature AmbientTemperature: -50 to 60 degC.
- Nacelle and wind angle categories in NACELLE_ANGLE_CATEGORIES: 0 to 360 deg.
- Turbine-mounted WindSpeed: 0 to 50 m/s; _min lower bound only; _max upper bound only; _std unbounded.
- OperationStateCompositeAnalytics: 0 to 6.
- Unknown signal categories: unbounded.
Stuck detection:
- Default tolerance: 1e-5.
- Default stuck duration for turbine signals not in MIN_STUCK_DURATION_MAP: 60 minutes.
- Minimum returned sample count is 2; if sampling interval is greater than or equal to configured stuck duration, the method returns 2.
- ActivePower, ActivePower_std: 60 minutes; ActivePower only checks stuck values >= 20 kW.
- Blade_PitchAngle: 1 day.
- Listed component temperature categories in MIN_STUCK_DURATION_MAP: 300 minutes.
- OperationStateCompositeAnalytics: 365 days.
- WindSpeed, WindSpeed_std: 60 minutes.
- NacelleDirection: 600 minutes.
- WindRelativeAngle, absolute WindDirection, and GeneratorTorque: 60 minutes.
3. bazeanalytics/models/met_mast.py
MetMast provides MET mast data quality parameters.
Methods used by wind DQ:
- get_range_bounds(signal_category)
- get_stuck_value_tolerance(signal_category)
- get_stuck_duration(signal_category)
- get_min_consecutive_stuck(signal_category, sampling_interval)
- get_stuck_value_min_threshold(signal_category)
- get_stuck_value_max_threshold(signal_category)
- get_corrupt_codes(signal_category)
Range bounds:
- wmet_WindSpeed: 0 to 50 m/s; _min lower bound only; _max upper bound only; _std and _avg_adc unbounded.
- wmet_WindDirection, _min, _max: 0 to 360 deg; _std unbounded.
- wmet_AmbientTemperature: -50 to 60 degC.
- wmet_relative_humidity: 0 to 100 percent.
- wmet_precipitation: lower bound 0 only.
- wmet_turbulence_intensity: upper bound 0.25 only.
- wmet_atmospheric_pressure and wmet_air_density: unbounded.
- Unknown signal categories: unbounded.
Stuck detection:
- Default tolerance: 1e-5.
- Default stuck duration: 60 minutes.
- Minimum returned sample count is 2.
- wmet_WindSpeed and wmet_WindSpeed_std: 60 minutes.
- No min or max value gate is configured; defaults are -inf and inf.
4. bazeanalytics/models/site.py
Site provides site-level wind data quality parameters.
Range bounds:
- SiteWindSpeed: 0 to 50 m/s.
- SiteActivePower: upper bound = 1.001 x capacity_dc_site converted from MW to kW, when that attribute is defined; otherwise unbounded.
- AirDensity: 0.7 x 1.225 to 1.3 x 1.225 kg/m^3.
- AtmosphericPressure: 0.7 x 101325 to 1.3 x 101325 Pa.
- ActivePowerMeter (SITE_POWER_FROM_METER): -0.01 x to 1.02 x the lower of nominal plant capacity and AC capacity, or AC capacity when nominal plant capacity is missing. Code comments note this signal is expected in MW.
- Unknown signal categories: unbounded.
Stuck detection:
- SiteWindSpeed: tolerance 1e-5, duration 60 minutes.
- SiteActivePower: tolerance 1e-5, duration 60 minutes.
- ActivePowerMeter (SITE_POWER_FROM_METER): tolerance 1e-5, duration 20 minutes, lower stuck gate = 0.01 x capacity, upper stuck gate = 0.98 x capacity.
- Unknown site signals use tolerance 1e-5, duration 1 hour, lower gate -inf, and upper gate inf.
5. bazeanalytics/wind/data_preparation/wind_data_quality.py
Wind data quality validation algorithm.
Class: WindDataQuality
Inherits from BaseAlgorithm and implements:
- _input_validation(timeseries) - raises for empty time series collections.
- _generate_placeholders(timeseries, objects, required_points) - creates fully missing placeholder time series for required but absent points.
- _create_missing_timeseries(object_id, point, signal_category, timestamps) - creates a placeholder with value=NaN and dq_flag=6.
- _create_data_quality_algo(obj, signal_category, ts_coll) - builds a configured DataQuality instance from object methods.
- clean_values_common(timeseries, objects) - groups by object and signal category and applies DQ.
- run(timeseries, objects, required_points=None) - optional placeholder generation, validation, then DQ.
Quality checks applied:
1. Corrupt-code detection.
2. Increment stuck detection with constant_rate_threshold=0.0.
3. Value stuck detection.
4. Increment out-of-bounds detection, but wind DQ does not pass min or max increment bounds, so this check is not configured for WindDataQuality.
5. Value out-of-bounds detection.
6. Missing-value detection.
Special missing-only categories:
- SetpointActivePower
- CommunicationState
For these categories the algorithm uses DataQuality(corrupt_codes=[], min_consecutive_stuck=None), so only missing values are flagged by the standard checks.
6. bazeanalytics/wind/data_preparation/wind_data_quality_summary.py
Wind wrapper around the common DataQualitySummary.
Class: WindDataQualitySummary
run(site_id, ts_turbines_dq, ts_sites_dq, ts_met_masts_dq=None) returns three collections:
1. Site-level daily percentage of valid points per device type.
2. Site-level daily DQ flag percentage per point name.
3. Per-object daily DQ flag percentage per point name.
It then renames internal summary columns to wind point-template names using POINT_NAMES_MAPPING.
Pipeline Steps
| Step file | Input tables | Algorithm | Output table |
|---|---|---|---|
Step 3_1 Wind Site Data Quality.py |
fact_site_input_10m |
WindDataQuality |
fact_site_dq_10m |
Step 3_2 Wind Turbine Data Quality.py |
fact_wtg_input_10m; optional fact_wtg_anomaly_input_10m |
WindDataQuality |
fact_wtg_dq_10m; optional fact_wtg_anomaly_dq_10m |
Step 3_3 Wind MET mast Data Quality.py |
fact_met_input_10m |
WindDataQuality |
fact_met_dq_10m |
Step 3_4 Wind Meter Data Quality.py |
fact_meter_input_10m |
WindDataQuality, then MeterEnergyDataQuality |
fact_meter_dq_10m |
Step 3_5 Wind Data Quality Summary.py |
fact_wtg_dq_10m, fact_met_dq_10m, fact_site_dq_10m |
WindDataQualitySummary |
fact_site_dq_summary_1d, fact_site_dq_per_point_1d, fact_site_dq_per_object_1d |
Step 3_6 Wind Meter Energy Daily.py |
fact_meter_dq_10m, fact_site_input_10m |
MeterEnergyDaily |
fact_meter_energy_1d |
Step 3_7 Wind Site Comm Status.py |
fact_wtg_dq_10m, fact_met_dq_10m, fact_site_dq_10m, optional fact_meter_dq_10m |
SiteCommunicationStatus |
fact_windfarm_site_comm_status_10m |
Implementation Details
Quality Check Flow
1. Optionally add required-point placeholders flagged as missing.
2. Validate that the time series collection is not empty.
3. For each object:
- Group that object's time series by signal category.
- Use missing-only DQ for setpoint and communication-state categories.
- Use object-specific DQ for Turbine, MetMast, and Site objects.
- Use default DataQuality for other object types.
- Add or replace the flagged time series in the input collection.
Data Quality Flags
The implementation uses the common DataQuality class. The flag codes are defined in bazeanalytics/schemas/statuses.py.
| Flag Code | Flag Name | Description |
|---|---|---|
| 0 | valid | No quality issue detected |
| 1 | increment_out_of_bounds | Increment outside configured bounds |
| 2 | value_out_of_bounds | Value outside configured bounds |
| 3 | increment_stuck | Rate of change stuck |
| 4 | value_stuck | Consecutive constant values |
| 5 | corrupt | Value is in configured corrupt-code list |
| 6 | missing | Null or NaN value |
When multiple checks flag the same sample, the largest numeric code wins.
Corrupt Codes Configuration
Default DataQuality corrupt codes:
- [-99, -999, -9999, -99999, -999999, -9999999]
Wind object corrupt-code behavior:
- Turbine temperature categories in TEMPERATURE_CATEGORIES return [850].
- MET mast temperature categories in MET_MAST_TEMPERATURE_CATEGORIES return [850].
- Site categories return [].
- Non-temperature turbine and MET mast categories return [].
Passing [] to DataQuality disables corrupt-code flagging for that signal. The default DataQuality corrupt codes are used only when the DataQuality default is left unchanged.
TURBINE OBJECT - Quality Check Specifications
Power Production Variables
| Signal category | Range check | Stuck check |
|---|---|---|
ActivePower |
> 1.1 x rated_power |
60 minutes, tolerance 1e-5, only values >= 20 kW |
ActivePower_max |
> 1.1 x rated_power |
Default 60 minutes, tolerance 1e-5 because it is not in the turbine stuck map |
ActivePower_min |
Unbounded | Default 60 minutes, tolerance 1e-5 because it is not in the turbine stuck map |
ActivePower_std |
Unbounded | 60 minutes, tolerance 1e-5 |
reactive_power and variants |
Unbounded | Default 60 minutes, tolerance 1e-5 |
Rotational Speed Variables
| Signal category | Range check | Stuck check |
|---|---|---|
GeneratorSpeed |
0 to 5000 RPM | Default 60 minutes, tolerance 1e-5 |
GeneratorSpeed_min |
lower bound 0 | Default 60 minutes, tolerance 1e-5 |
GeneratorSpeed_max |
upper bound 5000 | Default 60 minutes, tolerance 1e-5 |
GeneratorSpeed_std |
Unbounded | Default 60 minutes, tolerance 1e-5 |
RotorSpeed |
0 to 100 RPM | Default 60 minutes, tolerance 1e-5 |
RotorSpeed_min |
lower bound 0 | Default 60 minutes, tolerance 1e-5 |
RotorSpeed_max |
upper bound 100 | Default 60 minutes, tolerance 1e-5 |
RotorSpeed_std |
Unbounded | Default 60 minutes, tolerance 1e-5 |
Pitch Control Variables
| Signal category | Range check | Stuck check |
|---|---|---|
Blade_PitchAngle |
-10 to 100 deg | 1 day, tolerance 1e-5 |
Blade_PitchAngle_min |
lower bound -10 | Default 60 minutes, tolerance 1e-5 |
Blade_PitchAngle_max |
upper bound 100 | Default 60 minutes, tolerance 1e-5 |
Blade_PitchAngle_std |
Unbounded | Default 60 minutes, tolerance 1e-5 |
Nacelle and Wind Angle Variables
| Signal category | Range check | Stuck check |
|---|---|---|
NacelleDirection |
0 to 360 deg | 600 minutes, tolerance 1e-5 |
NacelleDirection_min |
0 to 360 deg | Default 60 minutes, tolerance 1e-5 |
NacelleDirection_max |
0 to 360 deg | Default 60 minutes, tolerance 1e-5 |
NacelleDirection_std |
Unbounded | Default 60 minutes, tolerance 1e-5 |
wind_relative_angle |
0 to 360 deg | 60 minutes, tolerance 1e-5 |
wind_relative_angle_min |
0 to 360 deg | Default 60 minutes, tolerance 1e-5 |
wind_relative_angle_max |
0 to 360 deg | Default 60 minutes, tolerance 1e-5 |
WindDirection |
0 to 360 deg | 60 minutes, tolerance 1e-5 |
Torque Variables
| Signal category | Range check | Stuck check |
|---|---|---|
GeneratorTorque |
Unbounded | 60 minutes, tolerance 1e-5 |
GeneratorTorque_min, _max, _std |
Unbounded | Default 60 minutes, tolerance 1e-5 |
WindDataQuality does not calculate torque and does not calculate yaw-error or large-yaw-action signals. It only flags supplied time series.
Temperature Sensor Variables
| Signal category group | Range check | Stuck check | Corrupt codes |
|---|---|---|---|
AmbientTemperature |
-50 to 60 degC | Default 60 minutes, tolerance 1e-5 |
[850] |
Gearbox and generator temperature categories explicitly listed in RANGE_BOUNDS_MAP |
-40 to 100 degC | 300 minutes when listed in MIN_STUCK_DURATION_MAP; otherwise default 60 minutes |
[850] |
Other turbine temperature categories in TEMPERATURE_CATEGORIES |
Unbounded unless explicitly listed in RANGE_BOUNDS_MAP |
Default 60 minutes unless explicitly listed in MIN_STUCK_DURATION_MAP |
[850] |
Turbine-Mounted Wind Sensors
| Signal category | Range check | Stuck check |
|---|---|---|
WindSpeed |
0 to 50 m/s | 60 minutes, tolerance 1e-5 |
WindSpeed_std |
Unbounded | 60 minutes, tolerance 1e-5 |
WindSpeed_min |
lower bound 0 | Default 60 minutes, tolerance 1e-5 |
WindSpeed_max |
upper bound 50 | Default 60 minutes, tolerance 1e-5 |
Missing-Only Turbine Categories
| Signal category | Checks applied |
|---|---|
SetpointActivePower |
Missing only |
CommunicationState |
Missing only |
MET MAST OBJECT - Quality Check Specifications
Wind Speed Variables
| Signal category | Range check | Stuck check |
|---|---|---|
wmet_WindSpeed |
0 to 50 m/s | 60 minutes, tolerance 1e-5 |
wmet_WindSpeed_std |
Unbounded | 60 minutes, tolerance 1e-5 |
wmet_WindSpeed_min |
lower bound 0 | Default 60 minutes, tolerance 1e-5 |
wmet_WindSpeed_max |
upper bound 50 | Default 60 minutes, tolerance 1e-5 |
wmet_WindSpeed_avg_adc |
Unbounded | Default 60 minutes, tolerance 1e-5 |
Wind Direction Variables
| Signal category | Range check | Stuck check |
|---|---|---|
wmet_WindDirection |
0 to 360 deg | Default 60 minutes, tolerance 1e-5 |
wmet_WindDirection_min |
0 to 360 deg | Default 60 minutes, tolerance 1e-5 |
wmet_WindDirection_max |
0 to 360 deg | Default 60 minutes, tolerance 1e-5 |
wmet_WindDirection_std |
Unbounded | Default 60 minutes, tolerance 1e-5 |
Atmospheric Variables (Met Mast)
| Signal category | Range check | Stuck check | Corrupt codes |
|---|---|---|---|
wmet_AmbientTemperature |
-50 to 60 degC | Default 60 minutes, tolerance 1e-5 |
[850] |
wmet_atmospheric_pressure |
Unbounded | Default 60 minutes, tolerance 1e-5 |
none |
wmet_air_density |
Unbounded | Default 60 minutes, tolerance 1e-5 |
none |
wmet_relative_humidity |
0 to 100 percent | Default 60 minutes, tolerance 1e-5 |
none |
wmet_precipitation |
lower bound 0 | Default 60 minutes, tolerance 1e-5 |
none |
Derived Variables (Met Mast)
| Signal category | Range check | Stuck check |
|---|---|---|
wmet_turbulence_intensity |
upper bound 0.25 | Default 60 minutes, tolerance 1e-5 |
SITE OBJECT - Quality Check Specifications
Wind Speed Variables
| Signal category | Range check | Stuck check |
|---|---|---|
SiteWindSpeed |
0 to 50 m/s | 60 minutes, tolerance 1e-5 |
Active Power Variables
| Signal category | Range check | Stuck check |
|---|---|---|
SiteActivePower |
> 1.001 x capacity_dc_site x 1000 when capacity_dc_site exists |
60 minutes, tolerance 1e-5 |
ActivePowerMeter (SITE_POWER_FROM_METER) |
-1 percent to 102 percent of site capacity in MW | 20 minutes, tolerance 1e-5, only values between 1 percent and 98 percent of site capacity |
Atmospheric Variables (Site)
| Signal category | Range check | Stuck check |
|---|---|---|
AtmosphericPressure |
70927.5 to 131722.5 Pa | Default 1 hour, tolerance 1e-5 |
AirDensity |
0.8575 to 1.5925 kg/m^3 | Default 1 hour, tolerance 1e-5 |
METER OBJECT - Quality Check Specifications
Step 3_4 Wind Meter Data Quality.py runs two algorithms:
1. WindDataQuality on the meter input collection. Because Meter is not a Turbine, MetMast, or Site, this part uses default DataQuality settings.
2. MeterEnergyDataQuality on cumulative TotalEnergyProduced (ENERGY_PROD_METER).
MeterEnergyDataQuality behavior:
- Adds TotalEnergyProduced#dq_flag.
- Flags missing cumulative energy as missing.
- Unwraps detected fixed-modulus counter rollovers.
- Flags sustained flat active-period counters as stuck after min_stuck_minutes=120 by default.
- Flags active increments greater than or equal to 1.2 x ac_capacity x sample_hours as increment out of bounds.
- Flags inactive increments greater than or equal to 1 percent of the active threshold as increment out of bounds.
- Suppresses increment spikes after communication-out windows.
- Flags active-period rollbacks as value out of bounds.
- If the active-period bad fraction exceeds METER_ENERGY_MAX_BAD_FRACTION after at least METER_ENERGY_MIN_SAMPLES, the whole cumulative series is set to NaN and flagged missing.