Source code for co2mpas.core.model.physical.cycle.NEDC

#!/usr/bin/env python
# -*- 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 define theoretical profiles of NEDC cycle.
"""
import schedula as sh
from co2mpas.defaults import dfl

dsp = sh.BlueDispatcher(
    name='NEDC cycle model',
    description='Returns the theoretical times, velocities, and gears of NEDC.'
)

dsp.add_data(
    'initial_temperature', dfl.values.initial_temperature_NEDC,
    description='Initial temperature of the test cell [°C].'
)
dsp.add_data(
    'max_time', dfl.values.max_time_NEDC, 5, description='Maximum time [s].',

)
dsp.add_data('k1', dfl.values.k1)
dsp.add_data('k2', dfl.values.k2)
dsp.add_data('k5', dfl.values.k5, 10)

dsp.add_function(
    function_id='set_max_gear_as_default_k5',
    function=sh.bypass,
    inputs=['max_gear'],
    outputs=['k5']
)


[docs]def nedc_gears(times, max_gear, k1=1, k2=2, k5=2): """ Returns the gear shifting profile according to NEDC [-]. :param times: Time vector [s]. :type times: numpy.array :param max_gear: Maximum gear of the gear box [-]. :type max_gear: int :param k1: K1 NEDC parameter (first or second gear) [-]. :type k1: int :param k2: K2 NEDC parameter (first or second gear) [-]. :type k2: int :param k5: K5 NEDC parameter (first or second gear) [-]. :type k5: int :return: Gear vector [-]. :rtype: numpy.array """ from scipy.interpolate import interp1d eps, parts = 0.01, {} # part one parts[0] = parts[1] = parts[2] = parts[3] = ( (0, 0), (6, 0), (6, k1), (11, k1), (11, 1), (25, 1), (25, k1), (28, k1), (28, 0), (44, 0), (44, k1), (49, k1), (49, 1), (55 - eps, 1), (55 - eps, 2), (93, 2), (93, k2), (96, k2), (96, 0), (112, 0), (112, k1), (117, k1), (117, 1), (123 - eps, 1), (123 - eps, 2), (134 - eps, 2), (134 - eps, 3), (177 - eps, 3), (177 - eps, 2), (185, 2), (185, k2), (188, k2), (188, 0), (195, 0) ) # part two parts[4] = ( (0, k1), (20, k1), (20, 1), (26 - eps, 1), (26 - eps, 2), (37 - eps, 2), (37 - eps, 3), (47 - eps, 3), (47 - eps, 4), (61, 4), (61, 5), (115, 5), (115, 4), (201, 4), (201, 5), (286, 5), (286, max_gear), (370, max_gear), (370, k5), (380, k5), (380, 0), (400, 0) ) tg = _repeat_parts(times, parts).T s = interp1d(*tg, kind='nearest', assume_sorted=True)(times) s[s > max_gear] = max_gear return s
# noinspection PyUnusedLocal, PyMissingOrEmptyDocstring
[docs]def is_manual(gear_box_type, *args): return gear_box_type == 'manual'
dsp.add_function( function_id='nedc_gears', function=sh.add_args(nedc_gears), inputs=['gear_box_type', 'times', 'max_gear', 'k1', 'k2', 'k5'], outputs=['gears'], input_domain=is_manual ) def _repeat_parts(times, parts): import numpy as np from functools import reduce it = [v[1] for v in sorted(parts.items())] def _func(x, y): y = np.array(y) y[:, 0] += x[-1][-1][0] return x + (y,) tv = np.concatenate(reduce(_func, it[1:], (it[0],))) n = int(np.ceil(times[-1] / tv[-1][0])) - 1 if n > 0: tv = np.concatenate(reduce(_func, (tv,) * n, (tv,))) return tv
[docs]@sh.add_function(dsp, outputs=['velocities']) def nedc_velocities(times, gear_box_type): """ Returns the velocity profile according to NEDC and gear box type [km/h]. :param times: Time vector [s]. :type times: numpy.array :param gear_box_type: Gear box type (manual or automatic or cvt). :type gear_box_type: str :return: Velocity vector [km/h]. :rtype: numpy.array """ from numpy import interp parts = { 'manual': { 0: ( (0, 0), (11, 0), (15, 15), (23, 15), (25, 10), (28, 0), (49, 0), (54, 15), (56, 15), (61, 32), (85, 32), (93, 10), (96, 0), (117, 0), (122, 15), (124, 15), (133, 35), (135, 35), (143, 50), (155, 50), (163, 35), (176, 35), (178, 35), (185, 10), (188, 0), (195, 0) ), 4: ( (0, 0), (20, 0), (25, 15), (27, 15), (36, 35), (38, 35), (46, 50), (48, 50), (61, 70), (111, 70), (119, 50), (188, 50), (201, 70), (251, 70), (286, 100), (316, 100), (336, 120), (346, 120), (362, 80), (370, 50), (380, 0), (400, 0) ) }, 'automatic': { 0: ( (0, 0), (11, 0), (15, 15), (23, 15), (25, 10), (28, 0), (49, 0), (61, 32), (85, 32), (93, 10), (96, 0), (117, 0), (143, 50), (155, 50), (163, 35), (176, 35), (178, 35), (185, 10), (188, 0), (195, 0) ), 4: ( (0, 0), (20, 0), (61, 70), (111, 70), (119, 50), (188, 50), (201, 70), (251, 70), (286, 100), (316, 100), (336, 120), (346, 120), (362, 80), (370, 50), (380, 0), (400, 0) ) } } for k, v in parts.items(): v[1] = v[2] = v[3] = v[0] parts['cvt'] = parts['planetary'] = parts['automatic'] tv = _repeat_parts(times, parts[gear_box_type]) return interp(times, *tv.T)