-
Notifications
You must be signed in to change notification settings - Fork 1.1k
add spectrum.average_photon_energy
gallery example
#2206
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from 14 commits
Commits
Show all changes
23 commits
Select commit
Hold shift + click to select a range
db1e875
Create average_photon_energy.py
RDaxini 78a8e13
Update average_photon_energy.py
RDaxini 2c3bb4a
Update average_photon_energy.py
RDaxini 27a92b0
Update average_photon_energy.py
RDaxini 9fcf180
Update average_photon_energy.py
RDaxini 19791cf
Update average_photon_energy.py
RDaxini fdc7532
Update average_photon_energy.py
RDaxini 61ea9a9
Update average_photon_energy.py
RDaxini 5690774
Update average_photon_energy.py
RDaxini 5b20088
Update average_photon_energy.py
RDaxini 1fdd0e4
Update average_photon_energy.py
RDaxini 698eea9
Update average_photon_energy.py
RDaxini ab71926
Update average_photon_energy.py
RDaxini 737d8bb
Update average_photon_energy.py
RDaxini 9ab21f1
Apply suggestions from code review
RDaxini 22744a8
Update average_photon_energy.py
RDaxini 5d6f7e6
Apply suggestions from code review
RDaxini b2164d7
Update average_photon_energy.py
RDaxini 8bfc2cf
Update average_photon_energy.py
RDaxini a955ded
Update v0.11.1.rst
RDaxini 7687ddb
Update docs/sphinx/source/whatsnew/v0.11.1.rst
RDaxini 5cfc22d
Update average_photon_energy.py
RDaxini 948d99a
Merge branch 'main' into ape_example
kandersolar File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,198 @@ | ||
""" | ||
Average Photon Energy Calculation | ||
============================ | ||
|
||
Calculation of the Average Photon Energy from SPECTRL2 output. | ||
""" | ||
|
||
# %% | ||
# Introduction | ||
# ------------ | ||
# This example demonstrates how to use the | ||
# :py:func:`~pvlib.spectrum.average_photon_energy` function to calculate the | ||
# Average Photon Energy (APE, :math:`\overline{E_\gamma}`) of spectral | ||
# irradiance distributions simulated using :py:func:`~pvlib.spectrum.spectrl2`. | ||
# More information on the SPECTRL2 model can be found in [1]_. | ||
# The APE parameter is a useful indicator of the overall shape of the solar | ||
# spectrum [2]_. Higher (lower) APE values indicate a blue (red) shift in the | ||
# spectrum and is one of a variety of such characterisation methods that is | ||
# used in the PV performance literature [3]_. | ||
# | ||
# To demonstrate this functionality, first we need to simulate some spectra | ||
RDaxini marked this conversation as resolved.
Show resolved
Hide resolved
|
||
# using :py:func:`~pvlib.spectrum.spectrl2`. In this example, we will simulate | ||
# spectra following a similar method to that which is followed in the | ||
# `Modelling Spectral Irradiance | ||
# <https://pvlib-python.readthedocs.io/en/stable/gallery/spectrum/plot_spectrl2_fig51A.html>`_ | ||
RDaxini marked this conversation as resolved.
Show resolved
Hide resolved
|
||
# example, which reproduces a figure from [4]_. The first step is to | ||
# import the required packages and define some basic system parameters and | ||
RDaxini marked this conversation as resolved.
Show resolved
Hide resolved
|
||
# and meteorological conditions. | ||
|
||
# %% | ||
import numpy as np | ||
import pandas as pd | ||
import matplotlib.pyplot as plt | ||
from scipy.integrate import trapezoid | ||
from pvlib import spectrum, solarposition, irradiance, atmosphere | ||
|
||
lat, lon = 39.742, -105.18 # NREL SRRL location | ||
tilt = 25 | ||
azimuth = 180 # south-facing system | ||
pressure = 81190 # at 1828 metres AMSL, roughly | ||
water_vapor_content = 0.5 # cm | ||
tau500 = 0.1 | ||
ozone = 0.31 # atm-cm | ||
albedo = 0.2 | ||
|
||
times = pd.date_range('2023-01-01 08:00', freq='h', periods=9, | ||
tz='America/Denver') | ||
solpos = solarposition.get_solarposition(times, lat, lon) | ||
aoi = irradiance.aoi(tilt, azimuth, solpos.apparent_zenith, solpos.azimuth) | ||
|
||
relative_airmass = atmosphere.get_relative_airmass(solpos.apparent_zenith, | ||
model='kastenyoung1989') | ||
|
||
# %% | ||
# Spectral simulation | ||
# ------------------------- | ||
# With all the necessary inputs now defined, we can model spectral irradiance | ||
# using :py:func:`pvlib.spectrum.spectrl2`. As we are calculating spectra for | ||
# more than one set of conditions, the function will return a dictionary | ||
# containing 2-D arrays for the spectral irradiance components and a 1-D array | ||
# of shape (122,) for wavelength. For each of the 2-D arrays, one dimension is | ||
# for wavelength in nm and one is for irradiance in Wm⁻²nm⁻¹. | ||
|
||
spectra_components = spectrum.spectrl2( | ||
apparent_zenith=solpos.apparent_zenith, | ||
aoi=aoi, | ||
surface_tilt=tilt, | ||
ground_albedo=albedo, | ||
surface_pressure=pressure, | ||
relative_airmass=relative_airmass, | ||
precipitable_water=water_vapor_content, | ||
ozone=ozone, | ||
aerosol_turbidity_500nm=tau500, | ||
) | ||
|
||
# %% | ||
# Visualising the spectral data | ||
# ----------------------------- | ||
# Let's take a look at the spectral irradiance data simulated on the hour for | ||
RDaxini marked this conversation as resolved.
Show resolved
Hide resolved
|
||
# eight hours on the first day of 2023. | ||
|
||
plt.figure() | ||
plt.plot(spectra_components['wavelength'], spectra_components['poa_global']) | ||
plt.xlim(200, 2700) | ||
plt.ylim(0, 1.8) | ||
plt.ylabel(r"Spectral irradiance (Wm⁻²nm⁻¹)") | ||
plt.xlabel(r"Wavelength (nm)") | ||
time_labels = times.strftime("%H:%M") | ||
labels = [ | ||
"{}, AM {:0.02f}".format(*vals) | ||
RDaxini marked this conversation as resolved.
Show resolved
Hide resolved
|
||
for vals in zip(time_labels, relative_airmass) | ||
] | ||
plt.legend(labels) | ||
plt.show() | ||
|
||
# %% | ||
# Given the changing broadband irradiance throughout the day, it is not obvious | ||
# from inspection how the relative distribution of light changes as a function | ||
# of wavelength. We can normalise the spectral irradiance curves to visualise | ||
# this shift in the shape of the spectrum over the course of the day. In | ||
# this example, we normalise by dividing each spectral irradiance value by the | ||
# total broadband irradiance, which we calculate by integrating the entire | ||
# spectral irradiance distribution with respect to wavelength. | ||
|
||
poa_global = spectra_components['poa_global'] | ||
RDaxini marked this conversation as resolved.
Show resolved
Hide resolved
|
||
wavelength = spectra_components['wavelength'] | ||
|
||
broadband_irradiance = np.array([trapezoid(poa_global[:, i], wavelength) | ||
for i in range(poa_global.shape[1])]) | ||
RDaxini marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
poa_global_normalised = poa_global / broadband_irradiance | ||
|
||
# Plot the normalised spectra | ||
plt.figure() | ||
plt.plot(wavelength, poa_global_normalised) | ||
plt.xlim(200, 2700) | ||
plt.ylim(0, 0.0018) | ||
plt.ylabel(r"Normalised Irradiance (nm⁻¹)") | ||
plt.xlabel(r"Wavelength (nm)") | ||
time_labels = times.strftime("%H:%M") | ||
labels = [ | ||
"{}, AM {:0.02f}".format(*vals) | ||
RDaxini marked this conversation as resolved.
Show resolved
Hide resolved
|
||
for vals in zip(time_labels, relative_airmass) | ||
] | ||
plt.legend(labels) | ||
plt.show() | ||
|
||
# %% | ||
# We can now see from the normalised irradiance curves that at the start and | ||
# end of the day, the spectrum is red shifted, meaning there is a greater | ||
# proportion of longer wavelength radiation. Meanwhile, during the middle of | ||
# the day, there is a greater prevalence of shorter wavelength radiation — a | ||
# blue shifted spectrum. | ||
# | ||
# How can we quantify this shift? This is where the average photon energy comes | ||
# into play. | ||
|
||
# %% | ||
# Calculating the average photon energy | ||
# ------------------------------------- | ||
# To calculate the APE, first we must convert our output spectra from from the | ||
RDaxini marked this conversation as resolved.
Show resolved
Hide resolved
|
||
# simulation into a compatible input for | ||
# :py:func:`pvlib.spectrum.average_photon_energy`. Since we have more than one | ||
# spectral irradiance distribution, a :py:class:`pandas.DataFrame` is | ||
# appropriate. We also need to set the column headers as wavelength, so each | ||
# row is a single spectral irradiance distribution. It is important to remember | ||
# here that the resulting APE values depend on the integration limits, i.e. | ||
# the wavelength range of the spectral irradiance input. APE values are only | ||
# comparable if calculated between the same integration limits. In this case, | ||
# our APE values are calculated between 300nm and 4000nm. | ||
|
||
spectra = pd.DataFrame(poa_global).T # convert to dataframe and transpose | ||
spectra.index = time_labels # add time index | ||
spectra.columns = wavelength # add wavelength column headers | ||
|
||
ape = spectrum.average_photon_energy(spectra) | ||
|
||
# %% | ||
# We can update the normalised spectral irradiance plot to include the APE | ||
# value of each spectral irradiance distribution in the legend. Note that the | ||
# units of the APE are electronvolts (eV). | ||
|
||
plt.figure() | ||
plt.plot(wavelength, poa_global_normalised) | ||
plt.xlim(200, 2700) | ||
plt.ylim(0, 0.0018) | ||
plt.ylabel(r"Normalised Irradiance (nm⁻¹)") | ||
plt.xlabel(r"Wavelength (nm)") | ||
time_labels = times.strftime("%H:%M") | ||
RDaxini marked this conversation as resolved.
Show resolved
Hide resolved
|
||
labels = [ | ||
"{}, APE {:0.02f}".format(*vals) | ||
RDaxini marked this conversation as resolved.
Show resolved
Hide resolved
|
||
for vals in zip(time_labels, ape) | ||
] | ||
plt.legend(labels) | ||
plt.show() | ||
|
||
# %% | ||
# As expected, the morning and evening spectra have a lower APE while a higher | ||
# APE is observed closer to the middle of the day. For reference, AM1.5 between | ||
# 300 and 4000 nm is 1.4501 eV. This indicates that the simulated spectra are | ||
# slightly red shifted with respect to the AM1.5 standard reference spectrum. | ||
|
||
# %% | ||
# References | ||
# ---------- | ||
# .. [1] Bird, R, and Riordan, C., 1984, "Simple solar spectral model for | ||
# direct and diffuse irradiance on horizontal and tilted planes at the | ||
# earth's surface for cloudless atmospheres", NREL Technical Report | ||
# TR-215-2436 :doi:`10.2172/5986936` | ||
# .. [2] Jardine, C., et al., 2002, January. Influence of spectral effects on | ||
# the performance of multijunction amorphous silicon cells. In Proc. | ||
# Photovoltaic in Europe Conference (pp. 1756-1759) | ||
# .. [3] Daxini, R., and Wu, Y., 2023. "Review of methods to account | ||
# for the solar spectral influence on photovoltaic device performance." | ||
# Energy 286 :doi:`10.1016/j.energy.2023.129461` | ||
# .. [4] Bird Simple Spectral Model: spectrl2_2.c | ||
# https://www.nrel.gov/grid/solar-resource/spectral.html | ||
# (Last accessed: 18/09/2024) |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.