pvlib 0.11.2__py3-none-any.whl → 0.12.1a1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (147) hide show
  1. pvlib/__init__.py +1 -0
  2. pvlib/atmosphere.py +40 -40
  3. pvlib/bifacial/infinite_sheds.py +4 -3
  4. pvlib/bifacial/utils.py +2 -1
  5. pvlib/iotools/__init__.py +6 -0
  6. pvlib/iotools/psm3.py +1 -1
  7. pvlib/iotools/psm4.py +819 -0
  8. pvlib/iotools/pvgis.py +10 -2
  9. pvlib/iotools/tmy.py +3 -69
  10. pvlib/irradiance.py +38 -15
  11. pvlib/ivtools/sdm/__init__.py +20 -0
  12. pvlib/ivtools/sdm/_fit_desoto_pvsyst_sandia.py +585 -0
  13. pvlib/ivtools/sdm/cec.py +93 -0
  14. pvlib/ivtools/sdm/desoto.py +401 -0
  15. pvlib/ivtools/sdm/pvsyst.py +630 -0
  16. pvlib/location.py +73 -33
  17. pvlib/modelchain.py +19 -36
  18. pvlib/pvsystem.py +114 -65
  19. pvlib/snow.py +64 -28
  20. pvlib/spectrum/__init__.py +0 -1
  21. pvlib/spectrum/irradiance.py +2 -64
  22. pvlib/spectrum/mismatch.py +3 -3
  23. pvlib/tools.py +6 -5
  24. {pvlib-0.11.2.dist-info → pvlib-0.12.1a1.dist-info}/METADATA +6 -5
  25. pvlib-0.12.1a1.dist-info/RECORD +80 -0
  26. {pvlib-0.11.2.dist-info → pvlib-0.12.1a1.dist-info}/WHEEL +1 -1
  27. pvlib/data/BIRD_08_16_2012.csv +0 -8761
  28. pvlib/data/BIRD_08_16_2012_patm.csv +0 -8761
  29. pvlib/data/Burlington, United States SolarAnywhere Time Series 2021 Lat_44_465 Lon_-73_205 TMY3 format.csv +0 -8762
  30. pvlib/data/Burlington, United States SolarAnywhere Time Series 20210101 to 20210103 Lat_44_4675 Lon_-73_2075 SA format.csv +0 -578
  31. pvlib/data/Burlington, United States SolarAnywhere Typical GHI Year Lat_44_465 Lon_-73_205 SA format.csv +0 -74
  32. pvlib/data/CPS SCH275KTL-DO-US-800-250kW_275kVA_1.OND +0 -146
  33. pvlib/data/CRNS0101-05-2019-AZ_Tucson_11_W.txt +0 -4
  34. pvlib/data/CRN_with_problems.txt +0 -3
  35. pvlib/data/ET-M772BH550GL.PAN +0 -75
  36. pvlib/data/NLD_Amsterdam062400_IWEC.epw +0 -8768
  37. pvlib/data/PVsyst_demo.csv +0 -10757
  38. pvlib/data/PVsyst_demo_model.csv +0 -3588
  39. pvlib/data/SRML-day-EUPO1801.txt +0 -1441
  40. pvlib/data/abq19056.dat +0 -6
  41. pvlib/data/bishop88_numerical_precision.csv +0 -101
  42. pvlib/data/bsrn-lr0100-pay0616.dat +0 -86901
  43. pvlib/data/bsrn-pay0616.dat.gz +0 -0
  44. pvlib/data/cams_mcclear_1min_verbose.csv +0 -60
  45. pvlib/data/cams_mcclear_monthly.csv +0 -42
  46. pvlib/data/cams_radiation_1min_verbose.csv +0 -72
  47. pvlib/data/cams_radiation_monthly.csv +0 -47
  48. pvlib/data/detect_clearsky_data.csv +0 -35
  49. pvlib/data/detect_clearsky_threshold_data.csv +0 -126
  50. pvlib/data/greensboro_kimber_soil_manwash.dat +0 -8761
  51. pvlib/data/greensboro_kimber_soil_nowash.dat +0 -8761
  52. pvlib/data/inverter_fit_snl_meas.csv +0 -127
  53. pvlib/data/inverter_fit_snl_sim.csv +0 -19
  54. pvlib/data/ivtools_numdiff.csv +0 -52
  55. pvlib/data/midc_20181014.txt +0 -1441
  56. pvlib/data/midc_raw_20181018.txt +0 -1441
  57. pvlib/data/midc_raw_short_header_20191115.txt +0 -1441
  58. pvlib/data/msn19056.dat +0 -6
  59. pvlib/data/precise_iv_curves1.json +0 -10251
  60. pvlib/data/precise_iv_curves2.json +0 -10251
  61. pvlib/data/precise_iv_curves_parameter_sets1.csv +0 -33
  62. pvlib/data/precise_iv_curves_parameter_sets2.csv +0 -33
  63. pvlib/data/pvgis_hourly_Timeseries_45.000_8.000_SA2_10kWp_CIS_5_2a_2013_2014.json +0 -1
  64. pvlib/data/pvgis_hourly_Timeseries_45.000_8.000_SA_30deg_0deg_2016_2016.csv +0 -35
  65. pvlib/data/pvgis_tmy_meta.json +0 -32
  66. pvlib/data/pvgis_tmy_test.csv +0 -8761
  67. pvlib/data/pvwatts_8760_rackmount.csv +0 -8779
  68. pvlib/data/pvwatts_8760_roofmount.csv +0 -8779
  69. pvlib/data/singleaxis_tracker_wslope.csv +0 -8761
  70. pvlib/data/spectrl2_example_spectra.csv +0 -123
  71. pvlib/data/surfrad-slv16001.dat +0 -1442
  72. pvlib/data/test_psm3_2017.csv +0 -17521
  73. pvlib/data/test_psm3_2019_5min.csv +0 -289
  74. pvlib/data/test_psm3_tmy-2017.csv +0 -8761
  75. pvlib/data/test_read_psm3.csv +0 -17523
  76. pvlib/data/test_read_pvgis_horizon.csv +0 -49
  77. pvlib/data/tmy_45.000_8.000_2005_2023.csv +0 -8789
  78. pvlib/data/tmy_45.000_8.000_2005_2023.epw +0 -8768
  79. pvlib/data/tmy_45.000_8.000_2005_2023.json +0 -1
  80. pvlib/data/tmy_45.000_8.000_2005_2023.txt +0 -8761
  81. pvlib/data/tmy_45.000_8.000_userhorizon.json +0 -1
  82. pvlib/ivtools/sdm.py +0 -1379
  83. pvlib/spa_c_files/README.md +0 -81
  84. pvlib/spa_c_files/cspa_py.pxd +0 -43
  85. pvlib/spa_c_files/spa_py.pyx +0 -30
  86. pvlib/tests/__init__.py +0 -0
  87. pvlib/tests/bifacial/__init__.py +0 -0
  88. pvlib/tests/bifacial/test_infinite_sheds.py +0 -317
  89. pvlib/tests/bifacial/test_losses_models.py +0 -54
  90. pvlib/tests/bifacial/test_pvfactors.py +0 -82
  91. pvlib/tests/bifacial/test_utils.py +0 -192
  92. pvlib/tests/conftest.py +0 -476
  93. pvlib/tests/iotools/__init__.py +0 -0
  94. pvlib/tests/iotools/test_acis.py +0 -213
  95. pvlib/tests/iotools/test_bsrn.py +0 -131
  96. pvlib/tests/iotools/test_crn.py +0 -95
  97. pvlib/tests/iotools/test_epw.py +0 -23
  98. pvlib/tests/iotools/test_midc.py +0 -89
  99. pvlib/tests/iotools/test_panond.py +0 -32
  100. pvlib/tests/iotools/test_psm3.py +0 -198
  101. pvlib/tests/iotools/test_pvgis.py +0 -644
  102. pvlib/tests/iotools/test_sodapro.py +0 -298
  103. pvlib/tests/iotools/test_solaranywhere.py +0 -287
  104. pvlib/tests/iotools/test_solargis.py +0 -68
  105. pvlib/tests/iotools/test_solcast.py +0 -324
  106. pvlib/tests/iotools/test_solrad.py +0 -152
  107. pvlib/tests/iotools/test_srml.py +0 -124
  108. pvlib/tests/iotools/test_surfrad.py +0 -75
  109. pvlib/tests/iotools/test_tmy.py +0 -133
  110. pvlib/tests/ivtools/__init__.py +0 -0
  111. pvlib/tests/ivtools/test_sde.py +0 -230
  112. pvlib/tests/ivtools/test_sdm.py +0 -429
  113. pvlib/tests/ivtools/test_utils.py +0 -173
  114. pvlib/tests/spectrum/__init__.py +0 -0
  115. pvlib/tests/spectrum/conftest.py +0 -40
  116. pvlib/tests/spectrum/test_irradiance.py +0 -138
  117. pvlib/tests/spectrum/test_mismatch.py +0 -304
  118. pvlib/tests/spectrum/test_response.py +0 -124
  119. pvlib/tests/spectrum/test_spectrl2.py +0 -72
  120. pvlib/tests/test__deprecation.py +0 -97
  121. pvlib/tests/test_albedo.py +0 -84
  122. pvlib/tests/test_atmosphere.py +0 -351
  123. pvlib/tests/test_clearsky.py +0 -884
  124. pvlib/tests/test_conftest.py +0 -37
  125. pvlib/tests/test_iam.py +0 -555
  126. pvlib/tests/test_inverter.py +0 -213
  127. pvlib/tests/test_irradiance.py +0 -1487
  128. pvlib/tests/test_location.py +0 -356
  129. pvlib/tests/test_modelchain.py +0 -2020
  130. pvlib/tests/test_numerical_precision.py +0 -124
  131. pvlib/tests/test_pvarray.py +0 -71
  132. pvlib/tests/test_pvsystem.py +0 -2511
  133. pvlib/tests/test_scaling.py +0 -207
  134. pvlib/tests/test_shading.py +0 -391
  135. pvlib/tests/test_singlediode.py +0 -608
  136. pvlib/tests/test_snow.py +0 -212
  137. pvlib/tests/test_soiling.py +0 -230
  138. pvlib/tests/test_solarposition.py +0 -966
  139. pvlib/tests/test_spa.py +0 -454
  140. pvlib/tests/test_temperature.py +0 -470
  141. pvlib/tests/test_tools.py +0 -146
  142. pvlib/tests/test_tracking.py +0 -474
  143. pvlib/tests/test_transformer.py +0 -60
  144. pvlib-0.11.2.dist-info/RECORD +0 -191
  145. {pvlib-0.11.2.dist-info → pvlib-0.12.1a1.dist-info/licenses}/AUTHORS.md +0 -0
  146. {pvlib-0.11.2.dist-info → pvlib-0.12.1a1.dist-info/licenses}/LICENSE +0 -0
  147. {pvlib-0.11.2.dist-info → pvlib-0.12.1a1.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,630 @@
1
+ import numpy as np
2
+
3
+ from scipy import constants
4
+
5
+ from pvlib.pvsystem import calcparams_pvsyst
6
+ from pvlib.singlediode import bishop88_mpp
7
+
8
+ from pvlib.ivtools.utils import rectify_iv_curve
9
+ from pvlib.ivtools.sde import _fit_sandia_cocontent
10
+
11
+ from pvlib.tools import _first_order_centered_difference
12
+
13
+ from pvlib.ivtools.sdm._fit_desoto_pvsyst_sandia import (
14
+ _extract_sdm_params, _initial_iv_params, _update_iv_params
15
+ )
16
+
17
+ from pvlib.pvsystem import (
18
+ _pvsyst_Rsh, _pvsyst_IL, _pvsyst_Io, _pvsyst_nNsVth, _pvsyst_gamma
19
+ )
20
+
21
+ CONSTANTS = {'E0': 1000.0, 'T0': 25.0, 'k': constants.k, 'q': constants.e}
22
+
23
+
24
+ def fit_pvsyst_sandia(ivcurves, specs, const=None, maxiter=5, eps1=1.e-3):
25
+ """
26
+ Estimate parameters for the PVsyst module performance model.
27
+
28
+ Parameters
29
+ ----------
30
+ ivcurves : dict
31
+ i : array
32
+ One array element for each IV curve. The jth element is itself an
33
+ array of current for jth IV curve (same length as v[j]) [A]
34
+ v : array
35
+ One array element for each IV curve. The jth element is itself an
36
+ array of voltage for jth IV curve (same length as i[j]) [V]
37
+ ee : array
38
+ effective irradiance for each IV curve, i.e., POA broadband
39
+ irradiance adjusted by solar spectrum modifier [W / m^2]
40
+ tc : array
41
+ cell temperature for each IV curve [C]
42
+ i_sc : array
43
+ short circuit current for each IV curve [A]
44
+ v_oc : array
45
+ open circuit voltage for each IV curve [V]
46
+ i_mp : array
47
+ current at max power point for each IV curve [A]
48
+ v_mp : array
49
+ voltage at max power point for each IV curve [V]
50
+
51
+ specs : dict
52
+ cells_in_series : int
53
+ number of cells in series
54
+ alpha_sc : float
55
+ temperature coefficient of isc [A/C]
56
+
57
+ const : dict
58
+ E0 : float
59
+ effective irradiance at STC, default 1000 [W/m^2]
60
+ T0 : float
61
+ cell temperature at STC, default 25 [C]
62
+ k : float
63
+ Boltzmann's constant [J/K]
64
+ q : float
65
+ elementary charge [Coulomb]
66
+
67
+ maxiter : int, default 5
68
+ input that sets the maximum number of iterations for the parameter
69
+ updating part of the algorithm.
70
+
71
+ eps1: float, default 1e-3
72
+ Tolerance for the IV curve fitting. The parameter updating stops when
73
+ absolute values of the percent change in mean, max and standard
74
+ deviation of Imp, Vmp and Pmp between iterations are all less than
75
+ eps1, or when the number of iterations exceeds maxiter.
76
+
77
+ Returns
78
+ -------
79
+ dict
80
+ I_L_ref : float
81
+ light current at STC [A]
82
+ I_o_ref : float
83
+ dark current at STC [A]
84
+ EgRef : float
85
+ effective band gap at STC [eV]
86
+ R_s : float
87
+ series resistance at STC [ohm]
88
+ R_sh_ref : float
89
+ shunt resistance at STC [ohm]
90
+ R_sh_0 : float
91
+ shunt resistance at zero irradiance [ohm]
92
+ R_sh_exp : float
93
+ exponential factor defining decrease in shunt resistance with
94
+ increasing effective irradiance
95
+ gamma_ref : float
96
+ diode (ideality) factor at STC [unitless]
97
+ mu_gamma : float
98
+ temperature coefficient for diode (ideality) factor [1/K]
99
+ cells_in_series : int
100
+ number of cells in series
101
+ iph : array
102
+ light current for each IV curve [A]
103
+ io : array
104
+ dark current for each IV curve [A]
105
+ rs : array
106
+ series resistance for each IV curve [ohm]
107
+ rsh : array
108
+ shunt resistance for each IV curve [ohm]
109
+ u : array
110
+ boolean for each IV curve indicating that the parameter values
111
+ are deemed reasonable by the private function ``_filter_params``
112
+
113
+ Notes
114
+ -----
115
+ The PVsyst module performance model is described in [1]_, [2]_, and [3]_.
116
+ The fitting method is documented in [4]_, [5]_, and [6]_.
117
+ Ported from PVLib Matlab [7]_.
118
+
119
+ References
120
+ ----------
121
+ .. [1] K. Sauer, T. Roessler, C. W. Hansen, Modeling the Irradiance and
122
+ Temperature Dependence of Photovoltaic Modules in PVsyst, IEEE Journal
123
+ of Photovoltaics v5(1), January 2015.
124
+ :doi:`10.1109/JPHOTOV.2014.2364133`
125
+ .. [2] A. Mermoud, PV Modules modeling, Presentation at the 2nd PV
126
+ Performance Modeling Workshop, Santa Clara, CA, May 2013
127
+ .. [3] A. Mermoud, T. Lejeuene, Performance Assessment of a Simulation
128
+ Model for PV modules of any available technology, 25th European
129
+ Photovoltaic Solar Energy Conference, Valencia, Spain, Sept. 2010
130
+ .. [4] C. Hansen, Estimating Parameters for the PVsyst Version 6
131
+ Photovoltaic Module Performance Model, Sandia National Laboratories
132
+ Report SAND2015-8598. :doi:`10.2172/1223058`
133
+ .. [5] C. Hansen, Parameter Estimation for Single Diode Models of
134
+ Photovoltaic Modules, Sandia National Laboratories Report SAND2015-2065.
135
+ :doi:`10.2172/1177157`
136
+ .. [6] C. Hansen, Estimation of Parameters for Single Diode Models using
137
+ Measured IV Curves, Proc. of the 39th IEEE PVSC, June 2013.
138
+ :doi:`10.1109/PVSC.2013.6744135`
139
+ .. [7] PVLib MATLAB https://github.com/sandialabs/MATLAB_PV_LIB
140
+ """
141
+
142
+ if const is None:
143
+ const = CONSTANTS
144
+
145
+ ee = ivcurves['ee']
146
+ tc = ivcurves['tc']
147
+ tck = tc + 273.15
148
+ isc = ivcurves['i_sc']
149
+ voc = ivcurves['v_oc']
150
+ imp = ivcurves['i_mp']
151
+ vmp = ivcurves['v_mp']
152
+
153
+ # Cell Thermal Voltage
154
+ vth = const['k'] / const['q'] * tck
155
+
156
+ n = len(ivcurves['v_oc'])
157
+
158
+ # Initial estimate of Rsh used to obtain the diode factor gamma0 and diode
159
+ # temperature coefficient mu_gamma. Rsh is estimated using the co-content
160
+ # integral method.
161
+
162
+ rsh = np.ones(n)
163
+ for j in range(n):
164
+ voltage, current = rectify_iv_curve(ivcurves['v'][j], ivcurves['i'][j])
165
+ # initial estimate of Rsh, from integral over voltage regression
166
+ # [5] Step 3a; [6] Step 3a
167
+ _, _, _, rsh[j], _ = _fit_sandia_cocontent(
168
+ voltage, current, vth[j] * specs['cells_in_series'])
169
+
170
+ gamma_ref, mu_gamma = _fit_pvsyst_sandia_gamma(voc, isc, rsh, vth, tck,
171
+ specs, const)
172
+
173
+ badgamma = np.isnan(gamma_ref) or np.isnan(mu_gamma) \
174
+ or not np.isreal(gamma_ref) or not np.isreal(mu_gamma)
175
+
176
+ if badgamma:
177
+ raise RuntimeError(
178
+ "Failed to estimate the diode (ideality) factor parameter;"
179
+ " aborting parameter estimation.")
180
+
181
+ gamma = gamma_ref + mu_gamma * (tc - const['T0'])
182
+ nnsvth = gamma * (vth * specs['cells_in_series'])
183
+
184
+ # For each IV curve, sequentially determine initial values for Io, Rs,
185
+ # and Iph [5] Step 3a; [6] Step 3
186
+ iph, io, rs, u = _initial_iv_params(ivcurves, ee, voc, isc, rsh,
187
+ nnsvth)
188
+
189
+ # Update values for each IV curve to converge at vmp, imp, voc and isc
190
+ iph, io, rs, rsh, u = _update_iv_params(voc, isc, vmp, imp, ee,
191
+ iph, io, rs, rsh, nnsvth, u,
192
+ maxiter, eps1)
193
+
194
+ # get single diode models from converged values for each IV curve
195
+ pvsyst = _extract_sdm_params(ee, tc, iph, io, rs, rsh, gamma, u,
196
+ specs, const, model='pvsyst')
197
+ # Add parameters estimated in this function
198
+ pvsyst['gamma_ref'] = gamma_ref
199
+ pvsyst['mu_gamma'] = mu_gamma
200
+ pvsyst['cells_in_series'] = specs['cells_in_series']
201
+
202
+ return pvsyst
203
+
204
+
205
+ def _fit_pvsyst_sandia_gamma(voc, isc, rsh, vth, tck, specs, const):
206
+ # Estimate the diode factor gamma from Isc-Voc data. Method incorporates
207
+ # temperature dependence by means of the equation for Io
208
+
209
+ y = np.log(isc - voc / rsh) - 3. * np.log(tck / (const['T0'] + 273.15))
210
+ x1 = const['q'] / const['k'] * (1. / (const['T0'] + 273.15) - 1. / tck)
211
+ x2 = voc / (vth * specs['cells_in_series'])
212
+ uu = np.logical_or(np.isnan(y), np.isnan(x1), np.isnan(x2))
213
+
214
+ x = np.vstack((np.ones(len(x1[~uu])), x1[~uu], -x1[~uu] *
215
+ (tck[~uu] - (const['T0'] + 273.15)), x2[~uu],
216
+ -x2[~uu] * (tck[~uu] - (const['T0'] + 273.15)))).T
217
+ alpha = np.linalg.lstsq(x, y[~uu], rcond=None)[0]
218
+
219
+ gamma_ref = 1. / alpha[3]
220
+ mu_gamma = alpha[4] / alpha[3] ** 2
221
+ return gamma_ref, mu_gamma
222
+
223
+
224
+ def pvsyst_temperature_coeff(alpha_sc, gamma_ref, mu_gamma, I_L_ref, I_o_ref,
225
+ R_sh_ref, R_sh_0, R_s, cells_in_series,
226
+ R_sh_exp=5.5, EgRef=1.121, irrad_ref=1000,
227
+ temp_ref=25):
228
+ r"""
229
+ Calculates the temperature coefficient of power for a pvsyst single
230
+ diode model.
231
+
232
+ The temperature coefficient is determined as the numerical derivative
233
+ :math:`\frac{dP}{dT}` at the maximum power point at reference conditions
234
+ [1]_.
235
+
236
+ Parameters
237
+ ----------
238
+ alpha_sc : float
239
+ The short-circuit current temperature coefficient of the module. [A/C]
240
+
241
+ gamma_ref : float
242
+ The diode ideality factor. [unitless]
243
+
244
+ mu_gamma : float
245
+ The temperature coefficient for the diode ideality factor. [1/K]
246
+
247
+ I_L_ref : float
248
+ The light-generated current (or photocurrent) at reference conditions.
249
+ [A]
250
+
251
+ I_o_ref : float
252
+ The dark or diode reverse saturation current at reference conditions.
253
+ [A]
254
+
255
+ R_sh_ref : float
256
+ The shunt resistance at reference conditions. [ohm]
257
+
258
+ R_sh_0 : float
259
+ The shunt resistance at zero irradiance conditions. [ohm]
260
+
261
+ R_s : float
262
+ The series resistance at reference conditions. [ohm]
263
+
264
+ cells_in_series : int
265
+ The number of cells connected in series.
266
+
267
+ R_sh_exp : float, default 5.5
268
+ The exponent in the equation for shunt resistance. [unitless]
269
+
270
+ EgRef : float, default 1.121
271
+ The energy bandgap of the module's cells at reference temperature.
272
+ Default of 1.121 eV is for crystalline silicon. Must be positive. [eV]
273
+
274
+ irrad_ref : float, default 1000
275
+ Reference irradiance. [W/m^2].
276
+
277
+ temp_ref : float, default 25
278
+ Reference cell temperature. [C]
279
+
280
+
281
+ Returns
282
+ -------
283
+ gamma_pdc : float
284
+ Temperature coefficient of power at maximum power point at reference
285
+ conditions. [1/C]
286
+
287
+ References
288
+ ----------
289
+ .. [1] K. Sauer, T. Roessler, C. W. Hansen, Modeling the Irradiance and
290
+ Temperature Dependence of Photovoltaic Modules in PVsyst, IEEE Journal
291
+ of Photovoltaics v5(1), January 2015.
292
+ """
293
+
294
+ def maxp(temp_cell, irrad_ref, alpha_sc, gamma_ref, mu_gamma, I_L_ref,
295
+ I_o_ref, R_sh_ref, R_sh_0, R_s, cells_in_series, R_sh_exp, EgRef,
296
+ temp_ref):
297
+ params = calcparams_pvsyst(
298
+ irrad_ref, temp_cell, alpha_sc, gamma_ref, mu_gamma, I_L_ref,
299
+ I_o_ref, R_sh_ref, R_sh_0, R_s, cells_in_series, R_sh_exp, EgRef,
300
+ irrad_ref, temp_ref)
301
+ res = bishop88_mpp(*params)
302
+ return res[2]
303
+
304
+ args = (irrad_ref, alpha_sc, gamma_ref, mu_gamma, I_L_ref,
305
+ I_o_ref, R_sh_ref, R_sh_0, R_s, cells_in_series, R_sh_exp, EgRef,
306
+ temp_ref)
307
+ pmp = maxp(temp_ref, *args)
308
+ gamma_pdc = _first_order_centered_difference(maxp, x0=temp_ref, args=args)
309
+
310
+ return gamma_pdc / pmp
311
+
312
+
313
+ def fit_pvsyst_iec61853_sandia_2025(effective_irradiance, temp_cell,
314
+ i_sc, v_oc, i_mp, v_mp,
315
+ cells_in_series, EgRef=1.121,
316
+ alpha_sc=None, beta_mp=None,
317
+ R_s=None, r_sh_coeff=0.12,
318
+ min_Rsh_irradiance=None,
319
+ irradiance_tolerance=20,
320
+ temperature_tolerance=1):
321
+ """
322
+ Estimate parameters for the PVsyst module performance model using
323
+ IEC 61853-1 matrix measurements.
324
+
325
+ Parameters
326
+ ----------
327
+ effective_irradiance : array
328
+ Effective irradiance for each test condition [W/m²]
329
+ temp_cell : array
330
+ Cell temperature for each test condition [C]
331
+ i_sc : array
332
+ Short circuit current for each test condition [A]
333
+ v_oc : array
334
+ Open circuit voltage for each test condition [V]
335
+ i_mp : array
336
+ Current at maximum power point for each test condition [A]
337
+ v_mp : array
338
+ Voltage at maximum power point for each test condition [V]
339
+ cells_in_series : int
340
+ The number of cells connected in series.
341
+ EgRef : float, optional
342
+ The energy bandgap at reference temperature in units of eV.
343
+ 1.121 eV for crystalline silicon. EgRef must be >0.
344
+ alpha_sc : float, optional
345
+ Temperature coefficient of short circuit current. If not specified,
346
+ it will be estimated using the ``i_sc`` values at irradiance of
347
+ 1000 W/m2. [A/K]
348
+ beta_mp : float, optional
349
+ Temperature coefficient of maximum power voltage. If not specified,
350
+ it will be estimated using the ``v_mp`` values at irradiance of
351
+ 1000 W/m2. [1/K]
352
+ R_s : float, optional
353
+ Series resistance value. If not provided, a value will be estimated
354
+ from the input measurements. [ohm]
355
+ r_sh_coeff : float, default 0.12
356
+ Shunt resistance fitting coefficient. The default value is taken
357
+ from [1]_.
358
+ min_Rsh_irradiance : float, optional
359
+ Irradiance threshold below which values are excluded when estimating
360
+ shunt resistance parameter values. May be useful for modules
361
+ with problematic low-light measurements. [W/m²]
362
+ irradiance_tolerance : float, default 20
363
+ Tolerance for irradiance variation around the STC value.
364
+ The default value corresponds to a +/- 2% interval around the STC
365
+ value of 1000 W/m². [W/m²]
366
+ temperature_tolerance : float, default 1
367
+ Tolerance for temperature variation around the STC value.
368
+ The default value corresponds to a +/- 1 degree interval around the STC
369
+ value of 25 degrees. [C]
370
+
371
+ Returns
372
+ -------
373
+ dict
374
+ alpha_sc : float
375
+ short circuit current temperature coefficient [A/K]
376
+ gamma_ref : float
377
+ diode (ideality) factor at STC [unitless]
378
+ mu_gamma : float
379
+ temperature coefficient for diode (ideality) factor [1/K]
380
+ I_L_ref : float
381
+ light current at STC [A]
382
+ I_o_ref : float
383
+ dark current at STC [A]
384
+ R_sh_ref : float
385
+ shunt resistance at STC [ohm]
386
+ R_sh_0 : float
387
+ shunt resistance at zero irradiance [ohm]
388
+ R_sh_exp : float
389
+ exponential factor defining decrease in shunt resistance with
390
+ increasing effective irradiance
391
+ R_s : float
392
+ series resistance at STC [ohm]
393
+ cells_in_series : int
394
+ number of cells in series
395
+ EgRef : float
396
+ effective band gap at STC [eV]
397
+
398
+ See also
399
+ --------
400
+ pvlib.pvsystem.calcparams_pvsyst
401
+ pvlib.ivtools.sdm.fit_pvsyst_sandia
402
+
403
+ Notes
404
+ -----
405
+ Input arrays of operating conditions and electrical measurements must be
406
+ 1-D with equal lengths.
407
+
408
+ Values supplied for ``alpha_sc``, ``beta_mp``, and ``R_s`` must be
409
+ consistent with the matrix data, as these values are used when estimating
410
+ other model parameters.
411
+
412
+ This method is non-iterative. In some cases, it may be desirable to
413
+ refine the estimated parameter values using a numerical optimizer such as
414
+ the default method in ``scipy.optimize.minimize``.
415
+
416
+ References
417
+ ----------
418
+ .. [1] K. S. Anderson, C. W. Hansen, and M. Theristis, "A Noniterative
419
+ Method of Estimating Parameter Values for the PVsyst Version 6
420
+ Single-Diode Model From IEC 61853-1 Matrix Measurements," IEEE Journal
421
+ of Photovoltaics, vol. 15, 3, 2025. :doi:`10.1109/JPHOTOV.2025.3554338`
422
+ """
423
+
424
+ is_g_stc = np.isclose(effective_irradiance, 1000, rtol=0,
425
+ atol=irradiance_tolerance)
426
+ is_t_stc = np.isclose(temp_cell, 25, rtol=0,
427
+ atol=temperature_tolerance)
428
+
429
+ if alpha_sc is None:
430
+ mu_i_sc = _fit_tempco_pvsyst_iec61853_sandia_2025(i_sc[is_g_stc],
431
+ temp_cell[is_g_stc])
432
+ i_sc_ref = float(i_sc[is_g_stc & is_t_stc].item())
433
+ alpha_sc = mu_i_sc * i_sc_ref
434
+
435
+ if beta_mp is None:
436
+ beta_mp = _fit_tempco_pvsyst_iec61853_sandia_2025(v_mp[is_g_stc],
437
+ temp_cell[is_g_stc])
438
+
439
+ R_sh_ref, R_sh_0, R_sh_exp = \
440
+ _fit_shunt_resistances_pvsyst_iec61853_sandia_2025(
441
+ i_sc, i_mp, v_mp, effective_irradiance, temp_cell, beta_mp,
442
+ coeff=r_sh_coeff, min_irradiance=min_Rsh_irradiance)
443
+
444
+ if R_s is None:
445
+ R_s = _fit_series_resistance_pvsyst_iec61853_sandia_2025(v_oc, i_mp,
446
+ v_mp)
447
+
448
+ gamma_ref, mu_gamma = \
449
+ _fit_diode_ideality_factor_pvsyst_iec61853_sandia_2025(
450
+ i_sc[is_t_stc], v_oc[is_t_stc], i_mp[is_t_stc], v_mp[is_t_stc],
451
+ effective_irradiance[is_t_stc], temp_cell[is_t_stc],
452
+ R_sh_ref, R_sh_0, R_sh_exp, R_s, cells_in_series)
453
+
454
+ I_o_ref = _fit_saturation_current_pvsyst_iec61853_sandia_2025(
455
+ i_sc, v_oc, effective_irradiance, temp_cell, gamma_ref, mu_gamma,
456
+ R_sh_ref, R_sh_0, R_sh_exp, R_s, cells_in_series, EgRef
457
+ )
458
+
459
+ I_L_ref = _fit_photocurrent_pvsyst_iec61853_sandia_2025(
460
+ i_sc, effective_irradiance, temp_cell, alpha_sc,
461
+ gamma_ref, mu_gamma,
462
+ I_o_ref, R_sh_ref, R_sh_0, R_sh_exp, R_s, cells_in_series, EgRef
463
+ )
464
+
465
+ gamma_ref, mu_gamma = \
466
+ _fit_diode_ideality_factor_post_pvsyst_iec61853_sandia_2025(
467
+ i_mp, v_mp, effective_irradiance, temp_cell, alpha_sc, I_L_ref,
468
+ I_o_ref, R_sh_ref, R_sh_0, R_sh_exp, R_s, cells_in_series, EgRef)
469
+
470
+ fitted_params = dict(
471
+ alpha_sc=alpha_sc,
472
+ gamma_ref=gamma_ref,
473
+ mu_gamma=mu_gamma,
474
+ I_L_ref=I_L_ref,
475
+ I_o_ref=I_o_ref,
476
+ R_sh_ref=R_sh_ref,
477
+ R_sh_0=R_sh_0,
478
+ R_sh_exp=R_sh_exp,
479
+ R_s=R_s,
480
+ cells_in_series=cells_in_series,
481
+ EgRef=EgRef,
482
+ )
483
+ return fitted_params
484
+
485
+
486
+ def _fit_tempco_pvsyst_iec61853_sandia_2025(values, temp_cell,
487
+ temp_cell_ref=25):
488
+ fit = np.polynomial.polynomial.Polynomial.fit(temp_cell, values, deg=1)
489
+ intercept, slope = fit.convert().coef
490
+ value_ref = intercept + slope*temp_cell_ref
491
+ return slope / value_ref
492
+
493
+
494
+ def _fit_shunt_resistances_pvsyst_iec61853_sandia_2025(
495
+ i_sc, i_mp, v_mp, effective_irradiance, temp_cell,
496
+ beta_v_mp, coeff=0.2, min_irradiance=None):
497
+ if min_irradiance is None:
498
+ min_irradiance = 0
499
+
500
+ mask = effective_irradiance >= min_irradiance
501
+ i_sc = i_sc[mask]
502
+ i_mp = i_mp[mask]
503
+ v_mp = v_mp[mask]
504
+ effective_irradiance = effective_irradiance[mask]
505
+ temp_cell = temp_cell[mask]
506
+
507
+ # Equation 10
508
+ Rsh_est = (
509
+ (v_mp / (1 + beta_v_mp * (temp_cell - 25)))
510
+ / (coeff * (i_sc - i_mp))
511
+ )
512
+ Rshexp = 5.5
513
+
514
+ # Eq 11
515
+ y = Rsh_est
516
+ x = np.exp(-Rshexp * effective_irradiance / 1000)
517
+
518
+ fit = np.polynomial.polynomial.Polynomial.fit(x, y, deg=1)
519
+ intercept, slope = fit.convert().coef
520
+ Rshbase = intercept
521
+ Rsh0 = slope + Rshbase
522
+
523
+ # Eq 12
524
+ expRshexp = np.exp(-Rshexp)
525
+ Rshref = Rshbase * (1 - expRshexp) + Rsh0 * expRshexp
526
+
527
+ return Rshref, Rsh0, Rshexp
528
+
529
+
530
+ def _fit_series_resistance_pvsyst_iec61853_sandia_2025(v_oc, i_mp, v_mp):
531
+ # Stein et al 2014, https://doi.org/10.1109/PVSC.2014.6925326
532
+
533
+ # Eq 13
534
+ x = np.array([np.ones(len(i_mp)), i_mp, np.log(i_mp), v_mp]).T
535
+ y = v_oc
536
+
537
+ coeff, _, _, _ = np.linalg.lstsq(x, y, rcond=None)
538
+ R_s = coeff[1]
539
+ return R_s
540
+
541
+
542
+ def _fit_diode_ideality_factor_pvsyst_iec61853_sandia_2025(
543
+ i_sc, v_oc, i_mp, v_mp, effective_irradiance, temp_cell,
544
+ R_sh_ref, R_sh_0, R_sh_exp, R_s, cells_in_series):
545
+
546
+ NsVth = _pvsyst_nNsVth(temp_cell, gamma=1, cells_in_series=cells_in_series)
547
+ Rsh = _pvsyst_Rsh(effective_irradiance, R_sh_ref, R_sh_0, R_sh_exp)
548
+ term1 = (i_sc * (1 + R_s/Rsh) - v_oc / Rsh) # Eq 15
549
+ term2 = (i_sc - i_mp) * (1 + R_s/Rsh) - v_mp / Rsh # Eq 16
550
+
551
+ # Eq 14
552
+ x1 = NsVth * np.log(term2 / term1)
553
+
554
+ x = np.array([x1]).T
555
+ y = v_mp + i_mp*R_s - v_oc
556
+
557
+ coeff, _, _, _ = np.linalg.lstsq(x, y, rcond=None)
558
+ gamma_ref = coeff[0]
559
+ return gamma_ref, 0
560
+
561
+
562
+ def _fit_saturation_current_pvsyst_iec61853_sandia_2025(
563
+ i_sc, v_oc, effective_irradiance, temp_cell, gamma_ref, mu_gamma,
564
+ R_sh_ref, R_sh_0, R_sh_exp, R_s, cells_in_series, EgRef):
565
+ R_sh = _pvsyst_Rsh(effective_irradiance, R_sh_ref, R_sh_0, R_sh_exp)
566
+ gamma = _pvsyst_gamma(temp_cell, gamma_ref, mu_gamma)
567
+ nNsVth = _pvsyst_nNsVth(temp_cell, gamma, cells_in_series)
568
+
569
+ # Eq 17
570
+ I_o_est = (i_sc * (1 + R_s/R_sh) - v_oc/R_sh) / (np.expm1(v_oc / nNsVth))
571
+ x = _pvsyst_Io(temp_cell, gamma, I_o_ref=1, EgRef=EgRef)
572
+
573
+ # Eq 18
574
+ log_I_o_ref = np.mean(np.log(I_o_est) - np.log(x))
575
+ I_o_ref = np.exp(log_I_o_ref)
576
+
577
+ return I_o_ref
578
+
579
+
580
+ def _fit_photocurrent_pvsyst_iec61853_sandia_2025(
581
+ i_sc, effective_irradiance, temp_cell, alpha_sc, gamma_ref,
582
+ mu_gamma, I_o_ref, R_sh_ref, R_sh_0, R_sh_exp, R_s, cells_in_series,
583
+ EgRef):
584
+ R_sh = _pvsyst_Rsh(effective_irradiance, R_sh_ref, R_sh_0, R_sh_exp)
585
+ gamma = _pvsyst_gamma(temp_cell, gamma_ref, mu_gamma)
586
+ I_o = _pvsyst_Io(temp_cell, gamma, I_o_ref, EgRef)
587
+ nNsVth = _pvsyst_nNsVth(temp_cell, gamma, cells_in_series)
588
+
589
+ # Eq 19
590
+ I_L_est = i_sc + I_o * (np.expm1(i_sc * R_s / nNsVth)) + i_sc * R_s / R_sh
591
+
592
+ # Eq 20
593
+ x = np.array([effective_irradiance / 1000]).T
594
+ y = I_L_est - effective_irradiance / 1000 * alpha_sc * (temp_cell - 25)
595
+ coeff, _, _, _ = np.linalg.lstsq(x, y, rcond=None)
596
+ I_L_ref = coeff[0]
597
+ return I_L_ref
598
+
599
+
600
+ def _fit_diode_ideality_factor_post_pvsyst_iec61853_sandia_2025(
601
+ i_mp, v_mp, effective_irradiance, temp_cell, alpha_sc, I_L_ref,
602
+ I_o_ref, R_sh_ref, R_sh_0, R_sh_exp, R_s, cells_in_series, EgRef):
603
+
604
+ Rsh = _pvsyst_Rsh(effective_irradiance, R_sh_ref, R_sh_0, R_sh_exp)
605
+ I_L = _pvsyst_IL(effective_irradiance, temp_cell, I_L_ref, alpha_sc)
606
+ NsVth = _pvsyst_nNsVth(temp_cell, gamma=1, cells_in_series=cells_in_series)
607
+
608
+ Tref_K = 25 + 273.15
609
+ Tcell_K = temp_cell + 273.15
610
+
611
+ # Eq 21
612
+ k = constants.k # Boltzmann constant in J/K
613
+ q = constants.e # elementary charge in coulomb
614
+ numerator = (
615
+ (q * EgRef / k) * (1/Tref_K - 1/Tcell_K)
616
+ + (v_mp + i_mp*R_s) / NsVth
617
+ )
618
+ denominator = (
619
+ np.log((I_L - i_mp - (v_mp+i_mp*R_s) / Rsh) / I_o_ref)
620
+ - 3 * np.log(Tcell_K / Tref_K)
621
+ )
622
+ gamma_est = numerator / denominator
623
+
624
+ # Eq 22
625
+ x = np.array([np.ones(len(i_mp)), temp_cell - 25]).T
626
+ y = gamma_est
627
+
628
+ coeff, _, _, _ = np.linalg.lstsq(x, y, rcond=None)
629
+ gamma_ref, mu_gamma = coeff
630
+ return gamma_ref, mu_gamma