|
7 | 7 |
|
8 | 8 | from tests.conftest import requires_statsmodels, TESTS_DATA_DIR |
9 | 9 |
|
| 10 | +import pytest |
| 11 | + |
10 | 12 |
|
11 | 13 | def _read_iv_curves_for_test(datafile, npts): |
12 | 14 | """ read constants and npts IV curves from datafile """ |
@@ -198,3 +200,107 @@ def test_pvsyst_temperature_coeff(): |
198 | 200 | params['I_L_ref'], params['I_o_ref'], params['R_sh_ref'], |
199 | 201 | params['R_sh_0'], params['R_s'], params['cells_in_series']) |
200 | 202 | assert_allclose(gamma_pdc, expected, rtol=0.0005) |
| 203 | + |
| 204 | + |
| 205 | +@pytest.fixture |
| 206 | +def pvsyst_iec61853_table3(): |
| 207 | + # test cases in Table 3 of https://doi.org/10.1109/JPHOTOV.2025.3554338 |
| 208 | + parameters = ['alpha_sc', 'I_L_ref', 'I_o_ref', 'gamma_ref', 'mu_gamma', |
| 209 | + 'R_sh_ref', 'R_sh_0', 'R_sh_exp', 'R_s', 'cells_in_series', |
| 210 | + 'EgRef'] |
| 211 | + high_current = { |
| 212 | + 'true': [1e-3, 10, 1e-11, 1.0, -1e-4, 300, 1500, 5.5, 0.2, 60, 1.121], |
| 213 | + 'estimated': [9.993e-4, 9.997, 1.408e-10, 1.109, -1.666e-5, 543.7, |
| 214 | + 6130, 5.5, 0.176, 60, 1.121] |
| 215 | + } |
| 216 | + high_voltage = { |
| 217 | + 'true': [1e-3, 1.8, 1e-9, 1.5, 1e-4, 3000, 10000, 5.5, 5.0, 108, 1.4], |
| 218 | + 'estimated': [9.983e-4, 1.799, 1.225e-8, 1.706, 2.662e-4, 4288, 47560, |
| 219 | + 5.5, 4.292, 108, 1.4], |
| 220 | + } |
| 221 | + for d in [high_current, high_voltage]: |
| 222 | + for key in d: |
| 223 | + d[key] = dict(zip(parameters, np.array(d[key]))) |
| 224 | + |
| 225 | + return { |
| 226 | + 'high current': high_current, 'high voltage': high_voltage |
| 227 | + } |
| 228 | + |
| 229 | + |
| 230 | +@pytest.fixture |
| 231 | +def iec61853_conditions(): |
| 232 | + ee = np.array([100, 100, 200, 200, 400, 400, 400, 600, 600, 600, 600, |
| 233 | + 800, 800, 800, 800, 1000, 1000, 1000, 1000, 1100, 1100, |
| 234 | + 1100], dtype=np.float64) |
| 235 | + tc = np.array([15, 25, 15, 25, 15, 25, 50, 15, 25, 50, 75, |
| 236 | + 15, 25, 50, 75, 15, 25, 50, 75, 25, 50, 75], |
| 237 | + dtype=np.float64) |
| 238 | + return ee, tc |
| 239 | + |
| 240 | + |
| 241 | +@requires_statsmodels |
| 242 | +def test_fit_pvsyst_iec61853_sandia(pvsyst_iec61853_table3, |
| 243 | + iec61853_conditions): |
| 244 | + ee, tc = iec61853_conditions |
| 245 | + for _, case in pvsyst_iec61853_table3.items(): |
| 246 | + true_params = case['true'] |
| 247 | + expected_params = case['estimated'] |
| 248 | + |
| 249 | + sde_params = pvsystem.calcparams_pvsyst(ee, tc, **true_params) |
| 250 | + iv = pvsystem.singlediode(*sde_params) |
| 251 | + |
| 252 | + fitted_params = sdm.fit_pvsyst_iec61853_sandia( |
| 253 | + ee, tc, iv['i_sc'], iv['v_oc'], iv['i_mp'], iv['v_mp'], |
| 254 | + true_params['cells_in_series'], EgRef=true_params['EgRef'], |
| 255 | + ) |
| 256 | + for key in expected_params.keys(): |
| 257 | + assert np.isclose(fitted_params[key], expected_params[key], |
| 258 | + atol=0, rtol=1e-3) |
| 259 | + |
| 260 | + |
| 261 | +@requires_statsmodels |
| 262 | +def test_fit_pvsyst_iec61853_sandia_optional(pvsyst_iec61853_table3, |
| 263 | + iec61853_conditions): |
| 264 | + # verify that modifying each optional parameter results in different output |
| 265 | + ee, tc = iec61853_conditions |
| 266 | + case = pvsyst_iec61853_table3['high current'] |
| 267 | + true_params = case['true'] |
| 268 | + expected = case['estimated'] |
| 269 | + sde_params = pvsystem.calcparams_pvsyst(ee, tc, **true_params) |
| 270 | + iv = pvsystem.singlediode(*sde_params) |
| 271 | + |
| 272 | + main_inputs = dict( |
| 273 | + effective_irradiance=ee, temp_cell=tc, i_sc=iv['i_sc'], |
| 274 | + v_oc=iv['v_oc'], i_mp=iv['i_mp'], v_mp=iv['v_mp'], |
| 275 | + cells_in_series=true_params['cells_in_series'] |
| 276 | + ) |
| 277 | + |
| 278 | + fitted_params = sdm.fit_pvsyst_iec61853_sandia(**main_inputs, |
| 279 | + EgRef=1.0) |
| 280 | + assert not np.isclose(fitted_params['I_o_ref'], expected['I_o_ref'], |
| 281 | + atol=0, rtol=1e-3) |
| 282 | + |
| 283 | + fitted_params = sdm.fit_pvsyst_iec61853_sandia(**main_inputs, |
| 284 | + alpha_sc=0.5e-3) |
| 285 | + assert not np.isclose(fitted_params['alpha_sc'], expected['alpha_sc'], |
| 286 | + atol=0, rtol=1e-3) |
| 287 | + |
| 288 | + fitted_params = sdm.fit_pvsyst_iec61853_sandia(**main_inputs, |
| 289 | + beta_mp=-1e-4) |
| 290 | + assert not np.isclose(fitted_params['R_sh_ref'], expected['R_sh_ref'], |
| 291 | + atol=0, rtol=1e-3) |
| 292 | + |
| 293 | + fitted_params = sdm.fit_pvsyst_iec61853_sandia(**main_inputs, |
| 294 | + r_sh_coeff=0.3) |
| 295 | + assert not np.isclose(fitted_params['R_sh_ref'], expected['R_sh_ref'], |
| 296 | + atol=0, rtol=1e-3) |
| 297 | + |
| 298 | + fitted_params = sdm.fit_pvsyst_iec61853_sandia(**main_inputs, |
| 299 | + R_s=0.5) |
| 300 | + assert not np.isclose(fitted_params['R_s'], expected['R_s'], |
| 301 | + atol=0, rtol=1e-3) |
| 302 | + |
| 303 | + fitted_params = sdm.fit_pvsyst_iec61853_sandia(**main_inputs, |
| 304 | + min_Rsh_irradiance=500) |
| 305 | + assert not np.isclose(fitted_params['R_sh_ref'], expected['R_sh_ref'], |
| 306 | + atol=0, rtol=1e-3) |
0 commit comments