Skip to content

implement multi-MPPT inverter model #1085

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

Merged
merged 22 commits into from
Dec 2, 2020
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
102 changes: 88 additions & 14 deletions pvlib/inverter.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,34 @@
from numpy.polynomial.polynomial import polyfit # different than np.polyfit


def _sandia_eff(v_dc, p_dc, inverter):
r'''
Calculate the inverter AC power without clipping
'''
Paco = inverter['Paco']
Pdco = inverter['Pdco']
Vdco = inverter['Vdco']
C0 = inverter['C0']
C1 = inverter['C1']
C2 = inverter['C2']
C3 = inverter['C3']
Pso = inverter['Pso']

A = Pdco * (1 + C1 * (v_dc - Vdco))
B = Pso * (1 + C2 * (v_dc - Vdco))
C = C0 * (1 + C3 * (v_dc - Vdco))

return (Paco / (A - B) - C * (A - B)) * (p_dc - B) + C * (p_dc - B)**2


def _sandia_limits(power_ac, p_dc, Paco, Pnt, Pso):
r'''
Applies minimum and maximum power limits to `power_ac`
'''
power_ac = np.minimum(Paco, power_ac)
return np.where(p_dc < Pso, -1.0 * abs(Pnt), power_ac)


def sandia(v_dc, p_dc, inverter):
r'''
Convert DC power and voltage to AC power using Sandia's
Expand Down Expand Up @@ -91,29 +119,75 @@ def sandia(v_dc, p_dc, inverter):
'''

Paco = inverter['Paco']
Pdco = inverter['Pdco']
Vdco = inverter['Vdco']
Pso = inverter['Pso']
C0 = inverter['C0']
C1 = inverter['C1']
C2 = inverter['C2']
C3 = inverter['C3']
Pnt = inverter['Pnt']
Pso = inverter['Pso']

A = Pdco * (1 + C1 * (v_dc - Vdco))
B = Pso * (1 + C2 * (v_dc - Vdco))
C = C0 * (1 + C3 * (v_dc - Vdco))

power_ac = (Paco / (A - B) - C * (A - B)) * (p_dc - B) + C * (p_dc - B)**2
power_ac = np.minimum(Paco, power_ac)
power_ac = np.where(p_dc < Pso, -1.0 * abs(Pnt), power_ac)
power_ac = _sandia_eff(v_dc, p_dc, inverter)
power_ac = _sandia_limits(power_ac, p_dc, Paco, Pnt, Pso)

if isinstance(p_dc, pd.Series):
power_ac = pd.Series(power_ac, index=p_dc.index)

return power_ac


def sandia_multi(v_dc, p_dc, inverter, dc_limit=None):
r'''
Convert DC power and voltage to AC power for an inverter with multiple
MPPT inputs.

Uses Sandia's Grid-Connected PV Inverter model [1]_.

Parameters
----------
v_dc : tuple
DC voltage on each MPPT input of the inverter. [V]

p_dc : tuple
DC power on each MPPT input of the inverter. [W]

inverter : dict-like
Defines parameters for the inverter model in [1]_.

dc_limit : float, default None
Limit applied to DC power on a MPPT input. If None,
then dc_limit is set equal to inverter['Paco']. [W]

Returns
-------
power_ac : numeric
AC power output for the inverter. [W]

Notes
-----

See :py:func:`pvlib.inverter.sandia` for definition of the parameters in
`inverter`.

References
----------
.. [1] D. King, S. Gonzalez, G. Galbraith, W. Boyson, "Performance Model
for Grid-Connected Photovoltaic Inverters", SAND2007-5036, Sandia
National Laboratories.

See also
--------
pvlib.inverter.sandia
'''
if dc_limit is None:
dc_limit = inverter['Paco']

power_ac = np.zeros_like(p_dc[0])
power_dc = np.zeros_like(p_dc[0])
for pdc in p_dc:
power_dc += pdc

for vdc, pdc in zip(v_dc, p_dc):
f = pdc / power_dc
power_ac += np.minimum(f * sandia(vdc, power_dc, inverter), dc_limit)
return power_ac


def adr(v_dc, p_dc, inverter, vtol=0.10):
r'''
Converts DC power and voltage to AC power using Anton Driesse's
Expand Down
21 changes: 21 additions & 0 deletions pvlib/tests/test_inverter.py
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,27 @@ def test_sandia_Pnt_micro():
assert_series_equal(pacs, pd.Series([-0.043, 132.545914746, 240.0]))


def test_sandia_multi(cec_inverter_parameters):
vdcs = pd.Series(np.linspace(0, 50, 3))
idcs = pd.Series(np.linspace(0, 11, 3)) / 2
pdcs = idcs * vdcs

pacs = inverter.sandia_multi((vdcs, vdcs), (pdcs, pdcs),
cec_inverter_parameters)
assert_series_equal(pacs, pd.Series([-0.020000, 132.004308, 250.000000]))


def test_sandia_multi_dc_limit(cec_inverter_parameters):
vdcs = pd.Series(np.linspace(0, 50, 3))
idcs = pd.Series(np.linspace(0, 11, 3)) / 2
pdcs = idcs * vdcs

pacs = inverter.sandia_multi((vdcs, vdcs), (pdcs, pdcs),
cec_inverter_parameters, dc_limit=50)
assert_series_equal(2 * pacs, pd.Series([-0.020000, 2 * 47.05127939,
2 * 47.01461547]))


def test_pvwatts_scalars():
expected = 85.58556604752516
out = inverter.pvwatts(90, 100, 0.95)
Expand Down