Skip to content

[DRAFT] Add more spectral responses #2038

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

Closed
wants to merge 11 commits into from
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ Spectrum

spectrum.spectrl2
spectrum.get_example_spectral_response
spectrum.get_spectral_response_of_material
spectrum.get_am15g
spectrum.calc_spectral_mismatch_field
spectrum.spectral_factor_caballero
Expand Down
4 changes: 4 additions & 0 deletions docs/sphinx/source/whatsnew/v0.11.0.rst
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,9 @@ Enhancements
shade perpendicular to ``axis_azimuth``. The function is applicable to both
fixed-tilt and one-axis tracking systems.
(:issue:`1689`, :pull:`1725`, :pull:`1962`)
* Added more spectral responses materials ``monosi``, ``polysi`` and ``hit``
with the function :py:func:`pvlib.spectrum.get_spectral_response_of_material`
(:issue:`2037`, :pull:`2038`)


Bug fixes
Expand All @@ -44,3 +47,4 @@ Contributors
* Cliff Hansen (:ghuser:`cwhanse`)
* Mark Mikofski (:ghuser:`mikofski`)
* Siddharth Kaul (:ghuser:`k10blogger`)
* Anton Driesse (:ghuser:`adriesse`)
182 changes: 182 additions & 0 deletions pvlib/data/duramat_spectral_responses.csv
Original file line number Diff line number Diff line change
@@ -0,0 +1,182 @@
wavelength,polysi,monosi,hit
300,0.0,0.0,0.0
305,0.03430462,0.046272006,0.0077158213
310,0.067423105,0.08857482,0.01129055
315,0.099974155,0.1274098,0.0107729435
320,0.13169432,0.16370991,0.00962472
325,0.16080761,0.19627707,0.008452892
330,0.18828392,0.2276486,0.0072233677
335,0.21377945,0.2564403,0.005968213
340,0.23356247,0.275583,0.0053931475
345,0.24752903,0.28591865,0.0057656765
350,0.25888252,0.29379436,0.0068725348
355,0.2688427,0.30039543,0.008698225
360,0.2786274,0.30690002,0.0112268925
365,0.28945923,0.31449127,0.014442682
370,0.30155563,0.3235986,0.030305862
375,0.31418228,0.33355278,0.06445885
380,0.3271351,0.3438895,0.10740852
385,0.34021187,0.35413796,0.14966583
390,0.35375977,0.3646153,0.19563293
395,0.36777306,0.37546867,0.2486229
400,0.38153076,0.3859689,0.29750824
405,0.3943119,0.39539665,0.33116913
410,0.40576935,0.4032473,0.34978485
415,0.41654396,0.4107895,0.3629303
420,0.42712402,0.41936165,0.3729782
425,0.43742943,0.42833382,0.38117218
430,0.44735146,0.43665642,0.3887558
435,0.45687103,0.44399372,0.39595795
440,0.46611214,0.4508558,0.402565
445,0.47519302,0.4574683,0.4091568
450,0.48422813,0.4640612,0.41630554
455,0.4932537,0.47094616,0.4245758
460,0.5022507,0.47808728,0.43358612
465,0.5112419,0.48519462,0.44250488
470,0.52025986,0.4919804,0.4505005
475,0.5294876,0.4986169,0.45726776
480,0.5388603,0.5053831,0.46339417
485,0.54803467,0.5121318,0.46939087
490,0.55667114,0.51871926,0.47575378
495,0.564579,0.52507454,0.48273468
500,0.5720749,0.53134376,0.48999023
505,0.57951355,0.53767616,0.4972229
510,0.58703995,0.5441938,0.5043335
515,0.594532,0.550827,0.5114441
520,0.6019516,0.5574755,0.5185089
525,0.6092453,0.56404114,0.52545166
530,0.6164131,0.57059807,0.53234863
535,0.62348175,0.5771724,0.5391693
540,0.6304512,0.5836116,0.5458679
545,0.6373291,0.58974564,0.5523529
550,0.64414597,0.59557885,0.5586395
555,0.6509476,0.6012377,0.5647888
560,0.6577034,0.6067527,0.57081604
565,0.6644249,0.61214554,0.5767517
570,0.6711197,0.6174469,0.5826111
575,0.6777687,0.62268066,0.5884094
580,0.6843834,0.6278839,0.594162
585,0.69096375,0.6330719,0.5998993
590,0.6974945,0.63828385,0.60565186
595,0.7039833,0.6435438,0.6114044
600,0.7104225,0.64887565,0.617218
605,0.7168274,0.65431213,0.6230774
610,0.72317886,0.65987504,0.6290283
615,0.7294426,0.66564506,0.6351013
620,0.7356148,0.67159164,0.6412964
625,0.74173737,0.6775796,0.6474762
630,0.74785995,0.68348694,0.65353394
635,0.75401306,0.6891915,0.659317
640,0.7602844,0.69464546,0.6648102
645,0.76665115,0.69996864,0.6700897
650,0.77301025,0.70524377,0.6752472
655,0.7792702,0.71055824,0.68037415
660,0.78533554,0.7160034,0.6855469
665,0.7912674,0.72201973,0.69070435
670,0.79698944,0.72805786,0.69599915
675,0.80231476,0.73349,0.70173645
680,0.8074875,0.7387412,0.7077484
685,0.8127403,0.7439641,0.71380615
690,0.8183594,0.74932206,0.71969604
695,0.82481,0.7550441,0.72550964
700,0.8318863,0.76101464,0.73132324
705,0.83882904,0.7668435,0.7368469
710,0.84488297,0.77214485,0.74176025
715,0.84970856,0.7767029,0.745697
720,0.85404587,0.7809339,0.74920654
725,0.85871506,0.78542,0.7534332
730,0.8645134,0.7907453,0.75979614
735,0.87086487,0.796572,0.76742554
740,0.87664413,0.80210876,0.77397156
745,0.8816147,0.80708313,0.7785797
750,0.88636017,0.81192017,0.78245544
755,0.8908882,0.81686836,0.78619385
760,0.8952484,0.8221763,0.79045105
765,0.89949036,0.82890755,0.79571533
770,0.903656,0.8356476,0.8012085
775,0.9078293,0.8410209,0.80630493
780,0.9120903,0.84603447,0.81126404
785,0.9164429,0.85078865,0.81614685
790,0.9208832,0.85538375,0.82095337
795,0.9254303,0.859933,0.8257446
800,0.9300728,0.8645434,0.8305664
805,0.93481445,0.8693128,0.8354187
810,0.93967056,0.8743526,0.84036255
815,0.9450035,0.87991554,0.8453369
820,0.9507446,0.88584244,0.85032654
825,0.9562454,0.8916059,0.855423
830,0.9608612,0.89669144,0.86073303
835,0.9646683,0.901147,0.86642456
840,0.9682121,0.905413,0.872406
845,0.9715347,0.9095677,0.87838745
850,0.9746666,0.9136723,0.8840332
855,0.97792816,0.91794693,0.88916016
860,0.9813576,0.9224439,0.89401245
865,0.9845543,0.9269671,0.89886475
870,0.9871063,0.9313224,0.9040222
875,0.98947525,0.93566674,0.9099884
880,0.99199677,0.9401049,0.9164734
885,0.9941025,0.9443316,0.9226227
890,0.99520874,0.9480504,0.9276123
895,0.99557877,0.95132226,0.9312897
900,0.9958687,0.95445687,0.9343262
905,0.99609756,0.95751953,0.937027
910,0.9962692,0.9605735,0.9396515
915,0.9963989,0.96368843,0.94252014
920,0.9964943,0.9669233,0.94592285
925,0.9963379,0.9706334,0.9500122
930,0.9957237,0.974823,0.9546356
935,0.99466705,0.97904533,0.95962524
940,0.9931793,0.9828535,0.96487427
945,0.9912758,0.9857984,0.9702301
950,0.988224,0.9881243,0.9767456
955,0.98368454,0.99024093,0.9845581
960,0.9782982,0.9919499,0.9920807
965,0.97270584,0.99304634,0.99775696
970,0.9675293,0.99331665,1.0
975,0.9622688,0.9926278,0.9988861
980,0.9560547,0.99116737,0.9964752
985,0.9489746,0.9891488,0.9940491
990,0.94112396,0.98680335,0.99295044
995,0.93165207,0.98391724,0.99334717
1000,0.9198532,0.98009384,0.99438477
1005,0.90608597,0.9752982,0.9957123
1010,0.8906975,0.9694868,0.9970398
1015,0.8740425,0.9626356,0.99806213
1020,0.856472,0.95470536,0.9984741
1025,0.83699036,0.9440831,0.9965668
1030,0.81474686,0.9297442,0.9912567
1035,0.7902565,0.91251916,0.9832001
1040,0.7640648,0.89323646,0.97299194
1045,0.7366905,0.87270683,0.96128845
1050,0.70866776,0.8517805,0.94873047
1055,0.6784744,0.8289032,0.9313507
1060,0.64549255,0.8028608,0.90708923
1065,0.6115532,0.77492195,0.879303
1070,0.57852554,0.7463662,0.8514404
1075,0.5462322,0.7168862,0.8238678
1080,0.5138664,0.685791,0.79478455
1085,0.48231888,0.6537334,0.7641907
1090,0.45248795,0.6213662,0.73213196
1095,0.42430305,0.5880454,0.69776917
1100,0.3972702,0.55379486,0.6612396
1105,0.37163544,0.5202495,0.62402344
1110,0.34648323,0.48674557,0.5852051
1115,0.32086182,0.4517975,0.54338074
1120,0.29496956,0.4157911,0.49925995
1125,0.26901722,0.37913403,0.45350647
1130,0.2431984,0.34222522,0.40682983
1135,0.21771908,0.3054548,0.3599167
1140,0.19278336,0.26922718,0.31345367
1145,0.16859627,0.23393631,0.2681427
1150,0.14535666,0.19998333,0.22467422
1155,0.12326908,0.16776466,0.18373871
1160,0.102535725,0.1376776,0.14602661
1165,0.083360195,0.11012105,0.1122303
1170,0.06594491,0.08549363,0.08304405
1175,0.050492764,0.064191684,0.059161186
1180,0.037207007,0.046614103,0.041270256
1185,0.024567366,0.030565398,0.026574135
1190,0.01253587,0.015515804,0.013303757
1195,0.0035382658,0.0043616975,0.0036991835
1200,0.0,0.0,0.0
1 change: 1 addition & 0 deletions pvlib/spectrum/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
calc_spectral_mismatch_field,
get_am15g,
get_example_spectral_response,
get_spectral_response_of_material,
spectral_factor_caballero,
spectral_factor_firstsolar,
spectral_factor_sapm,
Expand Down
80 changes: 80 additions & 0 deletions pvlib/spectrum/mismatch.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,10 @@
from scipy.interpolate import interp1d
from scipy.integrate import trapezoid
import os
from pathlib import Path

from warnings import warn
from functools import partial


def get_example_spectral_response(wavelength=None):
Expand Down Expand Up @@ -77,6 +79,84 @@ def get_example_spectral_response(wavelength=None):
return sr


def get_spectral_response_of_material(material, wavelengths=None):
"""
Read spectral response curve of a material from the database [1]_,
optionally interpolated to the specified wavelength(s).

Parameters
----------
material : str
The material name of the spectral response curve to read.
The names are ``'monosi'``, ``'polysi'``, ``'hit'`` and ``'all'``.
wavelengths : numeric, optional
The wavelengths at which the spectral response is interpolated.
By default the 181 available wavelengths are returned. :math:`[nm]`

Returns
-------
spectral_response : pandas.Series or pandas.DataFrame
The returned spectral response curve, indexed by ``wavelengths`` if
provided. If not, the curve is indexed by the 181 default wavelengths.

Notes
-----
The original dataset is available in [1]_.

Wavelengths outside of the range :math:`[300, 1200]` will result in
NaN values.

Examples
--------
>>> print(get_spectral_response_of_material("monosi").head())
>>> wavelength
>>> 300 0.000000
>>> 305 0.046272
>>> 310 0.088575
>>> 315 0.127410
>>> 320 0.163710
>>> Name: monosi, dtype: float64

References
----------
.. [1] A. Driesse, M. Theristis, and J. Stein, “PV module spectral response
measurements - Data and Resources.” EMN-DURMAT (EMN-DuraMAT); Sandia
National Laboratories (SNL-NM), Albuquerque, NM (United States), 2023.
:doi:`10.21948/2204677`.
Available: https://www.osti.gov/servlets/purl/2204677/
"""

sr_dataset_path = Path(pvlib.__path__[0]).joinpath(
"data", "duramat_spectral_responses.csv"
)
dataset = pd.read_csv(sr_dataset_path, index_col=0)

if material in dataset.columns:
dataset = dataset[material]
elif material != "all": # if material=="all", return the whole dataset
raise ValueError(
f"Material '{material}' not found in dataset.\n"
+ f"Available materials are {', '.join((*dataset.columns, 'all'))}"
)

if wavelengths is not None:
interpolator = partial(np.interp, xp=dataset.index, left=0, right=0)
if material == "all": # returned data is a DataFrame
dataset = pd.DataFrame(
index=wavelengths,
data={
col: interpolator(x=wavelengths, fp=dataset[col])
for col in dataset.columns
},
)
else: # returned data is a Series
dataset = pd.Series(
index=wavelengths,
data=interpolator(x=wavelengths, fp=dataset),
)
return dataset


def get_am15g(wavelength=None):
'''
Read the ASTM G173-03 AM1.5 global spectrum on a 37-degree tilted surface,
Expand Down
29 changes: 29 additions & 0 deletions pvlib/tests/test_spectrum.py
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,35 @@ def test_get_example_spectral_response():
assert_allclose(sr, expected, rtol=1e-5)


def test_get_spectral_response_of_material():
# test that the sr curves are read correctly
sr = spectrum.get_spectral_response_of_material(material="all")
assert len(sr) == 181
pd.testing.assert_series_equal(
sr.sum(),
pd.Series({"polysi": 116.32, "monosi": 115.51, "hit": 110.07}),
atol=1e-2,
)

# test raise error if material not in dataset
with pytest.raises(ValueError, match="Material '.*' not found in dataset"):
sr = spectrum.get_spectral_response_of_material(
material="not in dataset"
)

# test correct interpolation
material, wavelength = "polysi", [270, 850, 900, 950, 1200]
expected = [0.0, 0.974667, 0.995869, 0.988224, 0.0]
result = spectrum.get_spectral_response_of_material(material, wavelength)
assert_allclose(result, expected, atol=1e-6)

# "all" interpolation
material, wavelength = "all", [270, 850, 900, 950, 1200]
expected = [0.0, 0.974667, 0.995869, 0.988224, 0.0]
result = spectrum.get_spectral_response_of_material(material, wavelength)
assert_allclose(result["polysi"], expected, atol=1e-6)


def test_get_am15g():
# test that the reference spectrum is read and interpolated correctly
e = spectrum.get_am15g()
Expand Down
Loading