@sh.add_function(dsp, outputs=['co2_params_calibrated', 'calibration_status'])
def calibrate_co2_params(
is_cycle_hot, engine_coolant_temperatures, co2_emissions_model,
identified_co2_emissions, co2_params_identified,
_1st_step=dfl.functions.calibrate_co2_params.enable_first_step,
_2nd_step=dfl.functions.calibrate_co2_params.enable_second_step,
_3rd_step=dfl.functions.calibrate_co2_params.enable_third_step):
"""
Calibrates the CO2 emission model parameters (a2, b2, a, b, c, l, l2, t, trg
).
:param engine_coolant_temperatures:
Engine coolant temperature vector [°C].
:type engine_coolant_temperatures: numpy.array
:param co2_emissions_model:
CO2 emissions model (co2_emissions = models(params)).
:type co2_emissions_model: callable
:param identified_co2_emissions:
CO2 instantaneous emissions vector [CO2g/s].
:type identified_co2_emissions: numpy.array
:param co2_params_identified:
Identified initial guess of co2 emission model params.
:type co2_params_identified: Parameters
:param is_cycle_hot:
Is an hot cycle?
:type is_cycle_hot: bool
:param _1st_step:
Enable first step in the co2_params calibration? [-]
:type _1st_step: bool
:param _2nd_step:
Enable second step in the co2_params calibration? [-]
:type _2nd_step: bool
:param _3rd_step:
Enable third step in the co2_params calibration? [-]
:type _3rd_step: bool
:return:
Calibrated CO2 emission model parameters (a2, b2, a, b, c, l, l2, t,
trg) and their calibration statuses.
:rtype: (lmfit.Parameters, list)
"""
err = _define_co2_error(co2_emissions_model, identified_co2_emissions)
# Safety measure to not modify the initial guess.
p = copy.deepcopy(co2_params_identified)
# Identify cold and hot phases.
cold = _identify_cold_phase(p, is_cycle_hot, engine_coolant_temperatures)
hot = ~cold
# Definition of thermal and willans parameters.
thermal_p = {'t0', 't1', 'dt', 'trg'}
willans_p = {'a2', 'b2', 'a', 'b', 'c', 'l', 'l2'}
# Identification of all parameters that can vary.
pvary = {k for k, v in p.items() if v.vary}
# Zero step: Initialization of the statuses.
statuses = [(True, copy.deepcopy(p))]
# Definition of the optimization function.
def _op(par, params2optimize, **kws):
fixp = pvary - params2optimize
_set_attr(par, fixp)
if pvary - fixp:
par, s = _calibrate_model_params(err, par, **kws)
else:
s = True
statuses.append((s, copy.deepcopy(par)))
_set_attr(par, pvary, True)
return par
# First step: Calibration of willans parameters using the hot phase.
p = _op(p, _1st_step and hot.any() and willans_p or set(), sub_values=hot)
# Second step: Calibration of thermal parameters using the cold phase.
if not cold.any():
# When the cycle has not cold phases, thermal parameters have no effect.
# The third step will modify arbitrarily this parameters.
# Hence, to avoid erroneous results, thermal parameters are fixed to
# zero because they cannot be identified.
_set_attr(p, thermal_p)
_set_attr(p, pvary.intersection(('t1', 'dt')), 0, 'value')
pvary -= thermal_p
p = _op(p, _2nd_step and cold.any() and thermal_p or set(), sub_values=cold)
# Third step: Calibration of all parameters.
p = _op(p, _3rd_step and pvary or set())
return p, statuses