Skip to content

Commit bb86a53

Browse files
committed
replace statsmodels with np.linalg.lstsq
1 parent 8e35312 commit bb86a53

File tree

2 files changed

+18
-29
lines changed

2 files changed

+18
-29
lines changed

pvlib/ivtools/sdm/pvsyst.py

Lines changed: 18 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -414,11 +414,6 @@ def fit_pvsyst_iec61853_sandia(effective_irradiance, temp_cell,
414414
of Photovoltaics, vol. 15, 3, 2025. :doi:`10.1109/JPHOTOV.2025.3554338`
415415
"""
416416

417-
try:
418-
import statsmodels.api as sm
419-
except ImportError:
420-
raise ImportError('fit_pvsyst_iec61853_sandia requires statsmodels')
421-
422417
is_g_stc = np.isclose(effective_irradiance, 1000, rtol=0,
423418
atol=irradiance_tolerance)
424419
is_t_stc = np.isclose(temp_cell, 25, rtol=0,
@@ -440,11 +435,10 @@ def fit_pvsyst_iec61853_sandia(effective_irradiance, temp_cell,
440435
)
441436

442437
if R_s is None:
443-
R_s = _fit_series_resistance_pvsyst_iec61853_sandia(sm, v_oc,
444-
i_mp, v_mp)
438+
R_s = _fit_series_resistance_pvsyst_iec61853_sandia(v_oc, i_mp, v_mp)
445439

446440
gamma_ref, mu_gamma = _fit_diode_ideality_factor_pvsyst_iec61853_sandia(
447-
sm, i_sc[is_t_stc], v_oc[is_t_stc], i_mp[is_t_stc], v_mp[is_t_stc],
441+
i_sc[is_t_stc], v_oc[is_t_stc], i_mp[is_t_stc], v_mp[is_t_stc],
448442
effective_irradiance[is_t_stc], temp_cell[is_t_stc],
449443
R_sh_ref, R_sh_0, R_sh_exp, R_s, cells_in_series
450444
)
@@ -455,14 +449,14 @@ def fit_pvsyst_iec61853_sandia(effective_irradiance, temp_cell,
455449
)
456450

457451
I_L_ref = _fit_photocurrent_pvsyst_iec61853_sandia(
458-
sm, i_sc, effective_irradiance, temp_cell, alpha_sc,
452+
i_sc, effective_irradiance, temp_cell, alpha_sc,
459453
gamma_ref, mu_gamma,
460454
I_o_ref, R_sh_ref, R_sh_0, R_sh_exp, R_s, cells_in_series, EgRef
461455
)
462456

463457
gamma_ref, mu_gamma = \
464458
_fit_diode_ideality_factor_post_pvsyst_iec61853_sandia(
465-
sm, i_mp, v_mp, effective_irradiance, temp_cell, alpha_sc, I_L_ref,
459+
i_mp, v_mp, effective_irradiance, temp_cell, alpha_sc, I_L_ref,
466460
I_o_ref, R_sh_ref, R_sh_0, R_sh_exp, R_s, cells_in_series, EgRef)
467461

468462
fitted_params = dict(
@@ -524,21 +518,20 @@ def _fit_shunt_resistances_pvsyst_iec61853_sandia(
524518
return Rshref, Rsh0, Rshexp
525519

526520

527-
def _fit_series_resistance_pvsyst_iec61853_sandia(sm, v_oc, i_mp, v_mp):
521+
def _fit_series_resistance_pvsyst_iec61853_sandia(v_oc, i_mp, v_mp):
528522
# Stein et al 2014, https://doi.org/10.1109/PVSC.2014.6925326
529523

530524
# Eq 13
531-
x = np.array([i_mp, np.log(i_mp), v_mp]).T
532-
x = sm.add_constant(x)
525+
x = np.array([np.ones(len(i_mp)), i_mp, np.log(i_mp), v_mp]).T
533526
y = v_oc
534527

535-
results = sm.OLS(endog=y, exog=x).fit()
536-
R_s = results.params['x1']
528+
coeff, _, _, _ = np.linalg.lstsq(x, y, rcond=None)
529+
R_s = coeff[1]
537530
return R_s
538531

539532

540533
def _fit_diode_ideality_factor_pvsyst_iec61853_sandia(
541-
sm, i_sc, v_oc, i_mp, v_mp, effective_irradiance, temp_cell,
534+
i_sc, v_oc, i_mp, v_mp, effective_irradiance, temp_cell,
542535
R_sh_ref, R_sh_0, R_sh_exp, R_s, cells_in_series):
543536

544537
NsVth = _pvsyst_nNsVth(temp_cell, gamma=1, cells_in_series=cells_in_series)
@@ -552,8 +545,8 @@ def _fit_diode_ideality_factor_pvsyst_iec61853_sandia(
552545
x = np.array([x1]).T
553546
y = v_mp + i_mp*R_s - v_oc
554547

555-
results = sm.OLS(endog=y, exog=x).fit()
556-
gamma_ref = results.params['x1']
548+
coeff, _, _, _ = np.linalg.lstsq(x, y, rcond=None)
549+
gamma_ref = coeff[0]
557550
return gamma_ref, 0
558551

559552

@@ -576,7 +569,7 @@ def _fit_saturation_current_pvsyst_iec61853_sandia(
576569

577570

578571
def _fit_photocurrent_pvsyst_iec61853_sandia(
579-
sm, i_sc, effective_irradiance, temp_cell, alpha_sc, gamma_ref,
572+
i_sc, effective_irradiance, temp_cell, alpha_sc, gamma_ref,
580573
mu_gamma, I_o_ref, R_sh_ref, R_sh_0, R_sh_exp, R_s, cells_in_series,
581574
EgRef):
582575
R_sh = _pvsyst_Rsh(effective_irradiance, R_sh_ref, R_sh_0, R_sh_exp)
@@ -590,13 +583,13 @@ def _fit_photocurrent_pvsyst_iec61853_sandia(
590583
# Eq 20
591584
x = np.array([effective_irradiance / 1000]).T
592585
y = I_L_est - effective_irradiance / 1000 * alpha_sc * (temp_cell - 25)
593-
results = sm.OLS(endog=y, exog=x).fit()
594-
I_L_ref = results.params['x1']
586+
coeff, _, _, _ = np.linalg.lstsq(x, y, rcond=None)
587+
I_L_ref = coeff[0]
595588
return I_L_ref
596589

597590

598591
def _fit_diode_ideality_factor_post_pvsyst_iec61853_sandia(
599-
sm, i_mp, v_mp, effective_irradiance, temp_cell, alpha_sc, I_L_ref,
592+
i_mp, v_mp, effective_irradiance, temp_cell, alpha_sc, I_L_ref,
600593
I_o_ref, R_sh_ref, R_sh_0, R_sh_exp, R_s, cells_in_series, EgRef):
601594

602595
Rsh = _pvsyst_Rsh(effective_irradiance, R_sh_ref, R_sh_0, R_sh_exp)
@@ -620,10 +613,9 @@ def _fit_diode_ideality_factor_post_pvsyst_iec61853_sandia(
620613
gamma_est = numerator / denominator
621614

622615
# Eq 22
623-
x = np.array([temp_cell - 25]).T
624-
x = sm.add_constant(x)
616+
x = np.array([np.ones(len(i_mp)), temp_cell - 25]).T
625617
y = gamma_est
626618

627-
results = sm.OLS(endog=y, exog=x).fit()
628-
gamma_ref, mu_gamma = results.params
619+
coeff, _, _, _ = np.linalg.lstsq(x, y, rcond=None)
620+
gamma_ref, mu_gamma = coeff
629621
return gamma_ref, mu_gamma

tests/ivtools/sdm/test_pvsyst.py

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -238,7 +238,6 @@ def iec61853_conditions():
238238
return ee, tc
239239

240240

241-
@requires_statsmodels
242241
def test_fit_pvsyst_iec61853_sandia(pvsyst_iec61853_table3,
243242
iec61853_conditions):
244243
ee, tc = iec61853_conditions
@@ -258,7 +257,6 @@ def test_fit_pvsyst_iec61853_sandia(pvsyst_iec61853_table3,
258257
atol=0, rtol=1e-3)
259258

260259

261-
@requires_statsmodels
262260
def test_fit_pvsyst_iec61853_sandia_optional(pvsyst_iec61853_table3,
263261
iec61853_conditions):
264262
# verify that modifying each optional parameter results in different output
@@ -306,7 +304,6 @@ def test_fit_pvsyst_iec61853_sandia_optional(pvsyst_iec61853_table3,
306304
atol=0, rtol=1e-3)
307305

308306

309-
@requires_statsmodels
310307
def test_fit_pvsyst_iec61853_sandia_tolerance(pvsyst_iec61853_table3,
311308
iec61853_conditions):
312309
# verify that the *_tolerance parameters allow non-"perfect" irradiance

0 commit comments

Comments
 (0)