-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Add function to fit Sandia inverter model #1011
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
Changes from 15 commits
7de7a77
31f0407
4426306
0391eb0
e7c1594
c38679f
b67766d
c0f96dd
3b37893
ae4380f
ecce111
303ab1c
768d39d
e8662fb
a9bd4bf
de6916c
3d38e6c
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,127 @@ | ||
fraction_of_rated_power,dc_voltage_level,ac_power,dc_voltage,efficiency | ||
0.1,Vmin,32800,660.5,0.95814 | ||
0.2,Vmin,73000,660.9,0.9755 | ||
0.3,Vmin,107500,660.73,0.97787 | ||
0.5,Vmin,168100,660.1,0.97998 | ||
0.75,Vmin,235467,660.27,0.97785 | ||
1,Vmin,318067,660.03,0.97258 | ||
0.1,Vnom,32800,740.1,0.95441 | ||
0.2,Vnom,72900,740.2,0.96985 | ||
0.3,Vnom,107600,740.13,0.97611 | ||
0.5,Vnom,167500,740.57,0.97554 | ||
0.75,Vnom,234967,741.87,0.97429 | ||
1,Vnom,317267,737.7,0.97261 | ||
0.1,Vmax,32800,959.07,0.94165 | ||
0.2,Vmax,71600,959.43,0.95979 | ||
0.3,Vmax,107300,959.1,0.96551 | ||
0.5,Vmax,166700,959.5,0.96787 | ||
0.75,Vmax,234767,958.8,0.96612 | ||
1,Vmax,317467,957,0.96358 | ||
0.1,Vmin,32800,660.77,0.95721 | ||
0.2,Vmin,73000,660.77,0.97247 | ||
0.3,Vmin,107500,660.47,0.97668 | ||
0.5,Vmin,168100,660.23,0.98018 | ||
0.75,Vmin,235333.3333,660.3,0.97716 | ||
1,Vmin,317466.6667,659.8,0.97184 | ||
0.1,Vnom,32800,740.27,0.95534 | ||
0.2,Vnom,72900,740.27,0.97071 | ||
0.3,Vnom,107600,740.2,0.97523 | ||
0.5,Vnom,167500,740.8,0.97592 | ||
0.75,Vnom,234966.6667,741.67,0.97429 | ||
1,Vnom,317300,737.97,0.97252 | ||
0.1,Vmax,32800,959.23,0.93718 | ||
0.2,Vmax,71600,959.4,0.96107 | ||
0.3,Vmax,107300,959.27,0.96638 | ||
0.5,Vmax,166700,959.57,0.96825 | ||
0.75,Vmax,234733.3333,959.17,0.96731 | ||
1,Vmax,317466.6667,957.07,0.96241 | ||
0.1,Vmin,32800,660.57,0.95814 | ||
0.2,Vmin,73000,660.67,0.97333 | ||
0.3,Vmin,107500,660.5,0.97609 | ||
0.5,Vmin,168100,660.1,0.97884 | ||
0.75,Vmin,235066.6667,660.3,0.97781 | ||
1,Vmin,316900,659.27,0.97209 | ||
0.1,Vnom,32800,740.17,0.95441 | ||
0.2,Vnom,72900,740.27,0.97028 | ||
0.3,Vnom,107600,740.23,0.97464 | ||
0.5,Vnom,167500,740.3,0.97573 | ||
0.75,Vnom,235133.3333,742.13,0.97417 | ||
1,Vnom,317300,737.9,0.97252 | ||
0.1,Vmax,32800,959.2,0.93626 | ||
0.2,Vmax,71600,959.43,0.95979 | ||
0.3,Vmax,107300,959.2,0.96493 | ||
0.5,Vmax,166700,959.5,0.96806 | ||
0.75,Vmax,234833.3333,958.97,0.96573 | ||
1,Vmax,317400,956.87,0.96279 | ||
0.1,Vmin,32800,660.63,0.95627 | ||
0.2,Vmin,73000,660.9,0.97377 | ||
0.3,Vmin,107500,661.07,0.97846 | ||
0.5,Vmin,168100,660.13,0.97827 | ||
0.75,Vmin,235200,660.43,0.97701 | ||
1,Vmin,316933.3333,660.07,0.97308 | ||
0.1,Vnom,32800,740.27,0.95441 | ||
0.2,Vnom,72900,740.37,0.96985 | ||
0.3,Vnom,107600,740.27,0.97464 | ||
0.5,Vnom,167500,740.53,0.97592 | ||
0.75,Vnom,234800,742.13,0.97374 | ||
1,Vnom,317300,737.73,0.97202 | ||
0.1,Vmax,32800,959.2,0.93271 | ||
0.2,Vmax,71600,959.27,0.95594 | ||
0.3,Vmax,107300,959.2,0.96783 | ||
0.5,Vmax,166700,959.47,0.96806 | ||
0.75,Vmax,234700,958.67,0.96505 | ||
1,Vmax,317433.3333,956.8,0.96299 | ||
0.1,Vmin,32800,660.67,0.95534 | ||
0.2,Vmin,73000,660.8,0.9755 | ||
0.3,Vmin,107500,661.23,0.97905 | ||
0.5,Vmin,168100,660.33,0.97941 | ||
0.75,Vmin,236566.6667,660.43,0.97741 | ||
1,Vmin,317866.6667,659.53,0.97366 | ||
0.1,Vnom,32800,740.13,0.95627 | ||
0.2,Vnom,72900,740.37,0.97071 | ||
0.3,Vnom,107600,740.4,0.97523 | ||
0.5,Vnom,167500,740.57,0.97649 | ||
0.75,Vnom,234733.3333,741.83,0.97413 | ||
1,Vnom,317333.3333,737.77,0.97222 | ||
0.1,Vmax,32800,959.03,0.9336 | ||
0.2,Vmax,71600,959.33,0.96108 | ||
0.3,Vmax,107300,959.2,0.96464 | ||
0.5,Vmax,166700,959.57,0.96975 | ||
0.75,Vmax,234700,958.83,0.96584 | ||
1,Vmax,317400,956.7,0.96338 | ||
0.1,Vmin,32800,660.43,0.95349 | ||
0.2,Vmin,73000,660.83,0.97247 | ||
0.3,Vmin,107500,660.47,0.97668 | ||
0.5,Vmin,168100,660.27,0.97941 | ||
0.75,Vmin,236167,660.57,0.97657 | ||
1,Vmin,317833,660.47,0.97177 | ||
0.1,Vnom,32800,740.2,0.95534 | ||
0.2,Vnom,72900,740.3,0.96985 | ||
0.3,Vnom,107600,740.33,0.97434 | ||
0.5,Vnom,167500,740.53,0.9763 | ||
0.75,Vnom,234833,741.93,0.97468 | ||
1,Vnom,317333,737.73,0.97242 | ||
0.1,Vmax,32800,959.03,0.93626 | ||
0.2,Vmax,71600,959.37,0.95936 | ||
0.3,Vmax,107300,959.23,0.96464 | ||
0.5,Vmax,166700,959.5,0.96731 | ||
0.75,Vmax,235267,958.67,0.96592 | ||
1,Vmax,317400,957.07,0.96269 | ||
0.1,Vmin,32800,660.73,0.95627 | ||
0.2,Vmin,73000,660.57,0.97204 | ||
0.3,Vmin,107500,660.97,0.97787 | ||
0.5,Vmin,168100,660,0.97865 | ||
0.75,Vmin,236200,659.77,0.97778 | ||
1,Vmin,317200,659.2,0.97221 | ||
0.1,Vnom,32800,740.2,0.95257 | ||
0.2,Vnom,72900,740.33,0.97071 | ||
0.3,Vnom,107600,740.43,0.97464 | ||
0.5,Vnom,167500,740.63,0.97592 | ||
0.75,Vnom,235100,741.87,0.97458 | ||
1,Vnom,317333.3333,737.83,0.97232 | ||
0.1,Vmax,32800,959,0.93182 | ||
0.2,Vmax,71600,959.4,0.9585 | ||
0.3,Vmax,107300,959.07,0.96783 | ||
0.5,Vmax,166700,959.7,0.96806 | ||
0.75,Vmax,235466.6667,958.77,0.96569 | ||
1,Vmax,317400,956.6,0.96308 |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
fraction_of_rated_power,efficiency,dc_voltage_level,dc_voltage,dc_power,ac_power,efficiency | ||
0.1,0.892146066,Vmin,220,112.0892685,100,0.892146067 | ||
0.1,0.876414009,Vnom,240,114.1013254,100,0.876414009 | ||
0.1,0.861227164,Vmax,260,116.1133835,100,0.861227164 | ||
0.2,0.925255801,Vmin,220,216.15644,200,0.925255801 | ||
0.2,0.916673906,Vnom,240,218.1800951,200,0.916673906 | ||
0.2,0.908249736,Vmax,260,220.2037524,200,0.908249736 | ||
0.3,0.936909957,Vmin,220,320.2015283,300,0.936909957 | ||
0.3,0.93099374,Vnom,240,322.2363236,300,0.93099374 | ||
0.3,0.925151763,Vmax,260,324.2711217,300,0.925151763 | ||
0.5,0.946565413,Vmin,220,528.2255121,500,0.946565413 | ||
0.5,0.94289593,Vnom,240,530.2812159,500,0.94289593 | ||
0.5,0.939254781,Vmax,260,532.336923,500,0.939254781 | ||
0.75,0.951617818,Vmin,220,788.1315225,750,0.951617818 | ||
0.75,0.949113828,Vnom,240,790.2108027,750,0.949113828 | ||
0.75,0.946622992,Vmax,260,792.2900736,750,0.946622992 | ||
1,0.954289529,Vmin,220,1047.900002,1000,0.95428953 | ||
1,0.952380952,Vnom,240,1050,1000,0.952380952 | ||
1,0.950479992,Vmax,260,1052.1,1000,0.950479992 |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,12 +1,21 @@ | ||
# -*- coding: utf-8 -*- | ||
""" | ||
This module contains functions for inverter modeling, primarily conversion of | ||
DC to AC power. | ||
This module contains functions for inverter modeling and for fitting inverter | ||
models to data. | ||
|
||
Inverter models calculate AC power output from DC input. Model parameters | ||
should be passed as a single dict. | ||
|
||
Functions for estimating parameters for inverter models should follow the | ||
naming pattern 'fit_<model name>', e.g., fit_sandia. | ||
|
||
""" | ||
|
||
import numpy as np | ||
import pandas as pd | ||
|
||
from numpy.polynomial.polynomial import polyfit # different than np.polyfit | ||
|
||
|
||
def sandia(v_dc, p_dc, inverter): | ||
r''' | ||
|
@@ -306,3 +315,123 @@ def pvwatts(pdc, pdc0, eta_inv_nom=0.96, eta_inv_ref=0.9637): | |
power_ac = np.maximum(0, power_ac) # GH 541 | ||
|
||
return power_ac | ||
|
||
|
||
def fit_sandia(curves, p_ac_0, p_nt): | ||
r''' | ||
Determine parameters for the Sandia inverter model from efficiency | ||
curves. | ||
|
||
Parameters | ||
---------- | ||
curves : DataFrame | ||
Columns must be ``'fraction_of_rated_power'``, ``'dc_voltage_level'``, | ||
``'dc_voltage'``, ``'ac_power'``, ``'efficiency'``. See notes for the | ||
definition and unit for each column. | ||
p_ac_0 : numeric | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is it intentional that There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I agree, which would you prefer? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It's not clear to me where the balance should be struck between (1) presenting a consistent interface across functions or (2) maintaining as clear a connection as possible to the original model definitions. I think I would lean towards There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. That is my preference as well. The function returns a dict ready for |
||
Rated AC power of the inverter [W]. | ||
p_nt : numeric | ||
Night tare, i.e., power consumed while inverter is not delivering | ||
AC power. [W] | ||
|
||
Returns | ||
------- | ||
dict | ||
A set of parameters for the Sandia inverter model [1]_. See | ||
:py:func:`pvlib.inverter.sandia` for a description of keys and values. | ||
|
||
See Also | ||
-------- | ||
pvlib.inverter.sandia | ||
|
||
Notes | ||
----- | ||
An inverter efficiency curve at a specified DC voltage level and AC power | ||
level comprises a series of pairs ('fraction_of_rated_power', | ||
'efficiency'), e.g. (0.1, 0.5), (0.2, 0.7), etc. . The DataFrame | ||
`curves` must contain at least one efficiency curve for each combination | ||
of DC voltage level and AC power level. Columns in `curves` must be the | ||
following: | ||
|
||
========================= =============================================== | ||
Column name Description | ||
========================= =============================================== | ||
'fraction_of_rated_power' Fraction of rated AC power `p_ac_0`. The | ||
CEC inverter test protocol specifies values | ||
of 0.1, 0.2, 0.3, 0.5, 0.75 and 1.0. [unitless] | ||
'dc_voltage_level' Must be 'Vmin', 'Vnom', or 'Vmax'. Curves must | ||
be provided for all three voltage levels. At | ||
least one curve must be provided for each | ||
combination of fraction_of_rated_power and | ||
dc_voltage_level. | ||
'dc_voltage' DC input voltage. [V] | ||
'ac_power' Output AC power. [W] | ||
'efficiency' Ratio of AC output power to DC input power. | ||
[unitless] | ||
kandersolar marked this conversation as resolved.
Show resolved
Hide resolved
|
||
========================= =============================================== | ||
|
||
For each curve, DC input power is calculated from AC power and efficiency. | ||
The fitting procedure is described at [2]_. | ||
|
||
References | ||
---------- | ||
.. [1] SAND2007-5036, "Performance Model for Grid-Connected | ||
Photovoltaic Inverters by D. King, S. Gonzalez, G. Galbraith, W. | ||
Boyson | ||
.. [2] Sandia Inverter Model page, PV Performance Modeling Collaborative | ||
https://pvpmc.sandia.gov/modeling-steps/dc-to-ac-conversion/sandia-inverter-model/ | ||
''' # noqa: E501 | ||
|
||
voltage_levels = ['Vmin', 'Vnom', 'Vmax'] | ||
|
||
# average dc input voltage at each voltage level | ||
v_d = np.array( | ||
[curves['dc_voltage'][curves['dc_voltage_level'] == 'Vmin'].mean(), | ||
curves['dc_voltage'][curves['dc_voltage_level'] == 'Vnom'].mean(), | ||
curves['dc_voltage'][curves['dc_voltage_level'] == 'Vmax'].mean()]) | ||
v_nom = v_d[1] # model parameter | ||
# independent variable for regressions, x_d | ||
x_d = v_d - v_nom | ||
|
||
curves['dc_power'] = curves['ac_power'] / curves['efficiency'] | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Doesn't this modify the input DataFrame? |
||
|
||
# empty dataframe to contain intermediate variables | ||
coeffs = pd.DataFrame(index=voltage_levels, | ||
columns=['a', 'b', 'c', 'p_dc', 'p_s0'], data=np.nan) | ||
|
||
def solve_quad(a, b, c): | ||
return (-b + (b**2 - 4 * a * c)**.5) / (2 * a) | ||
kandersolar marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
# [2] STEP 3E, fit a line to (DC voltage, model_coefficient) | ||
def extract_c(x_d, add): | ||
beta0, beta1 = polyfit(x_d, add, 1) | ||
c = beta1 / beta0 | ||
return beta0, beta1, c | ||
|
||
for d in voltage_levels: | ||
x = curves['dc_power'][curves['dc_voltage_level'] == d] | ||
y = curves['ac_power'][curves['dc_voltage_level'] == d] | ||
# [2] STEP 3B | ||
# fit a quadratic to (DC power, AC power) | ||
c, b, a = polyfit(x, y, 2) | ||
|
||
# [2] STEP 3D, solve for p_dc and p_s0 | ||
p_dc = solve_quad(a, b, (c - p_ac_0)) | ||
p_s0 = solve_quad(a, b, c) | ||
|
||
# Add values to dataframe at index d | ||
coeffs['a'][d] = a | ||
coeffs['p_dc'][d] = p_dc | ||
coeffs['p_s0'][d] = p_s0 | ||
|
||
b_dc0, b_dc1, c1 = extract_c(x_d, coeffs['p_dc']) | ||
kandersolar marked this conversation as resolved.
Show resolved
Hide resolved
|
||
b_s0, b_s1, c2 = extract_c(x_d, coeffs['p_s0']) | ||
b_c0, b_c1, c3 = extract_c(x_d, coeffs['a']) | ||
|
||
p_dc0 = b_dc0 | ||
p_s0 = b_s0 | ||
c0 = b_c0 | ||
|
||
# prepare dict and return | ||
return {'Paco': p_ac_0, 'Pdco': p_dc0, 'Vdco': v_nom, 'Pso': p_s0, | ||
'C0': c0, 'C1': c1, 'C2': c2, 'C3': c3, 'Pnt': p_nt} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is
fraction_of_rated_power
actually required? I don't see it getting used anywhere.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The values are not used explicitly, but I think it would be confusing to describe the needed input without
fraction_of_rated_power
. If working from a datasheet, efficiency in usually given in terms offraction_of_rated_power
rather thanac_power
.