def _filter_temperature_samples(spl, on_engine, thermostat): adt = np.abs(spl[:, -1]) b = ~((adt <= 0.001) & on_engine[1:]) b[:co2_utl.argmax(on_engine)] = False i = co2_utl.argmax(thermostat < spl[:, 0]) b[i:] = True b[:i] &= adt[:i] < dfl.functions._filter_temperature_samples.max_abs_dt_cold return spl[b]
def _filter_temperature_samples(X, Y, on_engine, thermostat): adt = np.abs(Y) b = ~((adt <= 0.001) & on_engine[1:]) b[:co2_utl.argmax(on_engine)] = False i = co2_utl.argmax(thermostat < X[:, 0]) b[i:] = True # noinspection PyProtectedMember b[: i] &= adt[:i] < dfl.functions._filter_temperature_samples.max_abs_dt_cold return X[b], Y[b]
def check_initial_temperature(initial_temperature, engine_coolant_temperatures, engine_speeds_out, idle_engine_speed_median): """ Checks if initial temperature is valid according NEDC and WLTP regulations. :param initial_temperature: Engine initial temperature [°C] :type initial_temperature: float :param engine_coolant_temperatures: Engine coolant temperature vector [°C]. :type engine_coolant_temperatures: numpy.array :param engine_speeds_out: Engine speed vector [RPM]. :type engine_speeds_out: numpy.array :param idle_engine_speed_median: Engine speed idle median [RPM]. :type idle_engine_speed_median: float :return: True if data pass the checks. :rtype: bool """ idle = idle_engine_speed_median - con_vals.DELTA_RPM2VALIDATE_TEMP b = engine_speeds_out > idle i = co2_utl.argmax(b) + 1 t = np.mean(engine_coolant_temperatures[:i]) dT = abs(initial_temperature - t) return dT <= con_vals.MAX_VALIDATE_DTEMP and t <= con_vals.MAX_INITIAL_TEMP
def fit(self, currents, on_engine, times, soc, statuses, *args, init_time=0.0): b = (statuses[1:] > 0) & on_engine[1:] i = co2_utl.argmax(times >= times[0] + init_time) from ....engine._thermal import _build_samples X, Y = _build_samples(currents, soc, statuses, *args) if b[i:].any(): self.model, self.mask = self._fit_model(X[i:][b[i:]], Y[i:][b[i:]]) elif b[:i].any(): self.model, self.mask = self._fit_model(X[b], Y[b]) else: self.model = lambda *args, **kwargs: [0.0] self.mask = np.array((0, )) self.mask += 1 if b[:i].any(): init_spl = (times[1:i + 1] - times[0])[:, None], X[:i] init_spl = np.concatenate(init_spl, axis=1)[b[:i]] a = self._fit_model(init_spl, Y[:i][b[:i]], (0, ), (2, )) self.init_model, self.init_mask = a else: self.init_model, self.init_mask = self.model, self.mask return self
def identify_cold_start_speeds_phases(engine_coolant_temperatures, engine_thermostat_temperature, on_idle): """ Identifies phases when engine speed is affected by the cold start [-]. :param engine_coolant_temperatures: Engine coolant temperature vector [°C]. :type engine_coolant_temperatures: numpy.array :param engine_thermostat_temperature: Engine thermostat temperature [°C]. :type engine_thermostat_temperature: float :param on_idle: If the engine is on idle [-]. :type on_idle: numpy.array :return: Phases when engine speed is affected by the cold start [-]. :rtype: numpy.array """ temp = engine_coolant_temperatures i = co2_utl.argmax(temp > engine_thermostat_temperature) p = on_idle.copy() p[i:] = False return p
def fit(self, currents, on_engine, times, soc, statuses, *args, init_time=0.0): b = (statuses[1:] > 0) & on_engine[1:] i = co2_utl.argmax(times > times[0] + init_time) spl = _build_samples(currents, soc, statuses, *args) if b[i:].any(): self.model, self.mask = self._fit_model(spl[i:][b[i:]]) elif b[:i].any(): self.model, self.mask = self._fit_model(spl[b]) else: self.model, self.mask = lambda *args, **kwargs: [0.0], np.array( (0, )) self.mask += 1 if b[:i].any(): init_spl = (np.array([times[1:i + 1] - times[0]]).T, spl[:i]) init_spl = np.concatenate(init_spl, axis=1)[b[:i]] self.init_model, self.init_mask = self._fit_model( init_spl, (0, ), (2, )) else: self.init_model, self.init_mask = self.model, self.mask return self
def identify_cold_start_speeds_phases(engine_coolant_temperatures, engine_thermostat_temperature, on_idle): temp = engine_coolant_temperatures i = co2_utl.argmax(temp > engine_thermostat_temperature) p = on_idle.copy() p[i:] = False return p
def fit(self, is_hybrid, times, charging_statuses, state_of_charges, motive_powers): i = co2_utl.argmax(charging_statuses != 3) status, soc = charging_statuses[i:], state_of_charges[i:] self._fit_bers(status, motive_powers[i:]) self._fit_charge(status, soc, times[i:], is_hybrid) return self
def fit(self, times, alternator_statuses, state_of_charges, gear_box_powers_in): i = co2_utl.argmax(alternator_statuses != 3) status, soc = alternator_statuses[i:], state_of_charges[i:] self._fit_bers(status, gear_box_powers_in[i:]) self._fit_charge(status, soc) self._fit_boundaries(status, soc, times[i:]) return self
def fit(self, idle_engine_speed, on_engine, temperature_derivatives, temperatures, *args): """ Calibrates an engine temperature regression model to predict engine temperatures. This model returns the delta temperature function of temperature (previous), acceleration, and power at the wheel. :param idle_engine_speed: Engine speed idle median and std [RPM]. :type idle_engine_speed: (float, float) :param on_engine: If the engine is on [-]. :type on_engine: numpy.array :param temperature_derivatives: Derivative temperature vector [°C]. :type temperature_derivatives: numpy.array :param temperatures: Temperature vector [°C]. :type temperatures: numpy.array :return: The calibrated engine temperature regression model. :rtype: ThermalModel """ spl = _build_samples(temperature_derivatives, temperatures, *args) self.thermostat = self._identify_thermostat(spl, idle_engine_speed) spl = _filter_temperature_samples(spl, on_engine, self.thermostat) opt = { ## FIXME: Normally RANSAC sets this from its own `random_state`, # but strangely, without this `seed`, it fails with: # Failed DISPATCHING 'engine_model/thermal/calibrate_engine_temperature_regression_model' due to: # noqa # XGBoostError(b"Invalid Parameter format for seed expect int but value='<mtrand.RandomState",) # noqa 'seed': 0, 'max_depth': 2, 'n_estimators': int(min(300.0, 0.25 * (len(spl) - 1))) } model = _SafeRANSACRegressor( base_estimator=self.base_model(**opt), random_state=0, min_samples=0.85, max_trials=10 ) model = sk_pip.Pipeline([ ('feature_selection', _SelectFromModel(model, '0.8*median', in_mask=(0, 2))), ('classification', model) ]) model.fit(spl[:, :-1], spl[:, -1]) self.model = model.steps[-1][-1] self.mask = np.where(model.steps[0][-1]._get_support_mask())[0] self.min_temp = spl[:, 0].min() spl = spl[:co2_utl.argmax(self.thermostat <= spl[:, 0])] if not spl.any(): self.min_temp = -float('inf') return self spl = spl[:co2_utl.argmax(np.percentile(spl[:, 0], 60) <= spl[:, 0])] opt = { 'random_state': 0, 'max_depth': 2, 'n_estimators': int(min(300.0, 0.25 * (len(spl) - 1))) } model = self.base_model(**opt) model = sk_pip.Pipeline([ ('feature_selection', _SelectFromModel(model, '0.8*median', in_mask=(1,))), ('classification', model) ]) model.fit(spl[:, 1:-1], spl[:, -1]) self.cold = model.steps[-1][-1] self.mask_cold = np.where(model.steps[0][-1]._get_support_mask())[0] + 1 return self
def _filter_samples(spl, on_engine, thermostat): b = ~((np.abs(spl[:, -1]) <= 0.001) & on_engine[1:]) b[:co2_utl.argmax(on_engine)] = False b[co2_utl.argmax(thermostat < spl[:, 0]):] = True return spl[b]
def fit(self, idle_engine_speed, on_engine, temperature_derivatives, temperatures, *args): """ Calibrates an engine temperature regression model to predict engine temperatures. This model returns the delta temperature function of temperature (previous), acceleration, and power at the wheel. :param idle_engine_speed: Engine speed idle median and std [RPM]. :type idle_engine_speed: (float, float) :param on_engine: If the engine is on [-]. :type on_engine: numpy.array :param temperature_derivatives: Derivative temperature vector [°C]. :type temperature_derivatives: numpy.array :param temperatures: Temperature vector [°C]. :type temperatures: numpy.array :return: The calibrated engine temperature regression model. :rtype: ThermalModel """ spl = _build_samples(temperature_derivatives, temperatures, *args) self.thermostat = self._identify_thermostat(spl, idle_engine_speed) spl = _filter_samples(spl, on_engine, self.thermostat) opt = { 'random_state': 0, 'max_depth': 2, 'n_estimators': int(min(300, 0.25 * (len(spl) - 1))), 'loss': 'huber', 'alpha': 0.99 } model = co2_utl._SafeRANSACRegressor( base_estimator=self.base_model(**opt), random_state=0, min_samples=0.85, max_trials=10) model = sk_pip.Pipeline([('feature_selection', _SelectFromModel(model, '0.8*median', in_mask=(0, 2))), ('classification', model)]) model.fit(spl[:, :-1], spl[:, -1]) self.model = model.steps[-1][-1] self.mask = np.where(model.steps[0][-1]._get_support_mask())[0] self.min_temp = spl[:, 0].min() spl = spl[:co2_utl.argmax(self.thermostat <= spl[:, 0])] if not spl.any(): self.min_temp = -float('inf') return self spl = spl[:co2_utl.argmax(np.percentile(spl[:, 0], 60) <= spl[:, 0])] opt = { 'random_state': 0, 'max_depth': 2, 'n_estimators': int(min(300, 0.25 * (len(spl) - 1))), 'loss': 'huber', 'alpha': 0.99 } model = self.base_model(**opt) model = sk_pip.Pipeline([('feature_selection', _SelectFromModel(model, '0.8*median', in_mask=(1, ))), ('classification', model)]) model.fit(spl[:, 1:-1], spl[:, -1]) self.cold = model.steps[-1][-1] self.mask_cold = np.where( model.steps[0][-1]._get_support_mask())[0] + 1 return self
def identify_after_treatment_warm_up_phases( times, engine_speeds_out, engine_speeds_out_hot, on_idle, on_engine, idle_engine_speed, velocities, engine_starts, stop_velocity, is_hybrid=False): """ Identifies when engine speed is affected by the after treatment warm up [-]. :param times: Time vector [s]. :type times: numpy.array :param engine_speeds_out: Engine speed [RPM]. :type engine_speeds_out: numpy.array :param engine_speeds_out_hot: Engine speed at hot condition [RPM]. :type engine_speeds_out_hot: numpy.array :param on_idle: If the engine is on idle [-]. :type on_idle: numpy.array :param on_engine: If the engine is on [-]. :type on_engine: numpy.array :param idle_engine_speed: Engine speed idle median and std [RPM]. :type idle_engine_speed: (float, float) :param velocities: Velocity vector [km/h]. :type velocities: numpy.array :param engine_starts: When the engine starts [-]. :type engine_starts: numpy.array :param stop_velocity: Maximum velocity to consider the vehicle stopped [km/h]. :type stop_velocity: float :param is_hybrid: Is the vehicle hybrid? :type is_hybrid: bool :return: Phases when engine speed is affected by the after treatment warm up [-]. :rtype: numpy.array """ from .control import identify_engine_starts i, phases = np.where(on_idle)[0], np.zeros_like(times, int) start = engine_starts.copy() if is_hybrid: with np.errstate(divide='ignore', invalid='ignore'): r = engine_speeds_out[i] / engine_speeds_out_hot[i] b = ~co2_utl.get_inliers(r, 2, np.nanmedian, co2_utl.mad)[0] phases[i[b]] = 1 else: ds = np.abs(engine_speeds_out[i] - engine_speeds_out_hot[i]) phases[i[ds > idle_engine_speed[1]]] = 1 start |= identify_engine_starts(velocities > stop_velocity) for i, j in np.searchsorted(times, times[start, None] + [-2, 5 + dfl.EPS]): phases[i:j], start[i:j] = 0, True phases = co2_utl.median_filter(times, phases, 4) phases = co2_utl.clear_fluctuations(times, phases, 4).astype(bool) indices = co2_utl.index_phases(phases) if is_hybrid: indices = indices[(np.diff(times[indices], axis=1) > 10).ravel()][:1] else: b, f = identify_engine_starts(~on_engine), False for i, j in np.searchsorted(times, times[b, None] + [-5, 2 + dfl.EPS]): b[i:j] = f f = True b = (on_idle & ~start) | b | (times > np.min(times[on_engine]) + 200) indices = indices[:co2_utl.argmax(b[indices[:, 1]])] phases[:], n = False, len(times) for i, j in indices: while i and on_idle.take(i - 1, mode='clip'): i -= 1 phases[i:j + 1] = True return phases
def _set_alt_init_status(times, initialization_time, statuses): if initialization_time > 0: statuses[:co2_utl.argmax(times > (times[0] + initialization_time))] = 3 return statuses
def identify_alternator_initialization_time(alternator_currents, gear_box_powers_in, on_engine, accelerations, state_of_charges, alternator_statuses, times, alternator_current_threshold): """ Identifies the alternator initialization time delta [s]. :param alternator_currents: Alternator current vector [A]. :type alternator_currents: numpy.array :param gear_box_powers_in: Gear box power vector [kW]. :type gear_box_powers_in: numpy.array :param on_engine: If the engine is on [-]. :type on_engine: numpy.array :param accelerations: Vehicle acceleration [m/s2]. :type accelerations: numpy.array :param state_of_charges: State of charge of the battery [%]. .. note:: `state_of_charges` = 99 is equivalent to 99%. :type state_of_charges: numpy.array :param alternator_statuses: The alternator status (0: off, 1: on, due to state of charge, 2: on due to BERS) [-]. :type alternator_statuses: numpy.array :param times: Time vector [s]. :type times: numpy.array :param alternator_current_threshold: Alternator current threshold [A]. :type alternator_current_threshold: float :return: Alternator initialization time delta [s]. :rtype: float """ if alternator_statuses[0] == 1: s = alternator_currents < alternator_current_threshold n, i = len(on_engine), co2_utl.argmax((s[:-1] != s[1:]) & s[:-1]) i = min(n - 1, i) opt = { 'random_state': 0, 'max_depth': 2, 'loss': 'huber', 'alpha': 0.99 } spl = _build_samples(alternator_currents, state_of_charges, alternator_statuses, gear_box_powers_in, accelerations) j = min(i, int(n / 2)) opt['n_estimators'] = int(min(100, 0.25 * (n - j))) or 1 model = GradientBoostingRegressor(**opt) model.fit(spl[j:][:, :-1], spl[j:][:, -1]) err = np.abs(spl[:, -1] - model.predict(spl[:, :-1])) sets = np.array(co2_utl.get_inliers(err)[0], dtype=int)[:i] if sum(sets) / i < 0.5 or i > j: reg = DecisionTreeClassifier(max_depth=1, random_state=0) reg.fit(np.array((times[1:i + 1], )).T, sets) l, r = reg.tree_.children_left[0], reg.tree_.children_right[0] l, r = np.argmax(reg.tree_.value[l]), np.argmax(reg.tree_.value[r]) if l == 0 and r == 1: return reg.tree_.threshold[0] - times[0] elif r == 0 and not i > j: return times[i] - times[0] elif alternator_statuses[0] == 3: i = co2_utl.argmax(alternator_statuses != 3) return times[i] - times[0] return 0.0
def identify_service_battery_initialization_time( alternator_electric_powers, motive_powers, accelerations, service_battery_state_of_charges, service_battery_charging_statuses, times, service_battery_electric_powers_supply_threshold): """ Identifies the alternator initialization time delta [s]. :param alternator_electric_powers: Alternator electric power [kW]. :type alternator_electric_powers: numpy.array :param motive_powers: Motive power [kW]. :type motive_powers: numpy.array :param accelerations: Vehicle acceleration [m/s2]. :type accelerations: numpy.array :param service_battery_state_of_charges: State of charge of the service battery [%]. :type service_battery_state_of_charges: numpy.array :param service_battery_charging_statuses: Service battery charging statuses (0: Discharge, 1: Charging, 2: BERS, 3: Initialization) [-]. :type service_battery_charging_statuses: numpy.array :param times: Time vector [s]. :type times: numpy.array :param service_battery_electric_powers_supply_threshold: Service battery not charging power threshold [kW]. :type service_battery_electric_powers_supply_threshold: float :return: Service battery initialization time delta [s]. :rtype: float """ bats, p = service_battery_charging_statuses, motive_powers i = co2_utl.argmax(bats != 0) if bats[0] == 1 or (i and ((bats[:i] == 0) & (p[:i] == 0)).all()): s = service_battery_electric_powers_supply_threshold s = alternator_electric_powers < s n, i = len(times), int(co2_utl.argmax((s[:-1] != s[1:]) & s[:-1])) i = min(n - 1, i) # noinspection PyProtectedMember from ....engine._thermal import _build_samples, _XGBRegressor x, y = _build_samples(alternator_electric_powers, service_battery_state_of_charges, bats, p, accelerations) j = min(i, int(n / 2)) # noinspection PyArgumentEqualDefault model = _XGBRegressor(random_state=0, max_depth=2, n_estimators=int(min(100.0, 0.25 * (n - j))) or 1, objective='reg:squarederror').fit(x[j:], y[j:]) err = np.abs(y - model.predict(x)) sets = np.array(co2_utl.get_inliers(err)[0], dtype=int)[:i] if (i and sum(sets) / i < 0.5) or i > j: from sklearn.tree import DecisionTreeClassifier reg = DecisionTreeClassifier(max_depth=1, random_state=0) reg.fit(times[1:i + 1, None], sets) s, r = reg.tree_.children_left[0], reg.tree_.children_right[0] s, r = np.argmax(reg.tree_.value[s]), np.argmax(reg.tree_.value[r]) if s == 0 and r == 1: return reg.tree_.threshold[0] - times[0] elif r == 0 and not i > j: return times[i] - times[0] elif bats[0] == 3: i = co2_utl.argmax(bats != 3) return times[i] - times[0] return 0.0