-
Notifications
You must be signed in to change notification settings - Fork 1.2k
Expand file tree
/
Copy pathplot_transposition_gain.py
More file actions
124 lines (106 loc) · 5.19 KB
/
plot_transposition_gain.py
File metadata and controls
124 lines (106 loc) · 5.19 KB
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
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
"""
Modeling Transposition Gain
===========================
Calculating the gain in insolation of a tilted module over a flat module.
"""
# %%
# This example shows how to evaluate the transposition gain of a racking
# strategy. The transposition gain is the additional insolation collected
# by orienting at a tilt instead of horizontal; using PV modeling lingo, it's
# the increase in POA (plane of array) insolation over GHI (global horizontal
# irradiance) insolation.
#
# This example uses a TMY dataset and the
# :py:meth:`pvlib.irradiance.get_total_irradiance` function to transpose
# irradiance components to POA irradiance for various fixed tilts. It also
# models a single-axis tracking system for comparison. The monthly POA
# insolation is calculated for each strategy to show how orientation affects
# seasonal irradiance collection.
import pvlib
from pvlib import location
from pvlib import irradiance
from pvlib import tracking
from pvlib.iotools import read_tmy3
import pandas as pd
from matplotlib import pyplot as plt
import pathlib
# get full path to the data directory
DATA_DIR = pathlib.Path(pvlib.__file__).parent / 'data'
# get TMY3 dataset
tmy, metadata = read_tmy3(DATA_DIR / '723170TYA.CSV', coerce_year=1990,
map_variables=True)
# TMY3 datasets are right-labeled (AKA "end of interval") which means the last
# interval of Dec 31, 23:00 to Jan 1 00:00 is labeled Jan 1 00:00. When rolling
# up hourly irradiance to monthly insolation, a spurious January value is
# calculated from that last row, so we'll just go ahead and drop it here:
tmy = tmy.iloc[:-1, :]
# create location object to store lat, lon, timezone
location = location.Location.from_tmy(metadata)
# calculate the necessary variables to do transposition. Note that solar
# position doesn't depend on array orientation, so we just calculate it once.
# Note also that TMY datasets are right-labeled hourly intervals, e.g. the
# 10AM to 11AM interval is labeled 11. We should calculate solar position in
# the middle of the interval (10:30), so we subtract 30 minutes:
times = tmy.index - pd.Timedelta('30min')
solar_position = location.get_solarposition(times)
# but remember to shift the index back to line up with the TMY data:
solar_position.index += pd.Timedelta('30min')
# create a helper function to do the transposition for us
def calculate_poa(tmy, solar_position, surface_tilt, surface_azimuth):
# Use the get_total_irradiance function to transpose the irradiance
# components to POA irradiance
poa = irradiance.get_total_irradiance(
surface_tilt=surface_tilt,
surface_azimuth=surface_azimuth,
dni=tmy['dni'],
ghi=tmy['ghi'],
dhi=tmy['dhi'],
solar_zenith=solar_position['apparent_zenith'],
solar_azimuth=solar_position['azimuth'],
model='isotropic')
return poa['poa_global'] # just return the total in-plane irradiance
# create a dataframe to keep track of our monthly insolations
df_monthly = pd.DataFrame()
# fixed-tilt:
for tilt in range(0, 50, 10):
# we will hardcode azimuth=180 (south) for all fixed-tilt cases
poa_irradiance = calculate_poa(tmy, solar_position, tilt, 180)
column_name = f"FT-{tilt}"
# TMYs are hourly, so we can just sum up irradiance [W/m^2] to get
# insolation [Wh/m^2]:
df_monthly[column_name] = poa_irradiance.resample('m').sum()
# single-axis tracking:
orientation = tracking.singleaxis(solar_position['apparent_zenith'],
solar_position['azimuth'],
axis_slope=0, # flat array
axis_azimuth=180, # south-facing azimuth
max_angle=60, # a common maximum rotation
backtrack=True, # backtrack for a c-Si array
gcr=0.4) # a common ground coverage ratio
poa_irradiance = calculate_poa(tmy,
solar_position,
orientation['surface_tilt'],
orientation['surface_azimuth'])
df_monthly['SAT-0.4'] = poa_irradiance.resample('m').sum()
# calculate the percent difference from GHI
ghi_monthly = tmy['ghi'].resample('m').sum()
df_monthly = 100 * (df_monthly.divide(ghi_monthly, axis=0) - 1)
df_monthly.plot()
plt.xlabel('Month of Year')
plt.ylabel('Monthly Transposition Gain [%]')
plt.tight_layout()
plt.show()
# %%
# Note that in summer, steeper tilts actually collect less insolation than
# flatter tilts because the sun is so high in the sky at solar noon. However,
# the steeper tilts significantly increase insolation capture in winter when
# the sun is lower in the sky. In contrast to the highly seasonal gain shown
# by fixed tilts, the tracker system shows a much more consistent gain
# year-round.
#
# Because the seasonality of the fixed-tilt transposition gain is driven by
# solar position angles, the relative behavior of different orientations will
# be different for different locations. For example, a common rule of thumb
# (considered somewhat outdated today) used to be to set tilt equal to the
# latitude of the system location. At higher latitudes, the sun doesn't get
# as high in the sky, so steeper tilts make more sense.