|
12 | 12 |
|
13 | 13 | import numpy as np
|
14 | 14 | import pandas as pd
|
15 |
| - |
16 | 15 | from numpy.polynomial.polynomial import polyfit # different than np.polyfit
|
17 | 16 |
|
18 | 17 |
|
| 18 | +def _sandia_eff(v_dc, p_dc, inverter): |
| 19 | + r''' |
| 20 | + Calculate the inverter AC power without clipping |
| 21 | + ''' |
| 22 | + Paco = inverter['Paco'] |
| 23 | + Pdco = inverter['Pdco'] |
| 24 | + Vdco = inverter['Vdco'] |
| 25 | + C0 = inverter['C0'] |
| 26 | + C1 = inverter['C1'] |
| 27 | + C2 = inverter['C2'] |
| 28 | + C3 = inverter['C3'] |
| 29 | + Pso = inverter['Pso'] |
| 30 | + |
| 31 | + A = Pdco * (1 + C1 * (v_dc - Vdco)) |
| 32 | + B = Pso * (1 + C2 * (v_dc - Vdco)) |
| 33 | + C = C0 * (1 + C3 * (v_dc - Vdco)) |
| 34 | + |
| 35 | + return (Paco / (A - B) - C * (A - B)) * (p_dc - B) + C * (p_dc - B)**2 |
| 36 | + |
| 37 | + |
| 38 | +def _sandia_limits(power_ac, p_dc, Paco, Pnt, Pso): |
| 39 | + r''' |
| 40 | + Applies minimum and maximum power limits to `power_ac` |
| 41 | + ''' |
| 42 | + power_ac = np.minimum(Paco, power_ac) |
| 43 | + min_ac_power = -1.0 * abs(Pnt) |
| 44 | + below_limit = p_dc < Pso |
| 45 | + try: |
| 46 | + power_ac[below_limit] = min_ac_power |
| 47 | + except TypeError: # power_ac is a float |
| 48 | + if below_limit: |
| 49 | + power_ac = min_ac_power |
| 50 | + return power_ac |
| 51 | + |
| 52 | + |
19 | 53 | def sandia(v_dc, p_dc, inverter):
|
20 | 54 | r'''
|
21 | 55 | Convert DC power and voltage to AC power using Sandia's
|
@@ -54,10 +88,10 @@ def sandia(v_dc, p_dc, inverter):
|
54 | 88 | Column Description
|
55 | 89 | ====== ============================================================
|
56 | 90 | Paco AC power rating of the inverter. [W]
|
57 |
| - Pdco DC power input to inverter, typically assumed to be equal |
58 |
| - to the PV array maximum power. [W] |
| 91 | + Pdco DC power input that results in Paco output at reference |
| 92 | + voltage Vdco. [W] |
59 | 93 | Vdco DC voltage at which the AC power rating is achieved
|
60 |
| - at the reference operating condition. [V] |
| 94 | + with Pdco power input. [V] |
61 | 95 | Pso DC power required to start the inversion process, or
|
62 | 96 | self-consumption by inverter, strongly influences inverter
|
63 | 97 | efficiency at low power levels. [W]
|
@@ -91,29 +125,76 @@ def sandia(v_dc, p_dc, inverter):
|
91 | 125 | '''
|
92 | 126 |
|
93 | 127 | Paco = inverter['Paco']
|
94 |
| - Pdco = inverter['Pdco'] |
95 |
| - Vdco = inverter['Vdco'] |
96 |
| - Pso = inverter['Pso'] |
97 |
| - C0 = inverter['C0'] |
98 |
| - C1 = inverter['C1'] |
99 |
| - C2 = inverter['C2'] |
100 |
| - C3 = inverter['C3'] |
101 | 128 | Pnt = inverter['Pnt']
|
| 129 | + Pso = inverter['Pso'] |
102 | 130 |
|
103 |
| - A = Pdco * (1 + C1 * (v_dc - Vdco)) |
104 |
| - B = Pso * (1 + C2 * (v_dc - Vdco)) |
105 |
| - C = C0 * (1 + C3 * (v_dc - Vdco)) |
106 |
| - |
107 |
| - power_ac = (Paco / (A - B) - C * (A - B)) * (p_dc - B) + C * (p_dc - B)**2 |
108 |
| - power_ac = np.minimum(Paco, power_ac) |
109 |
| - power_ac = np.where(p_dc < Pso, -1.0 * abs(Pnt), power_ac) |
| 131 | + power_ac = _sandia_eff(v_dc, p_dc, inverter) |
| 132 | + power_ac = _sandia_limits(power_ac, p_dc, Paco, Pnt, Pso) |
110 | 133 |
|
111 | 134 | if isinstance(p_dc, pd.Series):
|
112 | 135 | power_ac = pd.Series(power_ac, index=p_dc.index)
|
113 | 136 |
|
114 | 137 | return power_ac
|
115 | 138 |
|
116 | 139 |
|
| 140 | +def sandia_multi(v_dc, p_dc, inverter): |
| 141 | + r''' |
| 142 | + Convert DC power and voltage to AC power for an inverter with multiple |
| 143 | + MPPT inputs. |
| 144 | +
|
| 145 | + Uses Sandia's Grid-Connected PV Inverter model [1]_. |
| 146 | +
|
| 147 | + Parameters |
| 148 | + ---------- |
| 149 | + v_dc : tuple, list or array of numeric |
| 150 | + DC voltage on each MPPT input of the inverter. If type is array, must |
| 151 | + be 2d with axis 0 being the MPPT inputs. [V] |
| 152 | +
|
| 153 | + p_dc : tuple, list or array of numeric |
| 154 | + DC power on each MPPT input of the inverter. If type is array, must |
| 155 | + be 2d with axis 0 being the MPPT inputs. [W] |
| 156 | +
|
| 157 | + inverter : dict-like |
| 158 | + Defines parameters for the inverter model in [1]_. |
| 159 | +
|
| 160 | + Returns |
| 161 | + ------- |
| 162 | + power_ac : numeric |
| 163 | + AC power output for the inverter. [W] |
| 164 | +
|
| 165 | + Raises |
| 166 | + ------ |
| 167 | + ValueError |
| 168 | + If v_dc and p_dc have different lengths. |
| 169 | +
|
| 170 | + Notes |
| 171 | + ----- |
| 172 | + See :py:func:`pvlib.inverter.sandia` for definition of the parameters in |
| 173 | + `inverter`. |
| 174 | +
|
| 175 | + References |
| 176 | + ---------- |
| 177 | + .. [1] D. King, S. Gonzalez, G. Galbraith, W. Boyson, "Performance Model |
| 178 | + for Grid-Connected Photovoltaic Inverters", SAND2007-5036, Sandia |
| 179 | + National Laboratories. |
| 180 | +
|
| 181 | + See also |
| 182 | + -------- |
| 183 | + pvlib.inverter.sandia |
| 184 | + ''' |
| 185 | + |
| 186 | + if len(p_dc) != len(v_dc): |
| 187 | + raise ValueError('p_dc and v_dc have different lengths') |
| 188 | + power_dc = sum(p_dc) |
| 189 | + power_ac = 0. * power_dc |
| 190 | + |
| 191 | + for vdc, pdc in zip(v_dc, p_dc): |
| 192 | + power_ac += pdc / power_dc * _sandia_eff(vdc, power_dc, inverter) |
| 193 | + |
| 194 | + return _sandia_limits(power_ac, power_dc, inverter['Paco'], |
| 195 | + inverter['Pnt'], inverter['Pso']) |
| 196 | + |
| 197 | + |
117 | 198 | def adr(v_dc, p_dc, inverter, vtol=0.10):
|
118 | 199 | r'''
|
119 | 200 | Converts DC power and voltage to AC power using Anton Driesse's
|
|
0 commit comments