Skip to content

Commit cc700f9

Browse files
RDaxiniIoannisSifnaioskandersolarechedey-ls
authored
add spectrum.average_photon_energy gallery example (#2206)
* Create average_photon_energy.py * Update average_photon_energy.py * Update average_photon_energy.py * Update average_photon_energy.py continuing creation * Update average_photon_energy.py * Update average_photon_energy.py * Update average_photon_energy.py * Update average_photon_energy.py * Update average_photon_energy.py add interpretation of APE values underneath table * Update average_photon_energy.py * Update average_photon_energy.py add ape table * Update average_photon_energy.py add last accessed to references * Update average_photon_energy.py wording, remove table * Update average_photon_energy.py reference order * Apply suggestions from code review Co-authored-by: Ioannis Sifnaios <[email protected]> * Update average_photon_energy.py * Apply suggestions from code review Co-authored-by: Kevin Anderson <[email protected]> * Update average_photon_energy.py add = variable names remove unused package * Update average_photon_energy.py gallery example ref * Update v0.11.1.rst * Update docs/sphinx/source/whatsnew/v0.11.1.rst Co-authored-by: Kevin Anderson <[email protected]> * Update average_photon_energy.py update legend Co-Authored-By: Kevin Anderson <[email protected]> Co-Authored-By: Echedey Luis <[email protected]> --------- Co-authored-by: Ioannis Sifnaios <[email protected]> Co-authored-by: Kevin Anderson <[email protected]> Co-authored-by: Kevin Anderson <[email protected]> Co-authored-by: Echedey Luis <[email protected]>
1 parent ad89390 commit cc700f9

File tree

2 files changed

+199
-0
lines changed

2 files changed

+199
-0
lines changed
Lines changed: 197 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,197 @@
1+
"""
2+
Average Photon Energy Calculation
3+
=================================
4+
5+
Calculation of the Average Photon Energy from SPECTRL2 output.
6+
"""
7+
8+
# %%
9+
# Introduction
10+
# ------------
11+
# This example demonstrates how to use the
12+
# :py:func:`~pvlib.spectrum.average_photon_energy` function to calculate the
13+
# Average Photon Energy (APE, :math:`\overline{E_\gamma}`) of spectral
14+
# irradiance distributions. This example uses spectral irradiance simulated
15+
# using :py:func:`~pvlib.spectrum.spectrl2`, but the same method is
16+
# applicable to spectral irradiance from any source.
17+
# More information on the SPECTRL2 model can be found in [1]_.
18+
# The APE parameter is a useful indicator of the overall shape of the solar
19+
# spectrum [2]_. Higher (lower) APE values indicate a blue (red) shift in the
20+
# spectrum and is one of a variety of such characterisation methods that is
21+
# used in the PV performance literature [3]_.
22+
#
23+
# To demonstrate this functionality, first we will simulate some spectra
24+
# using :py:func:`~pvlib.spectrum.spectrl2`. In this example, we will simulate
25+
# spectra following a similar method to that which is followed in the
26+
# :ref:`sphx_glr_gallery_spectrum_plot_spectrl2_fig51A.py` example, which
27+
# reproduces a figure from [4]_. The first step is to import the required
28+
# packages and define some basic system parameters and meteorological
29+
# conditions.
30+
31+
# %%
32+
import pandas as pd
33+
import matplotlib.pyplot as plt
34+
from scipy.integrate import trapezoid
35+
from pvlib import spectrum, solarposition, irradiance, atmosphere
36+
37+
lat, lon = 39.742, -105.18 # NREL SRRL location
38+
tilt = 25
39+
azimuth = 180 # south-facing system
40+
pressure = 81190 # at 1828 metres AMSL, roughly
41+
water_vapor_content = 0.5 # cm
42+
tau500 = 0.1
43+
ozone = 0.31 # atm-cm
44+
albedo = 0.2
45+
46+
times = pd.date_range('2023-01-01 08:00', freq='h', periods=9,
47+
tz='America/Denver')
48+
solpos = solarposition.get_solarposition(times, lat, lon)
49+
aoi = irradiance.aoi(tilt, azimuth, solpos.apparent_zenith, solpos.azimuth)
50+
51+
relative_airmass = atmosphere.get_relative_airmass(solpos.apparent_zenith,
52+
model='kastenyoung1989')
53+
54+
# %%
55+
# Spectral simulation
56+
# -------------------------
57+
# With all the necessary inputs now defined, we can model spectral irradiance
58+
# using :py:func:`pvlib.spectrum.spectrl2`. As we are calculating spectra for
59+
# more than one set of conditions, the function will return a dictionary
60+
# containing 2-D arrays for the spectral irradiance components and a 1-D array
61+
# of shape (122,) for wavelength. For each of the 2-D arrays, one dimension is
62+
# for wavelength in nm and one is for irradiance in Wm⁻²nm⁻¹.
63+
64+
spectra_components = spectrum.spectrl2(
65+
apparent_zenith=solpos.apparent_zenith,
66+
aoi=aoi,
67+
surface_tilt=tilt,
68+
ground_albedo=albedo,
69+
surface_pressure=pressure,
70+
relative_airmass=relative_airmass,
71+
precipitable_water=water_vapor_content,
72+
ozone=ozone,
73+
aerosol_turbidity_500nm=tau500,
74+
)
75+
76+
# %%
77+
# Visualising the spectral data
78+
# -----------------------------
79+
# Let's take a look at the spectral irradiance data simulated hourly for eight
80+
# hours on the first day of 2023.
81+
82+
plt.figure()
83+
plt.plot(spectra_components['wavelength'], spectra_components['poa_global'])
84+
plt.xlim(200, 2700)
85+
plt.ylim(0, 1.8)
86+
plt.ylabel(r"Spectral irradiance (Wm⁻²nm⁻¹)")
87+
plt.xlabel(r"Wavelength (nm)")
88+
time_labels = times.strftime("%H%M")
89+
labels = [
90+
f"{t}, {am_:0.02f}"
91+
for t, am_ in zip(time_labels, relative_airmass)
92+
]
93+
plt.legend(labels, title="Time, AM")
94+
plt.show()
95+
96+
# %%
97+
# Given the changing broadband irradiance throughout the day, it is not obvious
98+
# from inspection how the relative distribution of light changes as a function
99+
# of wavelength. We can normalise the spectral irradiance curves to visualise
100+
# this shift in the shape of the spectrum over the course of the day. In
101+
# this example, we normalise by dividing each spectral irradiance value by the
102+
# total broadband irradiance, which we calculate by integrating the entire
103+
# spectral irradiance distribution with respect to wavelength.
104+
105+
spectral_poa = spectra_components['poa_global']
106+
wavelength = spectra_components['wavelength']
107+
108+
broadband_irradiance = trapezoid(spectral_poa, wavelength, axis=0)
109+
110+
spectral_poa_normalised = spectral_poa / broadband_irradiance
111+
112+
# Plot the normalised spectra
113+
plt.figure()
114+
plt.plot(wavelength, spectral_poa_normalised)
115+
plt.xlim(200, 2700)
116+
plt.ylim(0, 0.0018)
117+
plt.ylabel(r"Normalised Irradiance (nm⁻¹)")
118+
plt.xlabel(r"Wavelength (nm)")
119+
time_labels = times.strftime("%H%M")
120+
labels = [
121+
f"{t}, {am_:0.02f}"
122+
for t, am_ in zip(time_labels, relative_airmass)
123+
]
124+
plt.legend(labels, title="Time, AM")
125+
plt.show()
126+
127+
# %%
128+
# We can now see from the normalised irradiance curves that at the start and
129+
# end of the day, the spectrum is red shifted, meaning there is a greater
130+
# proportion of longer wavelength radiation. Meanwhile, during the middle of
131+
# the day, there is a greater prevalence of shorter wavelength radiation — a
132+
# blue shifted spectrum.
133+
#
134+
# How can we quantify this shift? This is where the average photon energy comes
135+
# into play.
136+
137+
# %%
138+
# Calculating the average photon energy
139+
# -------------------------------------
140+
# To calculate the APE, first we must convert our output spectra from the
141+
# simulation into a compatible input for
142+
# :py:func:`pvlib.spectrum.average_photon_energy`. Since we have more than one
143+
# spectral irradiance distribution, a :py:class:`pandas.DataFrame` is
144+
# appropriate. We also need to set the column headers as wavelength, so each
145+
# row is a single spectral irradiance distribution. It is important to remember
146+
# here that the resulting APE values depend on the integration limits, i.e.
147+
# the wavelength range of the spectral irradiance input. APE values are only
148+
# comparable if calculated between the same integration limits. In this case,
149+
# our APE values are calculated between 300nm and 4000nm.
150+
151+
spectra = pd.DataFrame(spectral_poa).T # convert to dataframe and transpose
152+
spectra.index = time_labels # add time index
153+
spectra.columns = wavelength # add wavelength column headers
154+
155+
ape = spectrum.average_photon_energy(spectra)
156+
157+
# %%
158+
# We can update the normalised spectral irradiance plot to include the APE
159+
# value of each spectral irradiance distribution in the legend. Note that the
160+
# units of the APE are electronvolts (eV).
161+
162+
plt.figure()
163+
plt.plot(wavelength, spectral_poa_normalised)
164+
plt.xlim(200, 2700)
165+
plt.ylim(0, 0.0018)
166+
plt.ylabel(r"Normalised Irradiance (nm⁻¹)")
167+
plt.xlabel(r"Wavelength (nm)")
168+
time_labels = times.strftime("%H%M")
169+
labels = [
170+
f"{t}, {ape_:0.02f}"
171+
for t, ape_ in zip(time_labels, ape)
172+
]
173+
plt.legend(labels, title="Time, APE (eV)")
174+
plt.show()
175+
176+
# %%
177+
# As expected, the morning and evening spectra have a lower APE while a higher
178+
# APE is observed closer to the middle of the day. For reference, AM1.5 between
179+
# 300 and 4000 nm is 1.4501 eV. This indicates that the simulated spectra are
180+
# slightly red shifted with respect to the AM1.5 standard reference spectrum.
181+
182+
# %%
183+
# References
184+
# ----------
185+
# .. [1] Bird, R, and Riordan, C., 1984, "Simple solar spectral model for
186+
# direct and diffuse irradiance on horizontal and tilted planes at the
187+
# earth's surface for cloudless atmospheres", NREL Technical Report
188+
# TR-215-2436 :doi:`10.2172/5986936`
189+
# .. [2] Jardine, C., et al., 2002, January. Influence of spectral effects on
190+
# the performance of multijunction amorphous silicon cells. In Proc.
191+
# Photovoltaic in Europe Conference (pp. 1756-1759)
192+
# .. [3] Daxini, R., and Wu, Y., 2023. "Review of methods to account
193+
# for the solar spectral influence on photovoltaic device performance."
194+
# Energy 286 :doi:`10.1016/j.energy.2023.129461`
195+
# .. [4] Bird Simple Spectral Model: spectrl2_2.c
196+
# https://www.nrel.gov/grid/solar-resource/spectral.html
197+
# (Last accessed: 18/09/2024)

docs/sphinx/source/whatsnew/v0.11.1.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,8 @@ Documentation
6262
* Added gallery example demonstrating the application of
6363
several spectral mismatch factor models.
6464
(:issue:`2107`, :pull:`2114`)
65+
* Added gallery example demonstrating the application of
66+
:py:func:`~pvlib.spectrum.average_photon_energy`. (:issue:`2194`, :pull:`2206`)
6567
* Added gallery example on calculating cell temperature for
6668
floating PV. (:pull:`2110`)
6769
* Added gallery example demonstrating how to use

0 commit comments

Comments
 (0)