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.