Skip to content

Commit b6c795d

Browse files
RDaxinikandersolarIoannisSifnaiosechedey-lsAdamRJensen
authored
Add spectral factor gallery example (#2114)
* Create spectral_factor.py * Update spectral_factor.py fix directory, add refs * Update spectral_factor.py * Update spectral_factor.py * Update spectral_factor.py * Update spectral_factor.py * Update spectral_factor.py * Update docs/examples/spectrum/spectral_factor.py Co-authored-by: Kevin Anderson <[email protected]> * Update docs/examples/spectrum/spectral_factor.py Co-authored-by: Kevin Anderson <[email protected]> * Update docs/examples/spectrum/spectral_factor.py Co-authored-by: Kevin Anderson <[email protected]> * Update docs/examples/spectrum/spectral_factor.py Co-authored-by: Kevin Anderson <[email protected]> * Update spectral_factor.py * Update docs/examples/spectrum/spectral_factor.py Co-authored-by: Kevin Anderson <[email protected]> * Update docs/examples/spectrum/spectral_factor.py Co-authored-by: Kevin Anderson <[email protected]> * Update spectral_factor.py * Update spectral_factor.py * Update spectral_factor.py * Update docs/examples/spectrum/spectral_factor.py Co-authored-by: Ioannis Sifnaios <[email protected]> * Update docs/examples/spectrum/spectral_factor.py Co-authored-by: Ioannis Sifnaios <[email protected]> * Update spectral_factor.py * Update spectral_factor.py * Update spectral_factor.py * Update spectral_factor.py * Update spectral_factor.py * Update v0.11.1.rst * Update spectral_factor.py * Update spectral_factor.py trying new plots (goal to increase size) * Update spectral_factor.py * Apply suggestions from code review Co-authored-by: Echedey Luis <[email protected]> Co-authored-by: Adam R. Jensen <[email protected]> * Update spectral_factor.py * Update docs/examples/spectrum/spectral_factor.py Co-authored-by: Adam R. Jensen <[email protected]> * expand ama/amr initialism * Update spectral_factor.py * Update spectral_factor.py * Update spectral_factor.py * Update docs/examples/spectrum/spectral_factor.py Co-authored-by: Kevin Anderson <[email protected]> * Update spectral_factor.py --------- Co-authored-by: Kevin Anderson <[email protected]> Co-authored-by: Ioannis Sifnaios <[email protected]> Co-authored-by: Echedey Luis <[email protected]> Co-authored-by: Adam R. Jensen <[email protected]>
1 parent 6f5afa9 commit b6c795d

File tree

2 files changed

+155
-0
lines changed

2 files changed

+155
-0
lines changed
Lines changed: 150 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,150 @@
1+
"""
2+
Spectral Mismatch Estimation
3+
============================
4+
5+
Comparison of methods to estimate the spectral mismatch factor
6+
from atmospheric variable inputs.
7+
"""
8+
9+
# %%
10+
# Introduction
11+
# ------------
12+
# This example demonstrates how to use different ``spectrum.spectral_factor_*``
13+
# models in pvlib-python to calculate the spectral mismatch factor, :math:`M`.
14+
# While :math:`M` for a photovoltaic (PV) module can be calculated exactly
15+
# using spectral irradiance and module spectral response data, these data are
16+
# often not available. pvlib-python provides several functions to estimate the
17+
# spectral mismatch factor, :math:`M`, using proxies of the prevailing spectral
18+
# irradiance conditions, such as air mass and clearsky index, which are easily
19+
# derived from common ground-based measurements such as broadband irradiance.
20+
# More information on a range of spectral factor models, as well as the
21+
# variables upon which they are based, can be found in [1]_.
22+
#
23+
# To demonstrate this functionality, first we need to import some data.
24+
# This example uses a Typical Meteorological Year 3
25+
# (TMY3) file for the location of Greensboro, North Carolina, from the
26+
# pvlib-python data directory. This TMY3 file is constructed using the median
27+
# month from each year between 1980 and 2003, from which we extract the first
28+
# week of August 2001 to analyse.
29+
30+
# %%
31+
import pathlib
32+
from matplotlib import pyplot as plt
33+
import pandas as pd
34+
import pvlib
35+
from pvlib import location
36+
37+
DATA_DIR = pathlib.Path(pvlib.__file__).parent / 'data'
38+
meteo, metadata = pvlib.iotools.read_tmy3(DATA_DIR / '723170TYA.CSV',
39+
coerce_year=2001, map_variables=True)
40+
meteo = meteo.loc['2001-08-01':'2001-08-07']
41+
42+
# %%
43+
# Spectral Factor Functions
44+
# -------------------------
45+
# This example demonstrates the application of three pvlib-python
46+
# spectral factor functions:
47+
#
48+
# - :py:func:`~pvlib.spectrum.spectral_factor_sapm`, which requires only
49+
# the absolute airmass, :math:`AM_a`
50+
# - :py:func:`~pvlib.spectrum.spectral_factor_pvspec`, which requires
51+
# :math:`AM_a` and the clearsky index, :math:`k_c`
52+
# - :py:func:`~pvlib.spectrum.spectral_factor_firstsolar`, which requires
53+
# :math:`AM_a` and the atmospheric precipitable water content, :math:`W`
54+
55+
# %%
56+
# Calculation of inputs
57+
# ---------------------
58+
# Let's calculate the absolute air mass, which is required for all three
59+
# models. We use the Kasten and Young [2]_ model, which requires the apparent
60+
# sun zenith. Note: TMY3 files timestamps indicate the end of the hour, so we
61+
# shift the indices back 30-minutes to calculate solar position at the centre
62+
# of the interval.
63+
64+
# Create a location object
65+
lat, lon = metadata['latitude'], metadata['longitude']
66+
alt = altitude = metadata['altitude']
67+
tz = 'Etc/GMT+5'
68+
loc = location.Location(lat, lon, tz=tz, name='Greensboro, NC')
69+
70+
# Calculate solar position parameters
71+
solpos = loc.get_solarposition(
72+
meteo.index.shift(freq="-30min"),
73+
pressure=meteo.pressure*100, # convert from millibar to Pa
74+
temperature=meteo.temp_air)
75+
solpos.index = meteo.index # reset index to end of the hour
76+
77+
airmass_relative = pvlib.atmosphere.get_relative_airmass(
78+
solpos.apparent_zenith).dropna()
79+
airmass_absolute = pvlib.atmosphere.get_absolute_airmass(airmass_relative,
80+
meteo.pressure*100)
81+
# %%
82+
# Now we calculate the clearsky index, :math:`k_c`, which is the ratio of GHI
83+
# to clearsky GHI.
84+
85+
cs = loc.get_clearsky(meteo.index.shift(freq="-30min"))
86+
cs.index = meteo.index # reset index to end of the hour
87+
kc = pvlib.irradiance.clearsky_index(meteo.ghi, cs.ghi)
88+
# %%
89+
# :math:`W` is provided in the TMY3 file but in other cases can be calculated
90+
# from temperature and relative humidity
91+
# (see :py:func:`pvlib.atmosphere.gueymard94_pw`).
92+
93+
w = meteo.precipitable_water
94+
95+
# %%
96+
# Calculation of Spectral Mismatch
97+
# --------------------------------
98+
# Let's calculate the spectral mismatch factor using the three spectral factor
99+
# functions. First, we need to import some model coefficients for the SAPM
100+
# spectral factor function, which, unlike the other two functions, lacks
101+
# built-in coefficients.
102+
103+
# Import some for a mc-Si module from the SAPM module database.
104+
module = pvlib.pvsystem.retrieve_sam('SandiaMod')['LG_LG290N1C_G3__2013_']
105+
#
106+
# Calculate M using the three models for an mc-Si PV module.
107+
m_sapm = pvlib.spectrum.spectral_factor_sapm(airmass_absolute, module)
108+
m_pvspec = pvlib.spectrum.spectral_factor_pvspec(airmass_absolute, kc,
109+
'multisi')
110+
m_fs = pvlib.spectrum.spectral_factor_firstsolar(w, airmass_absolute,
111+
'multisi')
112+
113+
df_results = pd.concat([m_sapm, m_pvspec, m_fs], axis=1)
114+
df_results.columns = ['SAPM', 'PVSPEC', 'FS']
115+
# %%
116+
# Comparison Plots
117+
# ----------------
118+
# We can plot the results to visualise variability between the models. Note
119+
# that this is not an exact comparison since the exact same PV modules has
120+
# not been modelled in each case, only the same module technology.
121+
122+
# Plot M
123+
fig1, (ax1, ax2) = plt.subplots(2, 1)
124+
df_results.plot(ax=ax1, legend=False)
125+
ax1.set_xlabel('Day')
126+
ax1.set_ylabel('Spectral mismatch (-)')
127+
ax1.set_ylim(0.85, 1.15)
128+
ax1.legend(loc='upper center', frameon=False, ncols=3,
129+
bbox_to_anchor=(0.5, 1.3))
130+
131+
# We can also zoom in one one day, for example August 2nd.
132+
df_results.loc['2001-08-02'].plot(ax=ax2, legend=False)
133+
ax2.set_xlabel('Time')
134+
ax2.set_ylabel('Spectral mismatch (-)')
135+
ax2.set_ylim(0.85, 1.15)
136+
137+
plt.tight_layout()
138+
139+
plt.show()
140+
141+
# %%
142+
# References
143+
# ----------
144+
# .. [1] Daxini, R., and Wu, Y., 2023. "Review of methods to account
145+
# for the solar spectral influence on photovoltaic device performance."
146+
# Energy 286
147+
# :doi:`10.1016/j.energy.2023.129461`
148+
# .. [2] Kasten, F. and Young, A.T., 1989. Revised optical air mass tables
149+
# and approximation formula. Applied Optics, 28(22), pp.4735-4738.
150+
# :doi:`10.1364/AO.28.004735`

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

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,10 @@ Testing
2525

2626
Documentation
2727
~~~~~~~~~~~~~
28+
* Added gallery example demonstrating the application of
29+
several spectral mismatch factor models.
30+
(:issue:`2107`, :pull:`2114`)
31+
2832
* Added gallery example on calculating cell temperature for
2933
floating PV. (:pull:`2110`)
3034

@@ -37,4 +41,5 @@ Contributors
3741
* Ioannis Sifnaios (:ghuser:`IoannisSifnaios`)
3842
* Leonardo Micheli (:ghuser:`lmicheli`)
3943
* Echedey Luis (:ghuser:`echedey-ls`)
44+
* Rajiv Daxini (:ghuser:`RDaxini`)
4045

0 commit comments

Comments
 (0)