8.3 KiB
☀️ cyberbee PV Simulator
A modular, realistic photovoltaic plant simulator written in Python.
cyberbee PV Simulator generates synthetic time-series data for an entire PV plant hierarchy — from individual panels up to the plant level — with physically grounded models, configurable fault injection, and multi-format export.
Features
Physical modelling
- Solar position computed via
pvlib(elevation, azimuth, zenith, angle of incidence) - Clear-sky irradiance with seasonal and daily variation (GHI, DNI, DHI, POA)
- Module temperature model (simplified NOCT approach)
- Temperature coefficient applied to power output
- Annual degradation of panels
- Sensor noise (Gaussian)
Fault simulation
- Panel failure, soiling, and partial shading
- Combiner box offline
- Inverter shutdown
- Configurable daily failure probabilities per component level
- Fault severity and reduction factors
Weather
- Configurable cloud factor with random variability
- Rain events with daily probability
- Ambient temperature (annual mean + daily swing)
Hierarchical aggregation
PV Plant
├── Inverter 1
│ ├── Combiner Box 1
│ │ ├── String 1 → Panel 1 … Panel 20
│ │ └── String 2 → Panel 1 … Panel 20
│ └── Combiner Box 2
│ └── ...
└── Inverter 2
└── ...
Output & export
- CSV, Parquet, JSON, SQLite
- Per-component time series (panel, combiner, inverter, plant, weather, faults)
- KPI and statistics: energy yield, performance ratio, availability, specific yield, clipping losses, daily/monthly aggregations, fault summaries
Project Structure
pv_simulator/
│
├── config/
│ └── plant.json # Plant configuration
│
├── pvsim/
│ ├── __init__.py
│ ├── panel.py # PVPanel model
│ ├── combiner.py # CombinerBox model
│ ├── inverter.py # Inverter model
│ ├── plant.py # PVPlant (top-level object)
│ ├── sun.py # Solar position model (pvlib)
│ ├── weather.py # Meteorological model
│ ├── faults.py # Fault manager and fault types
│ ├── simulator.py # Simulation engine (PVSimulator)
│ ├── exporter.py # CSV / Parquet / JSON export
│ ├── statistics.py # KPI and statistics
│ └── utils.py # Shared utilities
│
├── output/ # Generated data (auto-created)
│
├── run.py # Entry point
├── requirements.txt
└── README.md
Installation
git clone https://github.com/your-username/pv-simulator.git
cd pv-simulator
python -m venv .venv
source .venv/bin/activate # Linux / macOS
# .venv\Scripts\activate # Windows
pip install -r requirements.txt
Requirements
| Library | Purpose |
|---|---|
numpy |
Numerical computations |
pandas |
Time-series management, CSV/Parquet export |
matplotlib |
Production charts |
scipy |
Statistical distributions and realistic noise |
pvlib |
Solar position, irradiance models, PV physics |
networkx |
Plant hierarchy representation |
pyyaml |
YAML configuration support |
tqdm |
Progress bar for long simulations |
Configuration
The entire plant is described in pv_simulator/config/plant.json. No code changes are needed to resize or reconfigure the plant.
{
"plant": {
"name": "ZAK_PV_Simulator",
"location": {
"latitude": 45.4642,
"longitude": 9.1900,
"timezone": "Europe/Rome",
"altitude": 120
},
"simulation": {
"time_resolution_minutes": 5,
"start_date": "2026-01-01 00:00:00",
"end_date": "2026-12-31 23:55:00"
}
},
"layout": {
"inverters": [
{
"id": "INV_001",
"nominal_power_kW": 100,
"combiners": [
{
"id": "CB_001",
"strings": 4,
"panels_per_string": 20,
"orientation": { "tilt_deg": 30, "azimuth_deg": 180 }
}
]
}
]
}
}
The default configuration generates:
| Component | Count |
|---|---|
| Inverters | 2 |
| Combiner boxes | 3 |
| Panels | 240 |
| Nominal DC power | 108 kWp |
Usage
Run a full simulation
from datetime import datetime
from pvsim.simulator import PVSimulator, SimulationConfig
from pvsim.exporter import SimulationExporter
from pvsim.statistics import SimulationStatistics
config = SimulationConfig(
start=datetime(2026, 6, 21),
end=datetime(2026, 6, 22),
timestep_minutes=5,
generate_random_faults=True,
)
result = simulator.run(config)
Compute KPIs
stats = SimulationStatistics(result)
kpi = stats.plant_kpi()
print(f"Energy produced : {kpi.energy_kWh:.1f} kWh")
print(f"Peak power : {kpi.peak_power_W:.0f} W")
print(f"Performance ratio: {kpi.performance_ratio:.2%}")
print(f"Availability : {kpi.availability:.2%}")
Export data
exporter = SimulationExporter(output_dir="output")
exporter.export_all(result, csv=True, parquet=True, json=True, statistics=True)
Output Structure
output/
│
├── simulation.json # Simulation summary
├── plant_kpi.json # Plant-level KPIs
│
├── panel_kpi.csv
├── combiner_kpi.csv
├── inverter_kpi.csv
├── daily_statistics.csv
├── monthly_statistics.csv
├── fault_summary.csv
│
├── csv/
│ ├── weather.csv
│ ├── panel.csv
│ ├── combiner.csv
│ ├── inverter.csv
│ ├── plant.csv
│ └── faults.csv
│
└── parquet/
├── weather.parquet
├── panel.parquet
├── combiner.parquet
├── inverter.parquet
├── plant.parquet
└── faults.parquet
Data Model
Each simulation timestep produces records at every level of the hierarchy.
Panel
| Field | Description |
|---|---|
timestamp |
Measurement instant |
irradiance_Wm2 |
Incident irradiance |
module_temperature_C |
Module temperature |
voltage_V |
Panel voltage |
current_A |
Panel current |
power_W |
Instantaneous power |
energy_Wh |
Energy in timestep |
soiling_factor |
Soiling loss factor |
degradation_factor |
Cumulative degradation |
enabled |
Panel operational status |
Combiner Box
| Field | Description |
|---|---|
dc_power_W |
Aggregated DC power |
dc_voltage_V |
Bus voltage |
dc_current_A |
Total current |
active_panel_count |
Active panels |
availability |
Fraction of active panels |
status |
normal / idle / fault |
Inverter
| Field | Description |
|---|---|
dc_power_W |
DC input power |
ac_power_W |
AC output power |
efficiency |
Conversion efficiency |
clipping_loss_W |
Clipping losses |
temperature_C |
Internal temperature |
status |
normal / idle / fault |
Plant
| Field | Description |
|---|---|
ac_power_W |
Total AC power |
energy_Wh |
Energy in timestep |
performance_ratio |
PR (AC / nominal) |
availability |
Active panel fraction |
fault_active |
Any active fault |
Simulation Pipeline
pv_simulator/config/plant.json
│
▼
PVPlant (built from config)
│
▼
PVSimulator.run()
│
▼
SimulationResult
│
├──────────────────┐
▼ ▼
statistics.py exporter.py
│ │
▼ ├── CSV
KPI ├── Parquet
├── JSON
└── SQLite (optional)
Planned Improvements
- Single-diode model via
pvlibfor accurate I-V curves - Partial shading with bypass diode simulation
- String-level mismatch modelling
- Hot-spot simulation
- Sensor drift and intermittent faults
- Streaming / chunked export for multi-year simulations at 5-minute resolution
- Diagnostic alarms per component
- Interactive dashboard (Plotly / Streamlit)
License
MIT License — see LICENSE for details.
Built as part of the ZAK project — a Linux-based measurement and monitoring platform for industrial and renewable energy systems.