Description
I would like to implement a hybrid model that combines the single-diode model (SDM) developments of Campanelli et al. (see this) with the SAPM to compute the effective irradiance ratio F and effective temperature ratio H using the SAPM when necessary, i.e., when not using a matched reference device or cell-embedded junction temperature measurement.
I figure one should embrace Python's duck typing (Quack!), so below is my proposed SDM 5 coefficient calculation architecture that is a partial generalization of the existing function calcparams_desoto
. Basically, this is a way of implementing a (somewhat inelegant) computational graph for all the coefficients (e.g., IL, I0, Rs, Rsh, nNsVth). I realize many folks aren't familiar with my model, but if you work through this, you'll see that something like this pattern may make it easier for users to implement different "flavors" of auxiliary equations for the SDM when they are trying to compare models, find a better model, and the like. (I may need to recast my model in terms of effective_irradiance
and cell_temp
to make it fit better with the current direction of the pvlib API, and this might make possible more reuse of auxiliary equations between different SDMs.)
There is a lot of metadata packed into kwargs
, and this provided metadata would change with the particular auxiliary equations selected. (I apologize that this will be a bit hard to understand from just the code snippet below, but I am still working on a runnable example.) What's nice about this pattern, is that one can specify a scalar, an array, or a function-to-be-computed for F, H, and IL, I0, Rs, Rsh, nNsVth, and once a parameter is computed, it can then "flow through" to the remaining computations. (However, unlike Dask, the user has to specify the computation in the proper (serial) order to avoid missing computations or re-computations of the computational graph's nodes.)
def calc_params_hybrid(**kwargs):
"""
Calculate the coefficients of the 5-parameter SDM using a hybrid method.
TODO Explain hybrid method and reference SAPM and Campanelli et al paper.
"""
# Unfortunately, order matters here because some computations rely on
# previous ones
# A computational graph framework might make this more elegant and handle
# more complicated cases, including parallel/distributed computations
kwargs['F'] = get_arg(kwargs['F'], **kwargs)
kwargs['H'] = get_arg(kwargs['H'], **kwargs)
kwargs['I0'] = get_arg(kwargs['I0'], **kwargs)
kwargs['Rs'] = get_arg(kwargs['Rs'], **kwargs)
kwargs['Gsh'] = get_arg(kwargs['Gsh'], **kwargs)
kwargs['nNsVth'] = get_arg(kwargs['nNsVth'], **kwargs)
kwargs['IL'] = get_arg(kwargs['IL'], **kwargs)
return kwargs['IL'], kwargs['I0'], kwargs['Rs'], 1. / kwargs['Gsh'], \
kwargs['nNsVth']
def get_arg(arg, **kwargs):
"""
Computes a function argument as a numpy array, when needed.
"""
if hasattr(arg, '__call__'):
# Call arg to compute it as a numpy array
return arg(**kwargs)
else:
# Return arg as is
return arg
def F_sapm(**kwargs):
"""
Returns the effective irradiance ratio from Campanelli et al. using SAPM
"""
# TODO Compute F from kwargs metadata mapped to SAPM args
F = sapm_effective_irradiance(total_irrad['poa_direct'],
total_irrad['poa_diffuse'],
am_abs, aoi, module) # WIP
return F
def H_sapm(**kwargs):
"""
Returns the effective temperature ratio from Campanelli et al. using SAPM
"""
# TODO Compute H from kwargs metadata mapped to SAPM args
H = sapm_celltemp(poa_global, wind_speed, temp_air,
model='open_rack_cell_glassback') # WIP
return H
def IL_campanelli(**kwargs):
"""
Returns the photocurrent from Campanelli et al.
"""
return kwargs['F'] * kwargs['Isc_ref'] +
kwargs['I0'] * np.expm1(kwargs['F'] * kwargs['Isc_ref'] *
kwargs['Rs'] / kwargs['nNsVth']) + \
kwargs['Gsh'] * kwargs['F'] * kwargs['Isc_ref'] * kwargs['Rs']
def I0_campanelli(**kwargs):
"""
Returns the reverse saturation current from Campanelli et al.
"""
return kwargs['I0_ref'] * kwargs['H']**3. * \
np.exp(kwargs['Eg_ref_star'] / kwargs['nNsVth_ref'] *
(1. - 1. / kwargs['H']) * (1. - kwargs['dEgdT_ref_star']))
def nNsVth_desoto(**kwargs):
"""
Returns a the modified thermal voltage from DeSoto et al.
Same as Campanelli et al.
"""
return kwargs['nNsVth_ref'] * kwargs['H']
def Gsh_photoconductive(**kwargs):
"""
Returns a photoconductive shunt conductance, like DeSoto et al.
"""
return kwargs['Gsh_ref'] * kwargs['F']