|
9 | 9 | import pandas as pd |
10 | 10 | from pathlib import Path |
11 | 11 | from functools import partial |
| 12 | +from scipy import constants |
| 13 | +from scipy.integrate import trapezoid |
12 | 14 |
|
13 | 15 |
|
14 | 16 | @deprecated( |
@@ -176,3 +178,95 @@ def get_reference_spectra(wavelengths=None, standard="ASTM G173-03"): |
176 | 178 | ) |
177 | 179 |
|
178 | 180 | return standard |
| 181 | + |
| 182 | + |
| 183 | +def average_photon_energy(spectra): |
| 184 | + r""" |
| 185 | + Calculate the average photon energy of one or more spectral irradiance |
| 186 | + distributions. |
| 187 | +
|
| 188 | + Parameters |
| 189 | + ---------- |
| 190 | + spectra : pandas.Series or pandas.DataFrame |
| 191 | +
|
| 192 | + Spectral irradiance, must be positive. [Wm⁻²nm⁻¹] |
| 193 | +
|
| 194 | + A single spectrum must be a :py:class:`pandas.Series` with wavelength |
| 195 | + [nm] as the index, while multiple spectra must be rows in a |
| 196 | + :py:class:`pandas.DataFrame` with column headers as wavelength [nm]. |
| 197 | +
|
| 198 | + Returns |
| 199 | + ------- |
| 200 | + ape : numeric or pandas.Series |
| 201 | + Average Photon Energy [eV]. |
| 202 | + Note: returns ``np.nan`` in the case of all-zero spectral irradiance |
| 203 | + input. |
| 204 | +
|
| 205 | + Notes |
| 206 | + ----- |
| 207 | + The average photon energy (APE) is an index used to characterise the solar |
| 208 | + spectrum. It has been used widely in the physics literature since the |
| 209 | + 1900s, but its application for solar spectral irradiance characterisation |
| 210 | + in the context of PV performance modelling was proposed in 2002 [1]_. The |
| 211 | + APE is calculated based on the principle that a photon's energy is |
| 212 | + inversely proportional to its wavelength: |
| 213 | +
|
| 214 | + .. math:: |
| 215 | +
|
| 216 | + E_\gamma = \frac{hc}{\lambda}, |
| 217 | +
|
| 218 | + where :math:`E_\gamma` is the energy of a photon with wavelength |
| 219 | + :math:`\lambda`, :math:`h` is the Planck constant, and :math:`c` is the |
| 220 | + speed of light. Therefore, the average energy of all photons within a |
| 221 | + single spectral irradiance distribution provides an indication of the |
| 222 | + general shape of the spectrum. A higher average photon energy |
| 223 | + (shorter wavelength) indicates a blue-shifted spectrum, while a lower |
| 224 | + average photon energy (longer wavelength) would indicate a red-shifted |
| 225 | + spectrum. This value of the average photon energy can be calculated by |
| 226 | + dividing the total energy in the spectrum by the total number of photons |
| 227 | + in the spectrum as follows [1]_: |
| 228 | +
|
| 229 | + .. math:: |
| 230 | +
|
| 231 | + \overline{E_\gamma} = \frac{1}{q} \cdot \frac{\int G(\lambda) \, |
| 232 | + d\lambda} |
| 233 | + {\int \Phi(\lambda) \, d\lambda}. |
| 234 | +
|
| 235 | + :math:`\Phi(\lambda)` is the photon flux density as a function of |
| 236 | + wavelength, :math:`G(\lambda)` is the spectral irradiance, :math:`q` is the |
| 237 | + elementary charge used here so that the average photon energy, |
| 238 | + :math:`\overline{E_\gamma}`, is expressed in electronvolts (eV). The |
| 239 | + integrals are computed over the full wavelength range of the ``spectra`` |
| 240 | + parameter. |
| 241 | +
|
| 242 | + References |
| 243 | + ---------- |
| 244 | + .. [1] Jardine, C., et al., 2002, January. Influence of spectral effects on |
| 245 | + the performance of multijunction amorphous silicon cells. In Proc. |
| 246 | + Photovoltaic in Europe Conference (pp. 1756-1759). |
| 247 | + """ |
| 248 | + |
| 249 | + if not isinstance(spectra, (pd.Series, pd.DataFrame)): |
| 250 | + raise TypeError('`spectra` must be either a' |
| 251 | + ' pandas Series or DataFrame') |
| 252 | + |
| 253 | + if (spectra < 0).any().any(): |
| 254 | + raise ValueError('Spectral irradiance data must be positive') |
| 255 | + |
| 256 | + hclambda = pd.Series((constants.h*constants.c)/(spectra.T.index*1e-9)) |
| 257 | + hclambda.index = spectra.T.index |
| 258 | + pfd = spectra.div(hclambda) |
| 259 | + |
| 260 | + def integrate(e): |
| 261 | + return trapezoid(e, x=e.T.index, axis=-1) |
| 262 | + |
| 263 | + int_spectra = integrate(spectra) |
| 264 | + int_pfd = integrate(pfd) |
| 265 | + |
| 266 | + with np.errstate(invalid='ignore'): |
| 267 | + ape = (1/constants.elementary_charge)*int_spectra/int_pfd |
| 268 | + |
| 269 | + if isinstance(spectra, pd.DataFrame): |
| 270 | + ape = pd.Series(ape, index=spectra.index) |
| 271 | + |
| 272 | + return ape |
0 commit comments