-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Implement calcparams_pvsyst and tests #486
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 11 commits
e20a079
e93cd8a
846c913
f457370
691a9a7
36d5941
131ff75
9d5d55e
d1be467
8d79f3d
34390a9
95bfde9
75e89f0
046a386
632ff87
1295bcf
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 |
---|---|---|
|
@@ -307,6 +307,36 @@ def calcparams_desoto(self, effective_irradiance, temp_cell, **kwargs): | |
|
||
return calcparams_desoto(effective_irradiance, temp_cell, **kwargs) | ||
|
||
def calcparams_pvsyst(self, effective_irradiance, temp_cell, **kwargs): | ||
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. similar to what was pointed out by @thunderfish24 in #478... the 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. done |
||
""" | ||
Use the :py:func:`calcparams_pvsyst` function, the input | ||
parameters and ``self.module_parameters`` to calculate the | ||
module currents and resistances. | ||
|
||
Parameters | ||
---------- | ||
effective_irradiance : numeric | ||
The irradiance (W/m2) that is converted to photocurrent. | ||
|
||
temp_cell : float or Series | ||
The average cell temperature of cells within a module in C. | ||
|
||
**kwargs | ||
See pvsystem.calcparams_pvsyst for details | ||
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. and delete 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. done |
||
|
||
Returns | ||
------- | ||
See pvsystem.calcparams_pvsyst for details | ||
""" | ||
|
||
kwargs = _build_kwargs(['gamma_ref', 'mugamma', 'I_L_ref', 'I_o_ref', | ||
'R_sh_ref', 'R_sh_0', 'R_sh_exp', | ||
'R_s', 'alpha_sc', 'EgRef', | ||
'cells_in_series'], | ||
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. should 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. done. I also added these keywords to |
||
self.module_parameters) | ||
|
||
return calcparams_pvsyst(effective_irradiance, temp_cell, **kwargs) | ||
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. This could be done in a separate issue (see #476), but I think the 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. We've chosen not to scale inside |
||
|
||
def sapm(self, effective_irradiance, temp_cell, **kwargs): | ||
""" | ||
Use the :py:func:`sapm` function, the input parameters, | ||
|
@@ -1011,28 +1041,21 @@ def calcparams_desoto(effective_irradiance, temp_cell, | |
Tuple of the following results: | ||
|
||
photocurrent : numeric | ||
Light-generated current in amperes at irradiance=S and | ||
cell temperature=Tcell. | ||
Light-generated current in amperes | ||
|
||
saturation_current : numeric | ||
Diode saturation curent in amperes at irradiance | ||
S and cell temperature Tcell. | ||
Diode saturation curent in amperes | ||
|
||
resistance_series : float | ||
Series resistance in ohms at irradiance S and cell temperature | ||
Tcell. | ||
Series resistance in ohms | ||
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. While passing through this territory, seems like this should be changed to "numeric" from "float". 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. Cut and paste inheritance? I don't think there is a difference here. 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'm good with float instead of numeric, because that seems to be most accurate. |
||
|
||
resistance_shunt : numeric | ||
Shunt resistance in ohms at irradiance S and cell temperature | ||
Tcell. | ||
Shunt resistance in ohms | ||
|
||
nNsVth : numeric | ||
Modified diode ideality factor at irradiance S and cell | ||
temperature Tcell. Note that in source [1] nNsVth = a (equation | ||
2). nNsVth is the product of the usual diode ideality factor | ||
(n), the number of series-connected cells in the module (Ns), | ||
and the thermal voltage of a cell in the module (Vth) at a cell | ||
temperature of Tcell. | ||
The product of the usual diode ideality factor (n, unitless), | ||
number of cells in series (Ns), and cell thermal voltage at | ||
specified effective irradiance and cell temperature. | ||
|
||
References | ||
---------- | ||
|
@@ -1051,8 +1074,6 @@ def calcparams_desoto(effective_irradiance, temp_cell, | |
|
||
See Also | ||
-------- | ||
sapm | ||
sapm_celltemp | ||
singlediode | ||
retrieve_sam | ||
|
||
|
@@ -1172,6 +1193,143 @@ def calcparams_desoto(effective_irradiance, temp_cell, | |
return IL, I0, Rs, Rsh, nNsVth | ||
|
||
|
||
def calcparams_pvsyst(effective_irradiance, temp_cell, | ||
alpha_sc, gamma_ref, mugamma, | ||
I_L_ref, I_o_ref, | ||
R_sh_ref, R_sh_0, R_s, | ||
cells_in_series, | ||
R_sh_exp=5.5, | ||
EgRef=1.121, | ||
irrad_ref=1000, temp_ref=25): | ||
''' | ||
Calculates five parameter values for the single diode equation at | ||
effective irradiance and cell temperature using the PVsyst v6 | ||
model described in [1,2,3]. The five values returned by calcparams_pvsyst | ||
can be used by singlediode to calculate an IV curve. | ||
|
||
Parameters | ||
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. What is the difference between numeric and float? Should a user NOT expect this function to be vectorized over the "float" parameters? 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'm pretty sure the function will work on array or Series inputs. Is the issue the type description We aren't using 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've used 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. for more context, note that some functions require "array-like" ( 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. So, 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. or unless there's a reason to specify 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 looked at both If we want to overhaul the docstrings, let's open a new issue for it. 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 think an issue is wise in order to define what we mean to ourselves/users and make everything consistent. |
||
---------- | ||
effective_irradiance : numeric | ||
The irradiance (W/m2) that is converted to photocurrent. | ||
|
||
temp_cell : numeric | ||
The average cell temperature of cells within a module in C. | ||
|
||
alpha_sc : float | ||
The short-circuit current temperature coefficient of the | ||
module in units of A/C. | ||
|
||
gamma_ref : float | ||
The diode ideality factor | ||
|
||
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. missing mugamma documentation here. mugamma or mu_gamma? 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. added. changed to 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 appears that the change was not applied here. |
||
mugamma : float | ||
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. Perhaps 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. yes |
||
The temperature coefficient for the diode ideality factor, 1/K | ||
|
||
I_L_ref : float | ||
The light-generated current (or photocurrent) at reference conditions, | ||
in amperes. | ||
|
||
I_o_ref : float | ||
The dark or diode reverse saturation current at reference conditions, | ||
in amperes. | ||
|
||
R_sh_ref : float | ||
The shunt resistance at reference conditions, in ohms. | ||
|
||
R_sh_0 : float | ||
The shunt resistance at zero irradiance conditions, in ohms. | ||
|
||
R_s : float | ||
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. R_s_ref seems more consistent with other variables at reference conditions. 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. But here we run into an unfortunate linkage to the SAM database for the CEC model parameters. I think changing |
||
The series resistance at reference conditions, in ohms. | ||
|
||
cells_in_series : integer | ||
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.
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 but we use |
||
The number of cells connected in series. | ||
|
||
R_sh_exp : float | ||
The exponent in the equation for shunt resistance, unitless. Defaults | ||
to 5.5. | ||
|
||
EgRef : float | ||
The energy bandgap at reference temperature in units of eV. | ||
1.121 eV for crystalline silicon. EgRef must be >0. | ||
|
||
irrad_ref : float (optional, default=1000) | ||
Reference irradiance in W/m^2. | ||
|
||
temp_ref : float (optional, default=25) | ||
Reference cell temperature in C. | ||
|
||
Returns | ||
------- | ||
Tuple of the following results: | ||
|
||
photocurrent : numeric | ||
Light-generated current in amperes | ||
|
||
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. temp_cell 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 edited the output description (and in |
||
saturation_current : numeric | ||
Diode saturation current in amperes | ||
|
||
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. temp_cell |
||
resistance_series : float | ||
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. Seems like this should be "numeric" too. |
||
Series resistance in ohms | ||
|
||
resistance_shunt : numeric | ||
Shunt resistance in ohms | ||
|
||
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. temp_cell |
||
nNsVth : numeric | ||
The product of the usual diode ideality factor (n, unitless), | ||
number of cells in series (Ns), and cell thermal voltage at | ||
specified effective irradiance and cell temperature. | ||
|
||
References | ||
---------- | ||
[1] K. Sauer, T. Roessler, C. W. Hansen, Modeling the Irradiance and | ||
Temperature Dependence of Photovoltaic Modules in PVsyst, | ||
IEEE Journal of Photovoltaics v5(1), January 2015. | ||
|
||
[2] A. Mermoud, PV modules modelling, Presentation at the 2nd PV | ||
Performance Modeling Workshop, Santa Clara, CA, May 2013 | ||
|
||
[3] A. Mermoud, T. Lejeune, Performance Assessment of a Simulation Model | ||
for PV modules of any available technology, 25th European Photovoltaic | ||
Solar Energy Conference, Valencia, Spain, Sept. 2010 | ||
|
||
See Also | ||
-------- | ||
calcparams_desoto | ||
singlediode | ||
|
||
''' | ||
|
||
# Boltzmann constant in J/K | ||
k = 1.3806488e-23 | ||
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. Appears to differ a bit from 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. Good catch. That's a typo. 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. ref #483. |
||
|
||
# elementary charge in coulomb | ||
q = 1.6021766e-19 | ||
|
||
# reference temperature | ||
Tref_K = temp_ref + 273.15 | ||
Tcell_K = temp_cell + 273.15 | ||
|
||
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. temp_ref_K ? 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. these are local variables, so I think its OK that they are different in style. 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. So I changed them as you suggested :) |
||
gamma = gamma_ref + mugamma * (Tcell_K - Tref_K) | ||
nNsVth = gamma * k / q * cells_in_series * Tcell_K | ||
|
||
IL = effective_irradiance / irrad_ref * \ | ||
(I_L_ref + alpha_sc * (Tcell_K - Tref_K)) | ||
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. Optimization possibility: |
||
|
||
I0 = I_o_ref * ((Tcell_K / Tref_K) ** 3) * \ | ||
(np.exp((q * EgRef) / (k * gamma) * (1 / Tref_K - 1 / Tcell_K))) | ||
|
||
Rsh_tmp = (R_sh_ref - R_sh_0 * np.exp(-R_sh_exp)) / (1.0 - np.exp(-R_sh_exp)) | ||
Rsh_base = np.maximum(0.0, Rsh_tmp) | ||
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. In looking over http://files.pvsyst.com/help/pvmodule_rshexp.htm, it is not clear to me why 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. You're not, PVsyst documentation is missing that definition of |
||
|
||
Rsh = Rsh_base + (R_sh_0 - Rsh_base) * \ | ||
np.exp(-R_sh_exp * effective_irradiance / irrad_ref) | ||
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. Optimization possibility: |
||
|
||
Rs = R_s | ||
|
||
return IL, I0, Rs, Rsh, nNsVth | ||
|
||
|
||
def retrieve_sam(name=None, path=None): | ||
''' | ||
Retrieve latest module and inverter info from a local file or the | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -174,6 +174,23 @@ def cec_module_params(sam_data): | |
return module_parameters | ||
|
||
|
||
@pytest.fixture(scope="session") | ||
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. not a big deal, but if we're still making changes this should not have 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 copied 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. no scope argument. 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. The reasoning for this is that this function returns a mutable dictionary. In principle, one test could inadvertently modify the dictionary, and a second test could pass or fail because of that modification. 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. OK. I'll remove this instance of |
||
def pvsyst_module_params(): | ||
module_parameters = {} | ||
module_parameters['gamma_ref'] = 1.05 | ||
module_parameters['mugamma'] = 0.001 | ||
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. test fixture and the two tests below need mugamma --> mu_gamma |
||
module_parameters['I_L_ref'] = 6.0 | ||
module_parameters['I_o_ref'] = 5e-9 | ||
module_parameters['EgRef'] = 1.121 | ||
module_parameters['R_sh_ref'] = 300 | ||
module_parameters['R_sh_0'] = 1000 | ||
module_parameters['R_s'] = 0.5 | ||
module_parameters['R_sh_exp'] = 5.5 | ||
module_parameters['cells_in_series'] = 60 | ||
module_parameters['alpha_sc'] = 0.001 | ||
return module_parameters | ||
|
||
|
||
def test_sapm(sapm_module_params): | ||
|
||
times = pd.DatetimeIndex(start='2015-01-01', periods=5, freq='12H') | ||
|
@@ -386,6 +403,35 @@ def test_calcparams_desoto(cec_module_params): | |
assert_allclose(nNsVth, 0.473) | ||
|
||
|
||
def test_calcparams_pvsyst(pvsyst_module_params): | ||
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. Not critical, but you might consider a simple "API" test that passes the five computed coefficients into 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. Fair point. I'm not going to put a new test in here because I don't clearly see how to separate issues being tested, and to avoid redundant tests. The current Do you have an example in the 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. No, I haven't written any tests yet and I admit that I am not familiar with this particular mocker setup. If a mock call can verify the API, then that would be great. I don't mean to hold up this PR and I'll look into it further with the Campanelli model. |
||
times = pd.DatetimeIndex(start='2015-01-01', periods=2, freq='12H') | ||
effective_irradiance = pd.Series([0.0, 800.0], index=times) | ||
temp_cell = pd.Series([25, 50], index=times) | ||
|
||
IL, I0, Rs, Rsh, nNsVth = pvsystem.calcparams_pvsyst( | ||
effective_irradiance, | ||
temp_cell, | ||
alpha_sc=pvsyst_module_params['alpha_sc'], | ||
gamma_ref=pvsyst_module_params['gamma_ref'], | ||
mugamma=pvsyst_module_params['mugamma'], | ||
I_L_ref=pvsyst_module_params['I_L_ref'], | ||
I_o_ref=pvsyst_module_params['I_o_ref'], | ||
R_sh_ref=pvsyst_module_params['R_sh_ref'], | ||
R_sh_0=pvsyst_module_params['R_sh_0'], | ||
R_s=pvsyst_module_params['R_s'], | ||
cells_in_series=pvsyst_module_params['cells_in_series'], | ||
EgRef=pvsyst_module_params['EgRef']) | ||
|
||
assert_series_equal(np.round(IL, 3), pd.Series([0.0, 4.8200], index=times)) | ||
assert_series_equal(np.round(I0, 3), | ||
pd.Series([0.0, 1.47e-7], index=times)) | ||
assert_allclose(Rs, 0.500) | ||
assert_series_equal(np.round(Rsh, 3), | ||
pd.Series([1000.0, 305.757], index=times)) | ||
assert_series_equal(np.round(nNsVth, 4), | ||
pd.Series([1.6186, 1.7961], index=times)) | ||
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. My preference is to compute the expected values directly in the test. I'm curious if you have particular reasons not to do 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 don't other than it was easy (for me) to compute the values in MATLAB and hardcode them here. My way is certainly less transparent. 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'm confused. I don't understand how general test values can be computed inside a test without duplicating the function itself. 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. Some view including a separate (re)computation as redundant, others view it as transparent. In this case I don't think any of the computations require an implicit solver, so where the values come from should not leave too much to question. |
||
|
||
|
||
def test_PVSystem_calcparams_desoto(cec_module_params, mocker): | ||
mocker.spy(pvsystem, 'calcparams_desoto') | ||
module_parameters = cec_module_params.copy() | ||
|
@@ -414,6 +460,36 @@ def test_PVSystem_calcparams_desoto(cec_module_params, mocker): | |
assert_allclose(nNsVth, 0.5, atol=0.1) | ||
|
||
|
||
def test_PVSystem_calcparams_pvsyst(pvsyst_module_params, mocker): | ||
mocker.spy(pvsystem, 'calcparams_pvsyst') | ||
module_parameters = pvsyst_module_params.copy() | ||
system = pvsystem.PVSystem(module_parameters=module_parameters) | ||
effective_irradiance = np.array([0, 800]) | ||
temp_cell = np.array([25, 50]) | ||
IL, I0, Rs, Rsh, nNsVth = system.calcparams_pvsyst(effective_irradiance, | ||
temp_cell) | ||
pvsystem.calcparams_pvsyst.assert_called_once_with( | ||
effective_irradiance, | ||
temp_cell, | ||
alpha_sc=pvsyst_module_params['alpha_sc'], | ||
gamma_ref=pvsyst_module_params['gamma_ref'], | ||
mugamma=pvsyst_module_params['mugamma'], | ||
I_L_ref=pvsyst_module_params['I_L_ref'], | ||
I_o_ref=pvsyst_module_params['I_o_ref'], | ||
R_sh_ref=pvsyst_module_params['R_sh_ref'], | ||
R_sh_0=pvsyst_module_params['R_sh_0'], | ||
R_s=pvsyst_module_params['R_s'], | ||
cells_in_series=pvsyst_module_params['cells_in_series'], | ||
EgRef=pvsyst_module_params['EgRef'], | ||
R_sh_exp=pvsyst_module_params['R_sh_exp']) | ||
|
||
assert_allclose(IL, np.array([0.0, 4.8200]), atol=1) | ||
assert_allclose(I0, np.array([0.0, 1.47e-7]), atol=1.0e-5) | ||
assert_allclose(Rs, 0.5, atol=0.1) | ||
assert_allclose(Rsh, np.array([1000, 305.757]), atol=50) | ||
assert_allclose(nNsVth, np.array([1.6186, 1.7961]), atol=0.1) | ||
|
||
|
||
@pytest.fixture(params=[ | ||
{ # Can handle all python scalar inputs | ||
'Rsh': 20., | ||
|
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.
(:issue:
470
)