Skip to content

Commit e881ce7

Browse files
Improve solver, streamline, and add tests
1 parent 4859d64 commit e881ce7

File tree

2 files changed

+98
-39
lines changed

2 files changed

+98
-39
lines changed

pvlib/pvsystem.py

Lines changed: 37 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -3040,48 +3040,39 @@ def max_power_point_mismatched(
30403040
resistance_series,
30413041
resistance_shunt,
30423042
nNsVth,
3043+
*,
3044+
i_mp_ic=None,
30433045
):
30443046
"""
30453047
Compute maximum power info for (possibly) mismatched set of devices in
3046-
series.
3048+
series. When using this serially on time-series data, passing i_mp_ic from
3049+
previous step may speed up computation. Algorithm falls back to automated
3050+
computation of i_mp_ic if solution fails with provided i_mp_ic. The value
3051+
of i_mp_ic used is returned along with i_mp (same value for all devices),
3052+
v_mp, and p_mp.
30473053
"""
3048-
if all(
3049-
[
3050-
isinstance(input, numbers.Number) for input in (
3051-
photocurrent,
3052-
saturation_current,
3053-
resistance_series,
3054-
resistance_shunt,
3055-
nNsVth,
3056-
)
3057-
]
3058-
):
3059-
# There cannot be mismatch, so fall back to non-mismatch function.
3060-
return {
3061-
**max_power_point(
3062-
photocurrent,
3063-
saturation_current,
3064-
resistance_series,
3065-
resistance_shunt,
3066-
nNsVth
3067-
)
3068-
}
3054+
if i_mp_ic is None:
3055+
i_mp_ic = max_power_point(
3056+
np.mean(photocurrent),
3057+
np.mean(saturation_current),
3058+
np.mean(resistance_series),
3059+
np.mean(resistance_shunt),
3060+
np.mean(nNsVth),
3061+
)["i_mp"]
3062+
retry_ic = False
3063+
else:
3064+
retry_ic = True
30693065

3070-
i_mp_0 = max_power_point(
3071-
np.mean(photocurrent),
3072-
np.mean(saturation_current),
3073-
np.mean(resistance_series),
3074-
np.mean(resistance_shunt),
3075-
np.mean(nNsVth),
3076-
)["i_mp"]
30773066
args = (
30783067
photocurrent,
30793068
saturation_current,
30803069
resistance_series,
30813070
resistance_shunt,
30823071
nNsVth,
30833072
)
3084-
sol = scipy.optimize.minimize(_negative_total_power, i_mp_0, args)
3073+
sol = scipy.optimize.minimize(
3074+
_negative_total_power, i_mp_ic, args=args, jac='3-point'
3075+
)
30853076

30863077
if sol.success:
30873078
i_mp = sol.x[0]
@@ -3095,9 +3086,25 @@ def max_power_point_mismatched(
30953086
)
30963087

30973088
return {
3089+
"i_mp_ic": i_mp_ic,
30983090
"i_mp": i_mp,
30993091
"v_mp": v_mp,
31003092
"p_mp": i_mp * v_mp,
3093+
"i_mp_string": i_mp,
3094+
"v_mp_string": np.sum(v_mp),
3095+
"p_mp_string": -sol.fun,
31013096
}
31023097

3098+
if retry_ic:
3099+
# Try solution one more time using automated inital condition.
3100+
# Caller can detect this occurance by seeing change in i_mp_ic in
3101+
# return value.
3102+
return max_power_point_mismatched(
3103+
photocurrent,
3104+
saturation_current,
3105+
resistance_series,
3106+
resistance_shunt,
3107+
nNsVth,
3108+
)
3109+
31033110
raise RuntimeError(f"unsuccessful solution: {sol}")

pvlib/tests/test_pvsystem.py

Lines changed: 61 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2564,6 +2564,35 @@ def test_Array_temperature_missing_parameters(model, keys):
25642564
"Ns": 60,
25652565
"T": 25.0,
25662566
},
2567+
{
2568+
"photocurrent": 6.2,
2569+
"saturation_current": 1.0e-8,
2570+
"n": 1.1,
2571+
"resistance_series": 0.0001,
2572+
"resistance_shunt": 5000.0,
2573+
"Ns": 60,
2574+
"T": 25.0,
2575+
"i_mp_ic": 5.8,
2576+
},
2577+
{
2578+
"photocurrent": np.array([5.8, 6.2]),
2579+
"saturation_current": 1.0e-8,
2580+
"n": 1.1,
2581+
"resistance_series": 0.0001,
2582+
"resistance_shunt": 5000.0,
2583+
"Ns": 60,
2584+
"T": 25.0,
2585+
},
2586+
{
2587+
"photocurrent": np.array([5.8, 6.2]),
2588+
"saturation_current": 1.0e-8,
2589+
"n": 1.1,
2590+
"resistance_series": 0.0001,
2591+
"resistance_shunt": 5000.0,
2592+
"Ns": 60,
2593+
"T": 25.0,
2594+
"i_mp_ic": None,
2595+
},
25672596
{
25682597
"photocurrent": np.array([5.8, 6.2]),
25692598
"saturation_current": 1.0e-8,
@@ -2572,11 +2601,22 @@ def test_Array_temperature_missing_parameters(model, keys):
25722601
"resistance_shunt": 5000.0,
25732602
"Ns": 60,
25742603
"T": 25.0,
2575-
}
2604+
"i_mp_ic": -1.0e14,
2605+
},
2606+
{
2607+
"photocurrent": np.array([5.8, 6.2]),
2608+
"saturation_current": 1.0e-8,
2609+
"n": 1.1,
2610+
"resistance_series": 0.0001,
2611+
"resistance_shunt": 5000.0,
2612+
"Ns": 60,
2613+
"T": 25.0,
2614+
"i_mp_ic": 5.6,
2615+
},
25762616
]
25772617
)
25782618
def test_max_power_point_mismatched(inputs):
2579-
"""Test max power point computaiton for mismatched devices in series."""
2619+
"""Test max power point computation for mismatched devices in series."""
25802620

25812621
photocurrent = inputs["photocurrent"]
25822622
saturation_current = inputs["saturation_current"]
@@ -2587,10 +2627,22 @@ def test_max_power_point_mismatched(inputs):
25872627
T_K = scipy.constants.convert_temperature(inputs["T"], "Celsius", "Kelvin")
25882628
nNsVth = inputs["n"] * inputs["Ns"] * k_B_J_per_K * T_K / q_C
25892629

2590-
pvsystem.max_power_point_mismatched(
2591-
photocurrent,
2592-
saturation_current,
2593-
resistance_series,
2594-
resistance_shunt,
2595-
nNsVth,
2596-
)
2630+
if "i_mp_ic" in inputs:
2631+
result = pvsystem.max_power_point_mismatched(
2632+
photocurrent,
2633+
saturation_current,
2634+
resistance_series,
2635+
resistance_shunt,
2636+
nNsVth,
2637+
i_mp_ic=inputs["i_mp_ic"],
2638+
)
2639+
else:
2640+
result = pvsystem.max_power_point_mismatched(
2641+
photocurrent,
2642+
saturation_current,
2643+
resistance_series,
2644+
resistance_shunt,
2645+
nNsVth,
2646+
)
2647+
2648+
print(result)

0 commit comments

Comments
 (0)