-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathsolar_park_simulator.py
74 lines (65 loc) · 3.7 KB
/
solar_park_simulator.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
import numpy as np
from numba import jit
from typing import List, Dict, Any
from logging_config import log_exceptions, get_logger
from weather_simulator import WeatherSimulator
class SolarParkSimulator:
def __init__(self, weather_simulator: WeatherSimulator, total_capacity: float, inverter_capacity: float,
performance_ratio: float):
self.logger = get_logger(self.__class__.__name__)
self.total_capacity = total_capacity
self.inverter_capacity = inverter_capacity
self.performance_ratio = performance_ratio
self.weather_simulator = weather_simulator
# Panel specifications
self.panel_efficiency = 0.2
self.temp_coefficient = -0.0035
self.dust_factor = 0.98
self.misc_losses = 0.97
self.annual_degradation = 0.005
self.years_in_operation = 0
@log_exceptions
def calculate_hourly_energy(self, weather: Dict[str, float]):
return self._calculate_hourly_energy_optimized(
self.total_capacity, self.inverter_capacity, self.performance_ratio,
self.panel_efficiency, self.temp_coefficient, self.dust_factor,
self.misc_losses, self.annual_degradation, self.years_in_operation,
weather['sun_intensity'], weather['temperature'], weather['humidity'],
weather['cloud_cover'], weather['wind_speed'], weather['is_raining']
)
@staticmethod
@jit(nopython=True)
def _calculate_hourly_energy_optimized(total_capacity: float, inverter_capacity: float, performance_ratio: float,
panel_efficiency: float, temp_coefficient: float, dust_factor: float,
misc_losses: float, annual_degradation: float, years_in_operation: float,
sun_intensity: float, temperature: float, humidity: float,
cloud_cover: float, wind_speed: float, is_raining: bool) -> float:
degradation_factor = (1 - annual_degradation) ** years_in_operation
base_energy = total_capacity * sun_intensity * performance_ratio * degradation_factor
temp_adjustment = 1 + temp_coefficient * (temperature - 25)
humidity_adjustment = 1 - (humidity - 50) * 0.001
cloud_adjustment = 1 - 0.75 * cloud_cover
wind_cooling = 1 + 0.001 * wind_speed
rain_adjustment = 0.9 if is_raining else 1
energy_produced = (base_energy * temp_adjustment * humidity_adjustment *
cloud_adjustment * wind_cooling * rain_adjustment *
dust_factor * misc_losses)
inverter_efficiency = min(0.9 + 0.05 * (energy_produced / inverter_capacity), 0.98)
return min(energy_produced * inverter_efficiency, inverter_capacity)
def simulate_annual_production(self) -> Dict[str, Any]:
self.logger.info("Starting annual simulation")
weather_data = self.weather_simulator.simulate_year()
hourly_production = np.array([self.calculate_hourly_energy(hour) for hour in weather_data])
total_annual_production = np.sum(hourly_production)
specific_yield = total_annual_production / self.total_capacity
self.logger.info("Complete annual simulation")
return {
'energy_production': hourly_production,
'weather_data': weather_data,
'total_annual_production': total_annual_production,
'specific_yield': specific_yield
}
def get_daily_production(self, weather_data: Dict[str, List[float]]) -> List[float]:
return [self.calculate_hourly_energy(
{key: weather_data[key][i] for key in weather_data}
) for i in range(24)]