def check_sign_currents(battery_currents, alternator_currents): """ Checks if battery currents and alternator currents have the right signs. :param battery_currents: Low voltage battery current vector [A]. :type battery_currents: numpy.array :param alternator_currents: Alternator currents [A]. :type alternator_currents: numpy.array :return: If battery and alternator currents have the right signs. :rtype: (bool, bool) """ #: Maximum allowed positive current for the alternator currents check [A]. import co2mpas.utils as co2_utl max_pos_curr = 1.0 b_c, a_c = battery_currents, alternator_currents a = co2_utl.reject_outliers(a_c, med=np.mean)[0] a = a <= max_pos_curr c = np.cov(a_c, b_c)[0][1] if c < 0: x = (a, a) elif c == 0: if any(b_c): x = (co2_utl.reject_outliers(b_c, med=np.mean)[0] <= 0, a) else: x = (True, a) else: x = (not a, a) return x
def check_sign_currents(battery_currents, alternator_currents): """ Checks if battery currents and alternator currents have the right signs. :param battery_currents: Low voltage battery current vector [A]. :type battery_currents: numpy.array :param alternator_currents: Alternator current vector [A]. :type alternator_currents: numpy.array :return: If battery and alternator currents have the right signs. :rtype: (bool, bool) """ b_c, a_c = battery_currents, alternator_currents a = co2_utl.reject_outliers(a_c, med=np.mean)[0] a = a <= con_vals.MAX_VALIDATE_POS_CURR c = np.cov(a_c, b_c)[0][1] if c < 0: x = (a, a) elif c == 0: if any(b_c): x = (co2_utl.reject_outliers(b_c, med=np.mean)[0] <= 0, a) else: x = (True, a) else: x = (not a, a) return x
def identify_service_battery_load(service_battery_loads, engine_powers_out, on_engine): """ Identifies service electric load (engine off and on) [kW]. :param service_battery_loads: Service battery load vector [kW]. :type service_battery_loads: numpy.array :param engine_powers_out: Engine power vector [kW]. :type engine_powers_out: numpy.array :param on_engine: If the engine is on [-]. :type on_engine: numpy.array :return: Service electric load (engine off and on) [kW]. :rtype: float, float """ rjo, mae = co2_utl.reject_outliers, co2_utl.mae p, b = service_battery_loads, engine_powers_out >= -dfl.EPS on = min(0.0, co2_utl.reject_outliers(p[on_engine & b], med=np.mean)[0]) off, b_off = on, b & ~on_engine & (p < 0) if b_off.any(): off = rjo(p[b_off], med=np.mean)[0] if on > off: p = p[b] if mae(p, on) > mae(p, off): on = off else: off = on return off, on
def identify_r_dynamic(velocity_speed_ratios, gear_box_ratios, final_drive_ratios): """ Identifies the dynamic radius of the wheels [m]. :param velocity_speed_ratios: Constant velocity speed ratios of the gear box [km/(h*RPM)]. :type velocity_speed_ratios: dict[int | float] :param gear_box_ratios: Gear box ratios [-]. :type gear_box_ratios: dict[int | float] :param final_drive_ratios: Final drive ratios [-]. :type final_drive_ratios: dict[int | float] :return: Dynamic radius of the wheels [m]. :rtype: float """ svr = gb_mec.calculate_speed_velocity_ratios(gear_box_ratios, final_drive_ratios, 1) r = [svr[k] * vs for k, vs in velocity_speed_ratios.items() if k] r_dynamic = co2_utl.reject_outliers(r)[0] return r_dynamic
def identify_r_dynamic(velocity_speed_ratios, gear_box_ratios, final_drive_ratios): """ Identifies the dynamic radius of the wheels [m]. :param velocity_speed_ratios: Constant velocity speed ratios of the gear box [km/(h*RPM)]. :type velocity_speed_ratios: dict[int | float] :param gear_box_ratios: Gear box ratios [-]. :type gear_box_ratios: dict[int, float | int] :param final_drive_ratios: Final drive ratios [-]. :type final_drive_ratios: dict[int, float | int] :return: Dynamic radius of the wheels [m]. :rtype: float """ from co2mpas.utils import reject_outliers from .gear_box.mechanical import calculate_speed_velocity_ratios svr = calculate_speed_velocity_ratios(gear_box_ratios, final_drive_ratios, 1) r = [svr[k] * vs for k, vs in velocity_speed_ratios.items() if k] r_dynamic = reject_outliers(r)[0] return r_dynamic
def identify_service_battery_capacity(times, service_battery_currents, service_battery_state_of_charges): """ Identify service battery capacity [Ah]. :param times: Time vector [s]. :type times: numpy.array :param service_battery_currents: Service battery current vector [A]. :type service_battery_currents: numpy.array :param service_battery_state_of_charges: State of charge of the service battery [%]. :type service_battery_state_of_charges: numpy.array :return: Service battery capacity [Ah]. :rtype: float """ soc = service_battery_state_of_charges ib = calculate_service_battery_currents_v1(1, times, soc) b = (ib < -dfl.EPS) | (ib > dfl.EPS) return co2_utl.reject_outliers(service_battery_currents[b] / ib[b])[0]
def identify_drive_battery_load(drive_battery_loads): """ Identifies drive electric load [kW]. :param drive_battery_loads: Drive battery load vector [kW]. :type drive_battery_loads: numpy.array :return: Drive electric load [kW]. :rtype: float """ return co2_utl.reject_outliers(drive_battery_loads)[0]
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]
def identify_r_dynamic_v1(velocities, gears, gear_box_speeds_in, gear_box_ratios, final_drive_ratios, stop_velocity): """ Identifies the dynamic radius of the wheels [m]. :param velocities: Vehicle velocity [km/h]. :type velocities: numpy.array :param gears: Gear vector [-]. :type gears: numpy.array :param gear_box_speeds_in: Gear box speed [RPM]. :type gear_box_speeds_in: numpy.array :param gear_box_ratios: Gear box ratios [-]. :type gear_box_ratios: dict[int, float | int] :param final_drive_ratios: Final drive ratios [-]. :type final_drive_ratios: dict[int, float | int] :param stop_velocity: Maximum velocity to consider the vehicle stopped [km/h]. :type stop_velocity: float :return: Dynamic radius of the wheels [m]. :rtype: float """ import numpy as np from co2mpas.utils import reject_outliers from .gear_box import mechanical as gb_mec svr = gb_mec.calculate_speed_velocity_ratios(gear_box_ratios, final_drive_ratios, 1.0) vsr = gb_mec.calculate_velocity_speed_ratios(svr) speed_x_r_dyn_ratios = gb_mec.calculate_gear_box_speeds_in( gears, velocities, vsr, stop_velocity) with np.errstate(divide='ignore', invalid='ignore'): r_dynamic = speed_x_r_dyn_ratios / gear_box_speeds_in r_dynamic = r_dynamic[np.isfinite(r_dynamic)] r_dynamic = reject_outliers(r_dynamic)[0] return r_dynamic
def identify_r_dynamic_v1(velocities, gears, engine_speeds_out, gear_box_ratios, final_drive_ratios, stop_velocity): """ Identifies the dynamic radius of the wheels [m]. :param velocities: Vehicle velocity [km/h]. :type velocities: numpy.array :param gears: Gear vector [-]. :type gears: numpy.array :param engine_speeds_out: Engine speed [RPM]. :type engine_speeds_out: numpy.array :param gear_box_ratios: Gear box ratios [-]. :type gear_box_ratios: dict[int | float] :param final_drive_ratios: Final drive ratios [-]. :type final_drive_ratios: dict[int | float] :param stop_velocity: Maximum velocity to consider the vehicle stopped [km/h]. :type stop_velocity: float :return: Dynamic radius of the wheels [m]. :rtype: float """ svr = gb_mec.calculate_speed_velocity_ratios(gear_box_ratios, final_drive_ratios, 1.0) vsr = gb_mec.calculate_velocity_speed_ratios(svr) speed_x_r_dyn_ratios = gb_mec.calculate_gear_box_speeds_in( gears, velocities, vsr, stop_velocity) r_dynamic = speed_x_r_dyn_ratios / engine_speeds_out r_dynamic = r_dynamic[~np.isnan(r_dynamic)] r_dynamic = co2_utl.reject_outliers(r_dynamic)[0] return r_dynamic
def identify_motor_p4_speed_ratio(wheel_speeds, motor_p4_speeds): """ Identifies motor P4 speed ratio. :param wheel_speeds: Rotating speed of the wheel [RPM]. :type wheel_speeds: numpy.array | float :param motor_p4_speeds: Rotating speed of motor P4 [RPM]. :type motor_p4_speeds: numpy.array | float :return: Motor P4 speed ratio [-]. :rtype: float """ b = wheel_speeds > 0 return co2_utl.reject_outliers(motor_p4_speeds[b] / wheel_speeds[b])[0]
def identify_upper_bound_engine_speed(gears, engine_speeds_out, idle_engine_speed): """ Identifies upper bound engine speed [RPM]. It is used to correct the gear prediction for constant accelerations (see :func:`co2mpas.model.physical.at_gear. correct_gear_upper_bound_engine_speed`). This is evaluated as the median value plus 0.67 standard deviation of the filtered cycle engine speed (i.e., the engine speeds when engine speed > minimum engine speed plus 0.67 standard deviation and gear < maximum gear). :param gears: Gear vector [-]. :type gears: numpy.array :param engine_speeds_out: Engine speed vector [RPM]. :type engine_speeds_out: numpy.array :param idle_engine_speed: Idle engine speed and its standard deviation [RPM]. :type idle_engine_speed: (float, float) :returns: Upper bound engine speed [RPM]. :rtype: float .. note:: Assuming a normal distribution then about 68 percent of the data values are within 0.67 standard deviation of the mean. """ max_gear = max(gears) idle_speed = idle_engine_speed[1] dom = (engine_speeds_out > idle_speed) & (gears < max_gear) m, sd = co2_utl.reject_outliers(engine_speeds_out[dom]) return m + sd * 0.674490
def identify_alternator_current_threshold(alternator_currents, velocities, on_engine, stop_velocity, alternator_off_threshold): """ Identifies the alternator current threshold [A] that identifies when the alternator is off. :param alternator_currents: Alternator current vector [A]. :type alternator_currents: numpy.array :param velocities: Velocity vector [km/h]. :type velocities: numpy.array :param on_engine: If the engine is on [-]. :type on_engine: numpy.array :param stop_velocity: Maximum velocity to consider the vehicle stopped [km/h]. :type stop_velocity: float :param alternator_off_threshold: Maximum negative current for being considered the alternator off [A]. :type alternator_off_threshold: float :return: Alternator current threshold [A]. :rtype: float """ b, l = np.logical_not(on_engine), -float('inf') if not b.any(): b, l = velocities < stop_velocity, alternator_off_threshold b &= alternator_currents < 0 if b.any(): return min(0.0, max(co2_utl.reject_outliers(alternator_currents[b])[0], l)) return 0.0
def identify_gear_box_mean_efficiency(gear_box_powers_in, gear_box_powers_out): """ Identify gear box mean efficiency [-]. :param gear_box_powers_in: Gear box power in vector [kW]. :type gear_box_powers_in: numpy.array :param gear_box_powers_out: Gear box power out vector [kW]. :type gear_box_powers_out: numpy.array :return: Gear box mean efficiency [-]. :rtype: float """ with np.errstate(divide='ignore', invalid='ignore'): eff = gear_box_powers_out / gear_box_powers_in b = eff > 1 eff[b] = 1 / eff[b] return reject_outliers(eff[np.isfinite(eff) & (eff >= 0)])[0]
def identify_speed_velocity_ratios(gears, velocities, gear_box_speeds_in, stop_velocity): """ Identifies speed velocity ratios from gear vector [h*RPM/km]. :param gears: Gear vector [-]. :type gears: numpy.array :param velocities: Velocity vector [km/h]. :type velocities: numpy.array :param gear_box_speeds_in: Gear box speed vector [RPM]. :type gear_box_speeds_in: numpy.array :param stop_velocity: Maximum velocity to consider the vehicle stopped [km/h]. :type stop_velocity: float :return: Speed velocity ratios of the gear box [h*RPM/km]. :rtype: dict """ ratios = gear_box_speeds_in / velocities ratios[velocities < stop_velocity] = 0 svr = { k: co2_utl.reject_outliers(ratios[gears == k])[0] for k in range(1, int(max(gears)) + 1) if k in gears } svr[0] = INF return svr
def fit(self, gears, velocities, velocity_speed_ratios, idle_engine_speed, stop_velocity): self.velocity_speed_ratios = velocity_speed_ratios idle = idle_engine_speed mvl = [np.array([idle[0] - idle[1], idle[0] + idle[1]])] for k in range(1, int(max(gears)) + 1): lm, on, vsr = [], None, velocity_speed_ratios[k] for i, b in enumerate(itertools.chain(gears == k, [False])): if not b and on is not None: v = velocities[on:i] lm.append([min(v), max(v)]) on = None elif on is None and b: on = i if lm: min_v, max_v = zip(*lm) lm = [sum(co2_utl.reject_outliers(min_v)), max(max_v)] mvl.append(np.array([max(idle[0], l / vsr) for l in lm])) else: mvl.append(mvl[-1].copy()) mvl = [[k, tuple(v * velocity_speed_ratios[k])] for k, v in reversed(list(enumerate(mvl[1:], 1)))] mvl[0][1] = (mvl[0][1][0], dfl.INF) mvl.append([0, (0, mvl[-1][1][0])]) for i, v in enumerate(mvl[1:]): v[1] = (v[1][0], max(v[1][1], mvl[i][1][0] + stop_velocity)) self.clear() # noinspection PyTypeChecker self.update(collections.OrderedDict(mvl)) return self
def identify_planetary_ratio(planetary_speeds_in, engine_speeds_out, final_drive_speeds_in): """ Calculates final drive speed [RPM]. :param planetary_speeds_in: Planetary speed vector [RPM]. :type planetary_speeds_in: numpy.array :param engine_speeds_out: Engine speed vector [RPM]. :type engine_speeds_out: numpy.array :param final_drive_speeds_in: Final drive speed in [RPM]. :type final_drive_speeds_in: float :return: Fundamental planetary speed ratio [-]. :rtype: numpy.array """ r = planetary_speeds_in - engine_speeds_out r /= engine_speeds_out - final_drive_speeds_in return co2_utl.reject_outliers(r)
def identify_electric_loads(alternator_nominal_voltage, battery_currents, alternator_currents, gear_box_powers_in, times, on_engine, engine_starts, alternator_start_window_width): """ Identifies vehicle electric load and engine start demand [kW]. :param alternator_nominal_voltage: Alternator nominal voltage [V]. :type alternator_nominal_voltage: float :param battery_currents: Low voltage battery current vector [A]. :type battery_currents: numpy.array :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 times: Time vector [s]. :type times: numpy.array :param on_engine: If the engine is on [-]. :type on_engine: numpy.array :param engine_starts: When the engine starts [-]. :type engine_starts: numpy.array :param alternator_start_window_width: Alternator start window width [s]. :type alternator_start_window_width: float :return: Vehicle electric load (engine off and on) [kW] and energy required to start engine [kJ]. :rtype: ((float, float), float) """ b_c, a_c = battery_currents, alternator_currents c = alternator_nominal_voltage / 1000.0 b = gear_box_powers_in >= 0 bL = b & np.logical_not(on_engine) & (b_c < 0) bH = b & on_engine off = min(0.0, c * co2_utl.reject_outliers(b_c[bL], med=np.mean)[0]) on = min(off, c * co2_utl.reject_outliers(b_c[bH] + a_c[bH], med=np.mean)[0]) loads = [off, on] start_demand = [] dt = alternator_start_window_width / 2 for i, j in _starts_windows(times, engine_starts, dt): p = b_c[i:j] * c # noinspection PyUnresolvedReferences p[p > 0] = 0.0 # noinspection PyTypeChecker p = np.trapz(p, x=times[i:j]) if p < 0: l = np.trapz(np.choose(on_engine[i:j], loads), x=times[i:j]) if p < l: start_demand.append(p - l) start_demand = -co2_utl.reject_outliers( start_demand)[0] if start_demand else 0.0 return (off, on), start_demand