energy calculation including shading effects
This commit is contained in:
parent
a086431c46
commit
ca4fcd8f49
0
Utilities/Optimisers.py
Normal file
0
Utilities/Optimisers.py
Normal file
@ -12,13 +12,14 @@ from Utilities.Processes import (
|
|||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
def get_location(c):
|
def get_location(c):
|
||||||
location = pvlib.location.Location(
|
location = pvlib.location.Location(
|
||||||
latitude=c["environment"]["location"]["latitude"],
|
latitude=c["environment"]["location"]["latitude"],
|
||||||
longitude=c["environment"]["location"]["longitude"],
|
longitude=c["environment"]["location"]["longitude"],
|
||||||
tz=c["simulation_date_time"]["tz"],
|
tz=c["simulation_date_time"]["tz"],
|
||||||
)
|
)
|
||||||
|
|
||||||
return location
|
return location
|
||||||
|
|
||||||
|
|
||||||
@ -85,9 +86,7 @@ def define_grid_layout(c):
|
|||||||
for i in range(int(max__panels_per_row)):
|
for i in range(int(max__panels_per_row)):
|
||||||
if counter < no_of_panels:
|
if counter < no_of_panels:
|
||||||
x.append(i * c["panel"]["dimensions"]["width"])
|
x.append(i * c["panel"]["dimensions"]["width"])
|
||||||
y.append(
|
y.append(j * pitch)
|
||||||
j * pitch
|
|
||||||
)
|
|
||||||
z.append(0)
|
z.append(0)
|
||||||
counter += 1
|
counter += 1
|
||||||
else:
|
else:
|
||||||
@ -121,10 +120,111 @@ def get_solar_data(c):
|
|||||||
|
|
||||||
# Get solar position data using PVLib
|
# Get solar position data using PVLib
|
||||||
solar_positions = location.get_solarposition(times)
|
solar_positions = location.get_solarposition(times)
|
||||||
clearsky_data = location.get_clearsky(times)
|
# filter solar positions to only include times when the sun is above the horizon
|
||||||
|
solar_positions = solar_positions[solar_positions["apparent_elevation"] > 0]
|
||||||
|
# get datetime range from solar_positions
|
||||||
|
day_times = solar_positions.index
|
||||||
|
clearsky_data = location.get_clearsky(day_times)
|
||||||
|
|
||||||
return solar_positions, clearsky_data
|
return solar_positions, clearsky_data
|
||||||
|
|
||||||
|
|
||||||
def calculate_shading(c, coordinates, solar_positions):
|
def calculate_shading(c):
|
||||||
|
panel_coordinates, no_of_panels = define_grid_layout(c)
|
||||||
|
solar_positions, clearsky_data = get_solar_data(c)
|
||||||
|
|
||||||
|
# split the solar positions data into morning and afternoon, using solar azimuth of
|
||||||
|
# 180 degrees as the threshold
|
||||||
|
morning_solar_positions = solar_positions[solar_positions["azimuth"] <= 180]
|
||||||
|
afternoon_solar_positions = solar_positions[solar_positions["azimuth"] > 180]
|
||||||
|
|
||||||
|
# the first row is always not shaded so exclude
|
||||||
|
no_of_rows = np.unique(panel_coordinates["y"]).shape[0]
|
||||||
|
no_of_shaded_rows = no_of_rows - 1
|
||||||
|
|
||||||
|
collector_width = c["panel"]["dimensions"]["length"]
|
||||||
|
# calculate delta between unique y coordinates of panels to get pitch
|
||||||
|
pitch = np.unique(panel_coordinates["y"])[1] - np.unique(panel_coordinates["y"])[0]
|
||||||
|
surface_to_axis_offset = 0
|
||||||
|
shaded_row_rotation = c["array"]["tilt"]
|
||||||
|
shading_row_rotation = c["array"]["tilt"]
|
||||||
|
axis_tilt = 0
|
||||||
|
axis_azimuth = c["array"]["front_face_azimuth"]
|
||||||
|
|
||||||
|
morning_shaded_fraction = pvlib.shading.shaded_fraction1d(
|
||||||
|
solar_zenith=morning_solar_positions["zenith"],
|
||||||
|
solar_azimuth=morning_solar_positions["azimuth"],
|
||||||
|
axis_azimuth=axis_azimuth,
|
||||||
|
shaded_row_rotation=shaded_row_rotation,
|
||||||
|
shading_row_rotation=shading_row_rotation,
|
||||||
|
collector_width=collector_width,
|
||||||
|
pitch=pitch,
|
||||||
|
surface_to_axis_offset=surface_to_axis_offset,
|
||||||
|
axis_tilt=axis_tilt,
|
||||||
|
)
|
||||||
|
morning_shaded_fraction = morning_shaded_fraction * no_of_shaded_rows / no_of_rows
|
||||||
|
|
||||||
|
afternoon_shaded_fraction = pvlib.shading.shaded_fraction1d(
|
||||||
|
solar_zenith=afternoon_solar_positions["zenith"],
|
||||||
|
solar_azimuth=afternoon_solar_positions["azimuth"],
|
||||||
|
axis_azimuth=axis_azimuth + 180,
|
||||||
|
shaded_row_rotation=shaded_row_rotation,
|
||||||
|
shading_row_rotation=shading_row_rotation,
|
||||||
|
collector_width=collector_width,
|
||||||
|
pitch=pitch,
|
||||||
|
surface_to_axis_offset=surface_to_axis_offset,
|
||||||
|
axis_tilt=axis_tilt,
|
||||||
|
)
|
||||||
|
afternoon_shaded_fraction = (
|
||||||
|
afternoon_shaded_fraction * no_of_shaded_rows / no_of_rows
|
||||||
|
)
|
||||||
|
logger.info(
|
||||||
|
f"Shaded fraction calculated for morning and afternoon solar positions."
|
||||||
|
)
|
||||||
|
|
||||||
|
# calculate irradiance on plane of array
|
||||||
|
poa_front = pvlib.irradiance.get_total_irradiance(
|
||||||
|
surface_tilt=c["array"]["tilt"],
|
||||||
|
surface_azimuth=c["array"]["front_face_azimuth"],
|
||||||
|
solar_zenith=morning_solar_positions["zenith"],
|
||||||
|
solar_azimuth=morning_solar_positions["azimuth"],
|
||||||
|
dni=clearsky_data["dni"],
|
||||||
|
ghi=clearsky_data["ghi"],
|
||||||
|
dhi=clearsky_data["dhi"],
|
||||||
|
)
|
||||||
|
# drop rows with poa_global NaN values
|
||||||
|
poa_front = poa_front.dropna(subset=["poa_global"])
|
||||||
|
|
||||||
|
poa_rear = pvlib.irradiance.get_total_irradiance(
|
||||||
|
surface_tilt=180 - c["array"]["tilt"],
|
||||||
|
surface_azimuth=c["array"]["front_face_azimuth"] + 180,
|
||||||
|
solar_zenith=afternoon_solar_positions["zenith"],
|
||||||
|
solar_azimuth=afternoon_solar_positions["azimuth"],
|
||||||
|
dni=clearsky_data["dni"],
|
||||||
|
ghi=clearsky_data["ghi"],
|
||||||
|
dhi=clearsky_data["dhi"],
|
||||||
|
)
|
||||||
|
# drop rows with poa_global NaN values
|
||||||
|
poa_rear = poa_rear.dropna(subset=["poa_global"])
|
||||||
|
|
||||||
|
effective_front = (
|
||||||
|
poa_front["poa_global"]
|
||||||
|
* (1 - morning_shaded_fraction)
|
||||||
|
* c["panel"]["efficiency"]
|
||||||
|
)
|
||||||
|
effective_rear = (
|
||||||
|
poa_rear["poa_global"]
|
||||||
|
* (1 - afternoon_shaded_fraction)
|
||||||
|
* c["panel"]["bifaciality"]
|
||||||
|
* c["panel"]["efficiency"]
|
||||||
|
)
|
||||||
|
|
||||||
|
energy_front = effective_front * 15 / 60 / 1e3
|
||||||
|
energy_rear = effective_rear * 15 / 60 / 1e3
|
||||||
|
energy_total = energy_front.sum() + energy_rear.sum()
|
||||||
|
logger.info(f"Energy yield calculated: {energy_total} kWh/m2")
|
||||||
|
|
||||||
|
panel_area = c["panel"]["dimensions"]["length"] * c["panel"]["dimensions"]["width"]
|
||||||
|
total_area = panel_area * no_of_panels
|
||||||
|
total_energy = energy_total * total_area
|
||||||
|
logger.info(f"Total energy yield calculated: {total_energy} kWh")
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
array:
|
array:
|
||||||
system_size: 100 # in kWp
|
system_size: 400 # in kWp
|
||||||
spacing: 1.5 # spacing between adjacent panel rows in m
|
spacing: 0.5 # spacing between adjacent panel rows in m
|
||||||
edge_setback: 1.8 # distance from the edge of the roof to the array
|
edge_setback: 1.8 # distance from the edge of the roof to the array
|
||||||
front_face_azimuth: 90 # 90=east, 180=south, 270=west
|
front_face_azimuth: 90 # 90=east, 180=south, 270=west
|
||||||
tilt: 90 # just 0 and 90 are supported for now
|
tilt: 90 # just 0 and 90 are supported for now
|
||||||
@ -24,6 +24,7 @@ environment:
|
|||||||
|
|
||||||
panel:
|
panel:
|
||||||
peak_power: 710 # in Wp
|
peak_power: 710 # in Wp
|
||||||
|
efficiency: 0.229 # max efficiency of the front face
|
||||||
bifaciality: 0.85 # rear face efficiency relative to front face
|
bifaciality: 0.85 # rear face efficiency relative to front face
|
||||||
# dimensions all in m
|
# dimensions all in m
|
||||||
dimensions:
|
dimensions:
|
||||||
|
4
main.py
4
main.py
@ -1,7 +1,7 @@
|
|||||||
# %%
|
# %%
|
||||||
import yaml
|
import yaml
|
||||||
import logging
|
import logging
|
||||||
from Utilities.Shading import define_grid_layout
|
from Utilities.Shading import calculate_shading
|
||||||
|
|
||||||
logging.basicConfig(
|
logging.basicConfig(
|
||||||
level=logging.INFO,
|
level=logging.INFO,
|
||||||
@ -24,7 +24,7 @@ with open(config_path, "r") as file:
|
|||||||
logger.info("Configuration loaded successfully.")
|
logger.info("Configuration loaded successfully.")
|
||||||
logger.debug(f"Configuration: {c}")
|
logger.debug(f"Configuration: {c}")
|
||||||
|
|
||||||
shading = define_grid_layout(c)
|
shading = calculate_shading(c)
|
||||||
logger.info("Shading calculation completed successfully.")
|
logger.info("Shading calculation completed successfully.")
|
||||||
|
|
||||||
# %%
|
# %%
|
||||||
|
Loading…
x
Reference in New Issue
Block a user