8000 Implement CEC model by cwhanse · Pull Request #560 · pvlib/pvlib-python · GitHub
[go: up one dir, main page]

Skip to content

Implement CEC model #560

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 13 commits into from
Sep 8, 2018
Merged
Show file tree
Hide file tree
Changes from 11 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
2 changes: 2 additions & 0 deletions docs/sphinx/source/api.rst
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,7 @@ Functions relevant for single diode models.
.. autosummary::
:toctree: generated/

pvsystem.calcparams_cec
pvsystem.calcparams_desoto
pvsystem.calcparams_pvsyst
pvsystem.i_from_v
Expand Down Expand Up @@ -419,6 +420,7 @@ ModelChain model definitions.
:toctree: generated/

modelchain.ModelChain.sapm
modelchain.ModelChain.cec
modelchain.ModelChain.desoto
modelchain.ModelChain.pvsyst
modelchain.ModelChain.pvwatts_dc
Expand Down
9 changes: 9 additions & 0 deletions docs/sphinx/source/whatsnew/v0.6.0.rst
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,13 @@ API Changes
dirindex functions. (:issue:`311`, :issue:`396`)
* Method ModelChain.infer_dc_model now returns a tuple (function handle, model name string)
instead of only the function handle (:issue:`417`)
* Add DC model methods desoto and pvsyst to ModelChain, and deprecates DC model method
singlediode (singlediode defaults to desoto until v0.7.0) (:issue:`487`)
* Add the CEC module model in pvsystem.calcparams_cec and ModelChain.cec. The CEC model
differs from the desoto model by using the parameter Adjust. Modules selected from
the SAM CEC library sam-library-cec-modules-2017-6-5.csv include the Adjust parameter
and ModelChain.infer_dc_model will now select the cec model rather than the desoto model.
(:issue:`463`)
* Add DC model methods desoto and pvsyst to ModelChain, and deprecates DC model method singlediode
(singlediode defaults to desoto until v0.7.0) (:issue:`487`)
* The behavior of irradiance.perez(return_components=True) has changed.
Expand Down Expand Up @@ -111,6 +118,8 @@ Enhancements
* Add irradiance.clearness_index function. (:issue:`396`)
* Add irradiance.clearness_index_zenith_independent function. (:issue:`396`)
* Add checking for consistency between module_parameters and dc_model. (:issue:`417`)
* Add DC model methods ``'desoto'`` and ``'pvsyst'`` to ModelChain (:issue:`487`)
* Add the CEC module model in `pvsystem.calcparams_cec` and `ModelChain.cec`. (:issue:`463`)
* Add DC model methods desoto and pvsyst to ModelChain (:issue:`487`)
* Set default alpha to 1.14 in :func:`~pvlib.atmosphere.angstrom_aod_at_lambda` (:issue:`563`)

Expand Down
28 changes: 26 additions & 2 deletions pvlib/modelchain.py
Original file line number Diff line number Diff line change
Expand Up @@ -247,7 +247,7 @@ class ModelChain(object):
dc_model: None, str, or function, default None
If None, the model will be inferred from the contents of
system.module_parameters. Valid strings are 'sapm',
'desoto', 'pvsyst', 'pvwatts'. The ModelChain instance will
'desoto', 'cec', 'pvsyst', 'pvwatts'. The ModelChain instance will
be passed as the first argument to a user-defined function.

ac_model: None, str, or function, default None
Expand Down Expand Up @@ -376,6 +376,8 @@ def dc_model(self, model):
self._dc_model = self.sapm
elif model == 'desoto':
self._dc_model = self.desoto
elif model == 'cec':
self._dc_model = self.cec
elif model == 'pvsyst':
self._dc_model = self.pvsyst
elif model == 'pvwatts':
Expand All @@ -396,7 +398,11 @@ def infer_dc_model(self):
params = set(self.system.module_parameters.keys())
if set(['A0', 'A1', 'C7']) <= params:
return self.sapm, 'sapm'
elif set(['a_ref', 'I_L_ref', 'I_o_ref', 'R_sh_ref', 'R_s']) <= params:
elif set(['a_ref', 'I_L_ref', 'I_o_ref', 'R_sh_ref',
'R_s', 'Adjust']) <= params:
return self.cec, 'cec'
elif set(['a_ref', 'I_L_ref', 'I_o_ref', 'R_sh_ref',
'R_s']) <= params:
return self.desoto, 'desoto'
elif set(['gamma_ref', 'mu_gamma', 'I_L_ref', 'I_o_ref',
'R_sh_ref', 'R_sh_0', 'R_sh_exp', 'R_s']) <= params:
Expand Down Expand Up @@ -433,6 +439,24 @@ def desoto(self):

return self

def cec(self):
(photocurrent, saturation_current, resistance_series,
resistance_shunt, nNsVth) = (
self.system.calcparams_cec(self.effective_irradiance,
self.temps['temp_cell']))

self.diode_params = (photocurrent, saturation_current,
resistance_series,
resistance_shunt, nNsVth)

self.dc = self.system.singlediode(
photocurrent, saturation_current, resistance_series,
resistance_shunt, nNsVth)

self.dc = self.system.scale_voltage_current_power(self.dc).fillna(0)

return self

def pvsyst(self):
(photocurrent, saturation_current, resistance_series,
resistance_shunt, nNsVth) = (
Expand Down
179 changes: 174 additions & 5 deletions pvlib/pvsystem.py
10000
Original file line number Diff line number Diff line change
Expand Up @@ -23,23 +23,26 @@

# a dict of required parameter names for each DC power model
DC_MODEL_PARAMS = {
'sapm' : set([
'sapm': set([
'A0', 'A1', 'A2', 'A3', 'A4', 'B0', 'B1', 'B2', 'B3',
'B4', 'B5', 'C0', 'C1', 'C2', 'C3', 'C4', 'C5', 'C6',
'C7', 'Isco', 'Impo', 'Aisc', 'Aimp', 'Bvoco',
'Mbvoc', 'Bvmpo', 'Mbvmp', 'N', 'Cells_in_Series',
'IXO', 'IXXO', 'FD']),
'desoto' : set([
'desoto': set([
'alpha_sc', 'a_ref', 'I_L_ref', 'I_o_ref',
'R_sh_ref', 'R_s']),
'pvsyst' : set([
'cec': set([
'alpha_sc', 'a_ref', 'I_L_ref', 'I_o_ref',
'R_sh_ref', 'R_s', 'Adjust']),
'pvsyst': set([
'gamma_ref', 'mu_gamma', 'I_L_ref', 'I_o_ref',
'R_sh_ref', 'R_sh_0', 'R_s', 'alpha_sc', 'EgRef',
'cells_in_series']),
'singlediode' : set([
'singlediode': set([
'alpha_sc', 'a_ref', 'I_L_ref', 'I_o_ref',
'R_sh_ref', 'R_s']),
'pvwatts' : set(['pdc0', 'gamma_pdc'])
'pvwatts': set(['pdc0', 'gamma_pdc'])
}


Expand Down Expand Up @@ -336,6 +339,35 @@ def calcparams_desoto(self, effective_irradiance, temp_cell, **kwargs):

return calcparams_desoto(effective_irradiance, temp_cell, **kwargs)

def calcparams_cec(self, effective_irradiance, temp_cell, **kwargs):
"""
Use the :py:func:`calcparams_cec` 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_cec for details

Returns
-------
See pvsystem.calcparams_cec for details
"""

kwargs = _build_kwargs(['a_ref', 'I_L_ref', 'I_o_ref', 'R_sh_ref',
'R_s', 'alpha_sc', 'Adjust', 'EgRef', 'dEgdT',
'irrad_ref', 'temp_ref'],
self.module_parameters)

return calcparams_cec(effective_irradiance, temp_cell, **kwargs)

def calcparams_pvsyst(self, effective_irradiance, temp_cell):
"""
Use the :py:func:`calcparams_pvsyst` function, the input
Expand Down Expand Up @@ -1223,6 +1255,143 @@ def calcparams_desoto(effective_irradiance, temp_cell,
return IL, I0, Rs, Rsh, nNsVth


def calcparams_cec(effective_irradiance, temp_cell,
alpha_sc, a_ref, I_L_ref, I_o_ref, R_sh_ref, R_s,
Adjust, EgRef=1.121, dEgdT=-0.0002677,
irrad_ref=1000, temp_ref=25):
'''
Calculates five parameter values for the single diode equation at
effective irradiance and cell temperature using the CEC
model described in [1]. The CEC model differs from the De soto et al.
model [3] by the parameter Adjust. The five values returned by
calcparams_cec can be used by singlediode to calculate an IV curve.

Parameters
----------
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.

a_ref : float
The product of the usual diode ideality factor (n, unitless),
number of cells in series (Ns), and cell thermal voltage at reference
conditions, in units of V.

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_s : float
The series resistance at reference conditions, in ohms.

Adjust : float
The adjustment to the temperature coefficient for short circuit
current, in percent

EgRef : float
The energy bandgap at reference temperature in units of eV.
1.121 eV for crystalline silicon. EgRef must be >0. For parameters
from the SAM CEC module database, EgRef=1.121 is implicit for all
cell types in the parameter estimation algorithm used by NREL.

dEgdT : float
The temperature dependence of the energy bandgap at reference
conditions in units of 1/K. May be either a scalar value
(e.g. -0.0002677 as in [3]) or a DataFrame (this may be useful if
dEgdT is a modeled as a function of temperature). For parameters from
the SAM CEC module database, dEgdT=-0.0002677 is implicit for all cell
types in the parameter estimation algorithm used by NREL.

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

saturation_current : numeric
Diode saturation curent in amperes

resistance_series : float
Series resistance in ohms

resistance_shunt : numeric
Shunt resistance in ohms

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] A. Dobos, "An Improved Coefficient Calculator for the California
Energy Commission 6 Parameter Photovoltaic Module Model", Journal of
Solar Energy Engineering, vol 134, 2012.

[2] System Advisor Model web page. https://sam.nrel.gov.

[3] W. De Soto et al., "Improvement and validation of a model for
photovoltaic array performance", Solar Energy, vol 80, pp. 78-88,
2006.

See Also
--------
calcparams_desoto
singlediode
retrieve_sam

'''

# test for use of function pre-v0.6.0 API change
if isinstance(a_ref, dict) or \
(isinstance(a_ref, pd.Series) and ('a_ref' in a_ref.keys())):
import warnings
warnings.warn('module_parameters detected as fourth positional'
+ ' argument of calcparams_cec. calcparams_cec'
+ ' will require one argument for each module model'
+ ' parameter in v0.7.0 and later', DeprecationWarning)
try:
module_parameters = a_ref
a_ref = module_parameters['a_ref']
I_L_ref = module_parameters['I_L_ref']
I_o_ref = module_parameters['I_o_ref']
R_sh_ref = module_parameters['R_sh_ref']
R_s = module_parameters['R_s']
except Exception as e:
raise e('Module parameters could not be extracted from fourth'
+ ' positional argument of calcparams_desoto. Check that'
+ ' parameters are from the CEC database and/or update'
+ ' your code for the new API for calcparams_desoto')

# pass adjusted temperature coefficient to desoto
return calcparams_desoto(effective_irradiance, temp_cell,
alpha_sc*(1.0 - Adjust/100),
a_ref, I_L_ref, I_o_ref,
R_sh_ref, R_s,
EgRef=1.121, dEgdT=-0.0002677,
irrad_ref=1000, temp_ref=25)


def calcparams_pvsyst(effective_irradiance, temp_cell,
alpha_sc, gam 3E95 ma_ref, mu_gamma,
I_L_ref, I_o_ref,
Expand Down
6 changes: 6 additions & 0 deletions pvlib/test/test_modelchain.py
Original file line number Diff line number Diff line change
Expand Up @@ -219,6 +219,7 @@ def poadc(mc):

@pytest.mark.parametrize('dc_model', [
'sapm',
pytest.param('cec', marks=requires_scipy),
pytest.param('desoto', marks=requires_scipy),
pytest.param('pvsyst', marks=requires_scipy),
pytest.param('singlediode', marks=requires_scipy),
Expand All @@ -227,16 +228,21 @@ def test_infer_dc_model(system, cec_dc_snl_ac_system, pvsyst_dc_snl_ac_system,
pvwatts_dc_pvwatts_ac_system, location, dc_model,
weather, mocker):
dc_systems = {'sapm': system,
'cec': cec_dc_snl_ac_system,
'desoto': cec_dc_snl_ac_system,
'pvsyst': pvsyst_dc_snl_ac_system,
'singlediode': cec_dc_snl_ac_system,
'pvwatts_dc': pvwatts_dc_pvwatts_ac_system}
dc_model_function = {'sapm': 'sapm',
'cec': 'calcparams_cec',
'desoto': 'calcparams_desoto',
'pvsyst': 'calcparams_pvsyst',
'singlediode': 'calcparams_desoto',
'pvwatts_dc': 'pvwatts_dc'}
system = dc_systems[dc_model]
# remove Adjust from model parameters for desoto, singlediode
if dc_model in ['desoto', 'singlediode']:
system.module_parameters.pop('Adjust')
m = mocker.spy(system, dc_model_function[dc_model])
mc = ModelChain(system, location,
aoi_model='no_loss', spectral_model='no_loss')
Expand Down
48 changes: 40 additions & 8 deletions pvlib/test/test_pvsystem.py
Original file line number Diff line number Diff line change
Expand Up @@ -379,9 +379,9 @@ def test_PVSystem_sapm_effective_irradiance(sapm_module_params, mocker):


def test_calcparams_desoto(cec_module_params):
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, 25], index=times)
times = pd.DatetimeIndex(start='2015-01-01', periods=3, freq='12H')
effective_irradiance = pd.Series([0.0, 800.0, 800.0], index=times)
temp_cell = pd.Series([25, 25, 50], index=times)

IL, I0, Rs, Rsh, nNsVth = pvsystem.calcparams_desoto(
effective_irradiance,
Expand All @@ -395,12 +395,44 @@ def test_calcparams_desoto(cec_module_params):
EgRef=1.121,
dEgdT=-0.0002677)

assert_series_equal(np.round(IL, 3), pd.Series([0.0, 6.036], index=times))
# changed value in GH 444 for 2017-6-5 module file
assert_allclose(I0, 1.94e-9)
assert_series_equal(IL, pd.Series([0.0, 6.036, 6.096], index=times),
check_less_precise=3)
assert_series_equal(I0, pd.Series([0.0, 1.94e-9, 7.419e-8], index=times),
check_less_precise=3)
assert_allclose(Rs, 0.094)
assert_series_equal(Rsh, pd.Series([np.inf, 19.65, 19.65], index=times),
check_less_precise=3)
assert_series_equal(nNsVth, pd.Series([0.473, 0.473, 0.5127], index=times),
check_less_precise=3)


def test_calcparams_cec(cec_module_params):
times = pd.DatetimeIndex(start='2015-01-01', periods=3, freq='12H')
effective_irradiance = pd.Series([0.0, 800.0, 800.0], index=times)
temp_cell = pd.Series([25, 25, 50], index=times)

IL, I0, Rs, Rsh, nNsVth = pvsystem.calcparams_cec(
effective_irradiance,
temp_cell,
alpha_sc=cec_module_params['alpha_sc'],
a_ref=cec_module_params['a_ref'],
I_L_ref=cec_module_params['I_L_ref'],
I_o_ref=cec_module_params['I_o_ref'],
R_sh_ref=cec_module_params['R_sh_ref'],
R_s=cec_module_params['R_s'],
Adjust=cec_module_params['Adjust'],
EgRef=1.121,
dEgdT=-0.0002677)

assert_series_equal(IL, pd.Series([0.0, 6.036, 6.0896], index=times),
check_less_precise=3)
assert_series_equal(I0, pd.Series([0.0, 1.94e-9, 7.419e-8], index=times),
check_less_precise=3)
assert_allclose(Rs, 0.094)
assert_series_equal(np.round(Rsh, 3), pd.Series([np.inf, 19.65], index=times))
assert_allclose(nNsVth, 0.473)
assert_series_equal(Rsh, pd.Series([np.inf, 19.65, 19.65], index=times),
check_less_precise=3)
assert_series_equal(nNsVth, pd.Series([0.473, 0.473, 0.5127], index=times),
check_less_precise=3)


def test_calcparams_pvsyst(pvsyst_module_params):
Expand Down
0