Skip to content

dofliu/digiWindFarm

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

225 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

digiWindTurbine

Wind farm monitoring and digital twin platform with:

  • physics-based wind turbine simulation
  • 104 SCADA tags aligned to Bachmann Z72 definitions
  • fault injection and degradation scenarios
  • wind and grid condition control
  • Modbus TCP simulation
  • FastAPI backend with WebSocket streaming
  • React frontend for dashboard, detail, history, and settings

Quick Start

Local Development

# Backend + simulator + Modbus TCP (default port 8100)
pip install -r requirements.txt
python run.py

# Frontend (default port 3100, another terminal)
cd frontend
npm install
npm run dev

Open http://localhost:3100.

Docker Compose

docker compose up --build

Open http://localhost:3100. Backend runs on port 8100, Modbus TCP on 5020.

Ports are configured in .env (copy from .env.example):

  • Backend: BACKEND_PORT=8100
  • Frontend: VITE_PORT=3100
  • Modbus: MODBUS_PORT=5020

Use python run.py --auto-port to auto-find an available port if the default is busy. In Settings, select Physics Simulation (Backend) to use backend realtime simulation data.

Current Scope

Implemented and usable today:

  • turbine startup, synchronization, production, normal stop, and emergency stop
  • separated rotor and generator speeds with first drivetrain torsion model, gearbox oil temperature/viscosity effects, and gear tooth contact-ratio mesh stiffness ripple + tooth wear index
  • 10-point thermal model with residual heat behavior
  • vibration, yaw, wind field, wake, and per-turbine individuality
  • 7 fault scenarios with fault-to-physics coupling
  • grid frequency and voltage events with per-turbine ride-through differences
  • sensor noise, drift, stuck values, and quantization
  • history page with event markers, event details, focus windows, and CSV export
  • electrical response model (frequency-watt, reactive power, power factor, ride-through)
  • spectral vibration model (1P/3P/gear/HF/broadband bands, crest factor, kurtosis, BPFO/BPFI bearing defect frequencies, gear mesh sideband analysis)
  • fatigue/load model (tower/blade moments, rainflow cycle counting, DEL, Miner's damage, alarm thresholds, RUL estimation, tower SDOF dynamic response, tower shadow 3P blade load modulation, wind shear 1P azimuth-dependent blade loading, blade mass imbalance ω² force coupling)
  • fault lifecycle tracking with start/end duration events
  • event export API (JSON/CSV) with severity grouping
  • Docker Compose deployment (backend + frontend with nginx reverse proxy)

Physics model tracking:

Architecture

Physics / OPC Data Source
  -> DataBroker
  -> FastAPI REST + WebSocket
  -> SQLite history storage
  -> React dashboard / detail / history / settings
  -> Modbus TCP simulator

Main modules:

  • simulator/physics/
    • turbine_physics.py
    • power_curve.py
    • thermal_model.py
    • vibration_model.py
    • yaw_model.py
    • wind_field.py
    • fault_engine.py
    • electrical_model.py
    • vibration_spectral.py
    • fatigue_model.py
    • scada_registry.py
  • simulator/grid_model.py
  • server/
  • frontend/

Key Features

Physics Simulation

  • turbine state mapping 1-9
  • cut-in / startup / sync / production / stop / cut-out behavior
  • distinct normal-stop and emergency-stop curves
  • curtailment, service mode, and operator commands

Fault Injection

  • bearing_wear
  • gearbox_overheat
  • pitch_motor_fault
  • converter_cooling_fault
  • yaw_misalignment
  • generator_overspeed
  • transformer_overheat

Grid Control

  • profiles: nominal, low_freq, high_freq, undervoltage, overvoltage, weak_grid, recovery
  • manual frequency and voltage override
  • per-turbine derate, trip, and reconnect differences

History

  • GET /api/turbines/{id}/history
  • GET /api/export/history
  • backend history events stored in SQLite
  • history events include operator, fault, grid, wind, and state transitions
  • grid and wind config events support start/end durations
  • frontend History page supports:
    • turbine, time range, and sample-size controls
    • custom tag selection
    • event filters and event search
    • event detail panel with payload
    • focus windows around selected events
    • CSV export for current range or focused window

Core APIs

Health

  • GET /api/health

Turbines

  • GET /api/turbines
  • GET /api/turbines/{id}
  • GET /api/turbines/{id}/history
  • GET /api/turbines/{id}/trend
  • GET /api/turbines/farm-status
  • GET /api/turbines/farm-trend

Config

  • GET /api/config
  • POST /api/config/datasource
  • POST /api/config/simulation
  • GET /api/config/wind
  • POST /api/config/wind
  • POST /api/config/wind/clear
  • GET /api/config/simulation/time-scale
  • POST /api/config/simulation/time-scale
  • POST /api/config/simulation/generate-bulk
  • GET /api/config/grid
  • POST /api/config/grid
  • POST /api/config/grid/clear
  • GET /api/config/storage/stats
  • GET /api/config/sessions
  • POST /api/config/storage/maintenance
  • GET /api/config/turbine-spec
  • POST /api/config/turbine-spec
  • GET /api/config/turbine-spec/presets

Control

  • POST /api/control/command
  • POST /api/control/curtail
  • GET /api/control/{id}/status

Faults

  • GET /api/faults/scenarios
  • POST /api/faults/inject
  • GET /api/faults/active
  • POST /api/faults/clear
  • GET /api/faults/test-plans
  • POST /api/faults/test-plans/{plan_id}/run

Maintenance

  • GET /api/maintenance/work-orders
  • POST /api/maintenance/work-orders
  • GET /api/maintenance/work-orders/{id}
  • PATCH /api/maintenance/work-orders/{id}
  • GET /api/maintenance/technicians
  • POST /api/maintenance/technicians
  • PATCH /api/maintenance/technicians/{id}/status
  • GET /api/maintenance/events/compare?turbine_ids=WT001,WT002

i18n (Tag Translation)

  • GET /api/i18n/tags
  • GET /api/i18n/tags/all
  • GET /api/i18n/tags/registry

Modbus TCP

  • GET /api/modbus/status
  • POST /api/modbus/start
  • POST /api/modbus/stop
  • GET /api/modbus/registers

Export / Realtime

  • GET /api/export/snapshot
  • GET /api/export/history?format=csv
  • GET /api/export/events?format=json (also supports csv, with severity grouping)
  • ws://localhost:8100/ws/realtime

Frontend Pages

  • Dashboard
  • Turbine Detail
  • History
  • Settings
  • MaintenanceHub

Note:

  • maintenance work order backend and technician management are implemented
  • the frontend MaintenanceHub uses real API backend (SQLite-backed)

Data Storage

  • realtime data: in-memory trend buffer
  • historical data: SQLite
  • historical events: SQLite history_events
  • database file: wind_farm_data.db

Historical storage currently grows continuously and does not yet have a cleanup policy.

Documentation

Known Gaps

  • deployment hardening: JWT, RBAC, HTTPS not yet implemented (Docker Compose is available)
  • spectral alarm threshold curves not yet implemented; BPFO/BPFI, gear mesh sideband analysis, and crest factor/kurtosis anomaly alarms completed
  • coolant level / leak detection implemented (level tracking, pump cavitation, fault coupling) — see #75
  • ambient humidity effect on air cooling implemented (moist-air density + dew-point condensation penalty) — see #89
  • localized turbulence pockets implemented (Gaussian spatial TI boost pockets, per-turbine TI multiplier, WMET_LocalTi tag) — see #91
  • wake model upgraded to Bastankhah-Porté-Agel Gaussian (TI-dependent expansion, Ct-coupled deficit, sum-of-squares superposition, WMET_WakeDef tag) — see #93
  • dynamic wake meandering implemented (Larsen-DWM lateral AR(1) oscillation of wake centerline, σ_θ=0.3·TI, τ≈25 s, new WMET_WakeMndr SCADA tag) — see #95
  • yaw-induced wake deflection implemented (Bastankhah 2016 θ_c initial skew, per-source δ_y(x)=tan(θ_c)·x coupled to yaw_error, new WMET_WakeDefl SCADA tag; driven by yaw_misalignment fault and transient yaw lag) — see #97
  • atmospheric stability / diurnal shear-TI coupling implemented (Monin-Obukhov-simplified continuous stability score s ∈ [−1, +1] from solar time × wind mechanical mixing × cloud damping; drives wind shear exponent α ∈ [0.04, 0.30] and turbulence intensity multiplier ∈ [0.5, 1.6]; new WMET_ShearAlpha + WMET_AtmStab SCADA tags) — see #99
  • air density coupling implemented (moist-air ρ from ideal gas law + Buck/Magnus vapor correction; updated every step from ambient temp + humidity and injected into PowerCurveModel.air_density so aerodynamic power P ∝ ρ·V³ and thrust F ∝ ρ·V² both respond; ±10% swing between cold-winter and hot-humid days; new WMET_AirDensity SCADA tag) — see #101
  • wake-added turbulence intensity implemented (Crespo-Hernández 1996: TI_w(x, r=0) = 0.73·a^0.8325·TI_∞^0.0325·(x/D)^-0.32 with a = 0.5·(1−√(1−Ct)), near-field capped at x/D=5; shared Bastankhah Gaussian σ for radial decay; Frandsen sum-of-squares across upstream sources; combined with pocket TI in quadrature before AR(1) generator so downstream σ_v observably rises — T1 at ~7D sees 12% wake-added TI and +36% wind-speed std vs free-stream T0 in self-test; new WMET_WakeTi SCADA tag) — see #103
  • dynamic atmospheric pressure P(t) implemented (synoptic _pressure_state continuous score in [−1, +1] mapped to ±1500 Pa around ISA 101325 Pa, covering typical mid-latitude frontal amplitude 1013±15 hPa; fed through WindEnvironmentModel.get_air_density(ts, ..., pressure_pa=...) so ρ gains another ±1.5% time variability from weather fronts on top of #101's T/RH coupling; manual override locks P at ISA reference; new WMET_AmbPressure SCADA tag, hPa) — see #106
  • atmospheric-stability × wake-expansion coupling implemented (Bastankhah k* = k_neutral · clamp(1 + 0.30·s, 0.55, 1.45) following Abkar & Porté-Agel 2015 / Peña et al. 2016; stable ABL slows wake recovery, convective ABL speeds it up; at 6 D / V=10 m/s / TI=8 % the self-test shows +33.8 % wake deficit at s=−1 and −22.0 % at s=+1; no new SCADA tag — observable via WMET_WakeDef × WMET_AtmStab correlation) — see #109
  • atmospheric-stability × wind-veer coupling implemented (per-turbine wind_veer_rate (#79) is multiplied by clamp(1 − s, 0.3, 2.5), following Holton §5.3 / Stull §8.5 / van der Laan et al. 2017; stable nocturnal ABL preserves the Ekman spiral → ~0.20 °/m and +37 % tower side-side moment vs neutral, convective afternoon mixes it out → ~0.03 °/m and −26 %; effective veer rate is shared between the aero power-loss block and fatigue_model.step() so structural loads and aero power stay consistent; no new SCADA tag — observable via WMET_AtmStab × WLOD_TwrSsMom correlation) — see #111
  • atmospheric-stability × wake-meander τ_m coupling implemented (the Larsen-DWM atmospheric integral timescale is now τ_m = 25 · clamp(1 − 0.6·s, 0.4, 2.0) s following Counihan 1975 / Larsen DWM 2008 / Peña & Hahmann 2012; stable ABL → 40 s slow meander, neutral → 25 s baseline, convective → 10 s fast turnover; lateral amplitude σ_θ stays at 0.3·TI so the amplitude path is owned by #99 TI-mult while τ_m owns the timescale path; self-test on a 4000 s AR(1) series shows lag-25 s autocorrelation 0.45 (stable) vs 0.28 (neutral) vs 0.01 (convective) and zero-crossing rate 0.082 vs 0.140 — slower meander under stable conditions and faster turnover under convection; no new SCADA tag — observable via WMET_WakeMndr × WMET_AtmStab autocorrelation) — see #113
  • atmospheric-stability × turbulence integral length scale L_u coupling implemented (TurbulenceGenerator.step() applies L_u_eff = 340 · clamp(1 − 0.6·s, 0.4, 2.0) m on top of the IEC 61400-1 neutral baseline so the AR(1) wind-speed autocorrelation timescale τ = L_u/V is stability-modulated. Stable nocturnal ABL → L_u=544 m, τ ≈ 54 s @ 10 m/s; neutral → 340 m, 34 s; convective afternoon → 136 m, 14 s. Validated on a 4000 s series at TI=0.10: observed lag-30 s autocorrelation 0.574 / 0.401 / 0.097 vs analytical 0.576 / 0.414 / 0.110 (stable / neutral / convective); steady-state σ_v stays at TI·V ≈ 1.0 m/s in all cases — the amplitude path is owned by #99's TI multiplier, this PR adds only the orthogonal timescale path. The same s ∈ [−1, +1] feeds both the farm-wide _turbulence_gen and every per-turbine _turb_gens[i].step(...) so the whole farm shares one ABL timescale. No new SCADA tag — observable via WMET_AtmStab × WROT_RotSpd low-frequency autocorrelation. References: Counihan 1975 / Kaimal & Finnigan 1994 / Peña & Hahmann 2012 / IEC 61400-1 ed.4 Annex C — see #115)
  • nacelle anemometer transfer function (NTF) implemented (IEC 61400-12-1 Annex D: real cup/sonic anemometer sits ~1.5R behind hub on top of nacelle, reads systematically below free-stream because of axial induction. NTF formula V_raw = V_∞ · (1 − 0.55·a) with a = 0.5·(1 − √(1 − Ct)) derived from the 1-D momentum theory and the existing aero_out.ct. Stopped/parked rotor: bluff-body speed-up 1.04·V_∞ instead of induction. Self-test (7/7 + monotonicity): Region 2 Ct≈0.82 → 0.84·V_∞; Region 2.5 → 0.89·V_∞; Region 3 Ct≈0.30 → 0.96·V_∞; cut-out → 1.04·V_∞. Backwards compatible — WMET_WSpeedNac keeps free-stream semantics so examples/data_quality_analysis.py and OPC adapter consumers still get the same number; new WMET_WSpeedRaw SCADA tag exposes the as-measured anemometer reading for power-curve verification studies. 103 SCADA tags total — see #117)
  • nacelle wind vane transfer function (WVTF) implemented (IEC 61400-12-2 Annex E: real wind vane co-located with the nacelle anemometer reads systematic swirl bias from rotor wake, since the rotor converts linear inflow into linear+rotational outflow (angular-momentum conservation). Closed form θ_s ≈ Ct/(2·λ) [rad] (Burton, Sharpe, Jenkins & Bossanyi 2011 Wind Energy Handbook 2nd ed. §3.7) reuses aero_out.ct and aero_out.tsr already computed by power_curve.get_power_cp, so there is zero extra cost and no new RNG mutation. Right-handed rotor (industry standard, clockwise from upwind) → +bias on the downstream vane. Operating-state branching: producing/starting with rotor_speed > 1 RPM and tsr > 1 applies the swirl bias; otherwise (stopped/parked, no rotor swirl) bias = 0°. Final clamp ±8° keeps the result inside physically observed bounds. Self-test (8/8 + Ct↑→bias↑ + λ↑→bias↓ monotonicity): Region 2 (Ct≈0.82, λ≈7) → +3.36°; Region 2.5 (Ct≈0.65, λ≈6) → +3.10°; Region 3 (Ct≈0.30, λ≈5) → +1.72°; starting (Ct≈0.55, λ≈6) → +2.63°; stopped/cut-out → 0°; extreme Ct=0.95/λ=2 clamps at +8°; 360° wrap-around verified (358° + 3.4° → 1.36°). Backwards compatible — WMET_WDirAbs intentionally keeps free-stream semantics so the wake-model upstream indexing, yaw controller (yaw_model.py), frontend wind rose, and OPC adapter consumers are all unchanged; new WMET_WDirRaw (REAL32, °, 0–360) exposes the as-measured vane reading for IEC 61400-12-2 nacelle power-curve studies, vane-miscalibration fault simulation, and the WMET_WDirRaw - yaw_angle observation channel that mirrors how field engineers diagnose systematic yaw misalignment. Pairs with #117 NTF to form a complete IEC 61400-12-1/2 nacelle sensor transfer function chain. 104 SCADA tags total (was 103): +1 raw nacelle wind vane tag (WMET_WDirRaw) — see #119
  • yaw-skew Glauert correction for NTF + WVTF implemented (#125, IEC 61400-12-1/2 / Glauert 1935 / Burton et al. 2011 §3.10 / Castillo-Negro 2008): closes the IEC 61400-12-1/2 nacelle sensor chain under non-zero yaw error. Under yaw misalignment γ the rotor's axial induction at the anemometer position reduces to a · cos²(γ) (Glauert combined-momentum / Coleman skewed-wake), and the swirl-plane angle projects onto the nacelle plane as θ_s · cos(γ). Both reuse yaw_out["yaw_error"] already in step() (no extra cost, no new RNG). γ clamped ±45°; γ=0 reproduces #117/#119 baseline exactly. Self-test 14/14 PASS: Region 2 / γ=0° → 0.842, γ=15° → 0.852 (NTF correction shrinks 6.7% per cos² law), γ=30° → 0.881 (shrinks 25%), γ=45° → 0.921 (correction halved); WVTF γ=15° → +3.24°, γ=30° → +2.91° (swirl projection cos γ); γ symmetry, γ↑ → factor↑/bias↓ monotonicity, ±45° clamp all verified. Pairs with the yaw_misalignment fault scenario so the as-measured WMET_WSpeedRaw and WMET_WDirRaw now respond physically to operational yaw error and to vane-miscalibration faults. Backwards compatible — WMET_WSpeedNac and WMET_WDirAbs keep free-stream semantics. No new SCADA tag — observable via (WMET_WSpeedRaw / WMET_WSpeedNac − 1) × WYAW_YwVn1AlgnAvg5s and (WMET_WDirRaw − WMET_WDirAbs) × WYAW_YwVn1AlgnAvg5s correlations. Also cleaned up duplicate WMET_WDirRaw registration left by the #119 merge in both turbine_physics.py::step() output dict and scada_registry.py _TAGS list (104 physics tags / 110 total registry entries unchanged).
  • full protection relay coordination not yet implemented
  • frontend RUL visualization pending (fatigue alarm thresholds, RUL estimation, and alarm event integration implemented — see #57)
  • dependency security vulnerabilities pending upgrade (see #48)
  • use the status and roadmap docs as the source of truth for current implementation state

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors