# -*- coding: utf-8 -*-
#
# Copyright 2015-2019 European Commission (JRC);
# Licensed under the EUPL (the 'Licence');
# You may not use this work except in compliance with the Licence.
# You may obtain a copy of the Licence at: http://ec.europa.eu/idabc/eupl
"""
Functions and `dsp` model to model clutch and torque converter.
Sub-Modules:
.. currentmodule:: co2mpas.core.model.physical.clutch_tc
.. autosummary::
:nosignatures:
:toctree: clutch_tc/
clutch
torque_converter
"""
import numpy as np
import schedula as sh
from co2mpas.defaults import dfl
from .clutch import dsp as _clutch
from .torque_converter import dsp as _torque_converter
dsp = sh.BlueDispatcher(
name='Clutch and torque-converter',
description='Models the clutch and torque-converter.'
)
dsp.add_data('stop_velocity', dfl.values.stop_velocity)
[docs]@sh.add_function(dsp, outputs=['has_torque_converter'])
def default_has_torque_converter(gear_box_type):
"""
Returns the default has torque converter value [-].
:param gear_box_type:
Gear box type (manual or automatic or cvt).
:type gear_box_type: str
:return:
Does the vehicle use torque converter? [-]
:rtype: bool
"""
return gear_box_type == 'automatic'
[docs]@sh.add_function(dsp, outputs=['clutch_phases'])
def calculate_clutch_phases(
times, velocities, gears, gear_shifts, stop_velocity, clutch_window):
"""
Calculate when the clutch is active [-].
:param times:
Time vector [s].
:type times: numpy.array
:param velocities:
Velocity vector [km/h].
:type velocities: numpy.array
:param gears:
Gear vector [-].
:type gears: numpy.array
:param gear_shifts:
When there is a gear shifting [-].
:type gear_shifts: numpy.array
:param stop_velocity:
Maximum velocity to consider the vehicle stopped [km/h].
:type stop_velocity: float
:param clutch_window:
Clutching time window [s].
:type clutch_window: tuple
:return:
When the clutch is active [-].
:rtype: numpy.array
"""
dn, up = clutch_window
b = np.zeros_like(times, dtype=bool)
for t in times[gear_shifts]:
b |= ((t + dn) <= times) & (times <= (t + up))
b &= (gears > 0) & (velocities > stop_velocity)
return b
[docs]@sh.add_function(dsp, outputs=['clutch_tc_speeds_delta'])
def identify_clutch_tc_speeds_delta(
clutch_phases, engine_speeds_out, engine_speeds_base):
"""
Identifies the engine speed delta due to the clutch [RPM].
:param clutch_phases:
When the clutch is active [-].
:type clutch_phases: numpy.array
:param engine_speeds_out:
Engine speed [RPM].
:type engine_speeds_out: numpy.array
:param engine_speeds_base:
Base engine speed (i.e., without clutch/TC effect) [RPM].
:type engine_speeds_base: numpy.array
:return:
Engine speed delta due to the clutch or torque converter [RPM].
:rtype: numpy.array
"""
return np.where(clutch_phases, engine_speeds_out - engine_speeds_base, 0)
[docs]@sh.add_function(dsp, outputs=['clutch_tc_speeds_delta'])
def predict_clutch_tc_speeds_delta(
clutch_tc_speed_model, times, clutch_phases, accelerations,
velocities, gear_box_speeds_in, gears, gear_box_torques_in):
"""
Predicts engine speed delta due to the clutch or torque converter [RPM].
:param clutch_tc_speed_model:
Clutch or Torque converter speed model.
:type clutch_tc_speed_model: callable
:param times:
Time vector [s].
:type times: numpy.array
:param clutch_phases:
When the clutch is active [-].
:type clutch_phases: numpy.array
:param accelerations:
Acceleration vector [m/s2].
:type accelerations: numpy.array
:param velocities:
Vehicle velocity [km/h].
:type velocities: numpy.array
:param gear_box_speeds_in:
Gear box speed vector [RPM].
:type gear_box_speeds_in: numpy.array
:param gears:
Gear vector [-].
:type gears: numpy.array
:param gear_box_torques_in:
Torque required vector [N*m].
:type gear_box_torques_in: numpy.array
:return:
Engine speed delta due to the clutch or torque converter [RPM].
:rtype: numpy.array
"""
b = dfl.functions.predict_clutch_tc_speeds_delta.ENABLE
if b and clutch_phases.any():
func, kwargs = clutch_tc_speed_model, dict(
accelerations=accelerations,
gear_box_torques_in=gear_box_torques_in,
gear_box_speeds_in=gear_box_speeds_in, gears=gears,
velocities=velocities
)
return np.where(clutch_phases, func(times, **kwargs), 0)
return np.zeros_like(clutch_phases, float)
def _calculate_clutch_tc_powers(
clutch_tc_speeds_delta, k_factor_curve, gear_box_speed_in,
gear_box_power_in, engine_speed_out_hot):
engine_speed_out = engine_speed_out_hot + clutch_tc_speeds_delta
is_not_eng2gb = gear_box_speed_in >= engine_speed_out
if clutch_tc_speeds_delta == 0:
ratio = 1
else:
if is_not_eng2gb:
speed_out, speed_in = engine_speed_out, gear_box_speed_in
else:
speed_out, speed_in = gear_box_speed_in, engine_speed_out
if (speed_in > 0) and (clutch_tc_speeds_delta != 0):
ratio = speed_out / speed_in
else:
ratio = 1
eff = k_factor_curve(ratio) * ratio
if is_not_eng2gb and eff != 0:
eff = 1 / eff
if eff > 0:
return gear_box_power_in / eff
return gear_box_power_in
[docs]@sh.add_function(dsp, outputs=['clutch_tc_mean_efficiency'])
def identify_clutch_tc_mean_efficiency(clutch_tc_efficiencies):
"""
Identify clutch or torque converter mean efficiency [-].
:param clutch_tc_efficiencies:
Clutch or torque converter efficiency [-].
:type clutch_tc_efficiencies: numpy.array
:return:
Clutch or torque converter mean efficiency [-].
:rtype: float
"""
from co2mpas.utils import reject_outliers
return reject_outliers(clutch_tc_efficiencies)[0]
[docs]@sh.add_function(dsp, outputs=['clutch_tc_efficiencies'])
def calculate_clutch_tc_efficiencies(
clutch_tc_speeds_delta, k_factor_curve, gear_box_speeds_in,
engine_speeds_out):
"""
Calculates the efficiency of the clutch or torque converter [-].
:param clutch_tc_speeds_delta:
Engine speed delta due to the clutch or torque converter [RPM].
:type clutch_tc_speeds_delta: numpy.array
:param k_factor_curve:
k factor curve.
:type k_factor_curve: callable
:param gear_box_speeds_in:
Gear box speed vector [RPM].
:type gear_box_speeds_in: numpy.array
:param engine_speeds_out:
Engine speed [RPM].
:type engine_speeds_out: numpy.array
:return:
Clutch or torque converter efficiency [-].
:rtype: numpy.array
"""
is_not_eng2gb = gear_box_speeds_in >= engine_speeds_out
speed_out = np.where(is_not_eng2gb, engine_speeds_out, gear_box_speeds_in)
speed_in = np.where(is_not_eng2gb, gear_box_speeds_in, engine_speeds_out)
ratios = np.ones_like(clutch_tc_speeds_delta, dtype=float)
b = (speed_in > 0) & ~np.isclose(clutch_tc_speeds_delta, 0)
ratios[b] = speed_out[b] / speed_in[b]
return k_factor_curve(ratios) * ratios
[docs]@sh.add_function(dsp, outputs=['clutch_tc_powers'])
def calculate_clutch_tc_powers(
clutch_tc_efficiencies, gear_box_speeds_in, clutch_tc_powers_out,
engine_speeds_out):
"""
Calculates the power that flows in the clutch or torque converter [kW].
:param clutch_tc_efficiencies:
Clutch or torque converter efficiency [-].
:type clutch_tc_efficiencies: numpy.array
:param gear_box_speeds_in:
Gear box speed vector [RPM].
:type gear_box_speeds_in: numpy.array
:param clutch_tc_powers_out:
Clutch or torque converter power out [kW].
:type clutch_tc_powers_out: numpy.array
:param engine_speeds_out:
Engine speed [RPM].
:type engine_speeds_out: numpy.array
:return:
Clutch or torque converter power [kW].
:rtype: numpy.array
"""
b = gear_box_speeds_in >= engine_speeds_out
eff = np.where(clutch_tc_efficiencies == 0, 1, clutch_tc_efficiencies)
return clutch_tc_powers_out * np.where(b, eff, 1 / eff)
# noinspection PyMissingOrEmptyDocstring
[docs]def clutch_domain(kwargs):
b = not kwargs.get('has_torque_converter', True)
return b or kwargs.get('gear_box_type') == 'cvt'
dsp.add_dispatcher(
include_defaults=True,
input_domain=clutch_domain,
dsp=_clutch,
dsp_id='clutch',
inputs=(
'engine_speeds_out', 'stop_velocity', 'clutch_tc_speeds_delta', 'times',
'stand_still_torque_ratio', 'gear_box_speeds_in', 'clutch_speed_model',
'accelerations', 'clutch_window', 'lockup_speed_ratio', 'velocities',
'gear_shifts', 'gears', 'clutch_phases', dict(
gear_box_type=sh.SINK, has_torque_converter=sh.SINK
)),
outputs=(
'clutch_speed_model', 'clutch_phases', 'clutch_window',
'k_factor_curve', 'clutch_tc_speeds_delta'
)
)
# noinspection PyMissingOrEmptyDocstring
[docs]def torque_converter_domain(kwargs):
b = kwargs.get('has_torque_converter')
return b and kwargs.get('gear_box_type') != 'cvt'
dsp.add_dispatcher(
include_defaults=True,
input_domain=torque_converter_domain,
dsp=_torque_converter,
dsp_id='torque_converter',
inputs=(
'lockup_speed_ratio', 'engine_max_speed', 'stand_still_torque_ratio',
'torque_converter_speed_model', 'gear_box_torques_in', 'clutch_window',
'full_load_curve', 'engine_speeds_out_hot', 'm1000_curve_norm_torques',
'm1000_curve_factor', 'm1000_curve_ratios', 'clutch_tc_speeds_delta',
'gear_box_speeds_in', 'idle_engine_speed', dict(
gear_box_type=sh.SINK, has_torque_converter=sh.SINK
)),
outputs=(
'k_factor_curve', 'torque_converter_speed_model', 'clutch_window',
'm1000_curve_factor'
)
)
dsp.add_function(
function=sh.bypass,
inputs=['torque_converter_speed_model'],
outputs=['clutch_tc_speed_model']
)
dsp.add_function(
function=sh.bypass,
inputs=['clutch_speed_model'],
outputs=['clutch_tc_speed_model']
)