Simulatore Pannello Fotovoltaico

This commit is contained in:
2026-07-18 14:18:41 +00:00
parent 265d9cd188
commit 20d2e8f7ba

243
pvsim/panel.py Normal file
View File

@@ -0,0 +1,243 @@
```python
"""
panel.py
Modello del singolo pannello fotovoltaico.
Ogni pannello riceve dal simulatore:
- Irradianza [W/m²]
- Temperatura ambiente [°C]
- Timestamp
e restituisce le principali grandezze elettriche.
"""
from __future__ import annotations
from dataclasses import dataclass, field
from datetime import datetime
from typing import Dict
import random
import math
@dataclass
class PVPanel:
panel_id: str
nominal_power: float = 450.0 # W
area: float = 2.1 # m²
vmp: float = 41.5
imp: float = 10.85
voc: float = 49.8
isc: float = 11.35
temp_coeff: float = -0.0035 # -0.35 %/°C
nominal_temp: float = 25.0
annual_degradation: float = 0.005
sensor_noise: float = 0.01
# stato pannello
enabled: bool = True
soiling_factor: float = 1.0
degradation: float = 1.0
total_energy_Wh: float = 0.0
# ------------------------------------------------------------------
def module_temperature(
self,
ambient_temperature: float,
irradiance: float
) -> float:
"""
Stima della temperatura del modulo.
Formula semplificata:
Tmodule = Tamb + irradiance * 0.03
"""
return ambient_temperature + irradiance * 0.03
# ------------------------------------------------------------------
def degradation_factor(
self,
years: float
) -> float:
return (1.0 - self.annual_degradation) ** years
# ------------------------------------------------------------------
def compute_power(
self,
irradiance: float,
ambient_temperature: float,
years_from_start: float
) -> float:
if not self.enabled:
return 0.0
module_temp = self.module_temperature(
ambient_temperature,
irradiance
)
temp_factor = (
1 +
self.temp_coeff *
(module_temp - self.nominal_temp)
)
degr = self.degradation_factor(years_from_start)
power = (
self.nominal_power *
(irradiance / 1000.0) *
temp_factor *
degr *
self.soiling_factor
)
power = max(power, 0.0)
noise = random.gauss(1.0, self.sensor_noise)
return power * noise
# ------------------------------------------------------------------
def compute_voltage(
self,
power: float
) -> float:
if power <= 0:
return 0.0
voltage = self.vmp * (
0.98 + 0.04 * random.random()
)
return voltage
# ------------------------------------------------------------------
def compute_current(
self,
power: float,
voltage: float
) -> float:
if voltage <= 0:
return 0.0
return power / voltage
# ------------------------------------------------------------------
def update(
self,
timestamp: datetime,
irradiance: float,
ambient_temperature: float,
years_from_start: float,
timestep_minutes: float
) -> Dict:
power = self.compute_power(
irradiance,
ambient_temperature,
years_from_start
)
voltage = self.compute_voltage(power)
current = self.compute_current(
power,
voltage
)
module_temp = self.module_temperature(
ambient_temperature,
irradiance
)
energy = power * timestep_minutes / 60.0
self.total_energy_Wh += energy
return {
"timestamp": timestamp,
"panel_id": self.panel_id,
"irradiance_Wm2": irradiance,
"ambient_temperature_C": ambient_temperature,
"module_temperature_C": module_temp,
"voltage_V": voltage,
"current_A": current,
"power_W": power,
"energy_Wh": energy,
"total_energy_Wh": self.total_energy_Wh,
"enabled": self.enabled,
"soiling_factor": self.soiling_factor,
"degradation_factor":
self.degradation_factor(years_from_start)
}
# ------------------------------------------------------------------
def fail(self):
self.enabled = False
# ------------------------------------------------------------------
def repair(self):
self.enabled = True
# ------------------------------------------------------------------
def soil(self, loss=0.9):
self.soiling_factor = loss
# ------------------------------------------------------------------
def clean(self):
self.soiling_factor = 1.0
# ------------------------------------------------------------------
def __repr__(self):
return (
f"PVPanel("
f"{self.panel_id}, "
f"{self.nominal_power}W)"
)