def calculate_willans_factors(
co2_params_calibrated, engine_fuel_lower_heating_value, engine_stroke,
engine_capacity, min_engine_on_speed, fmep_model, engine_speeds_out,
engine_powers_out, times, velocities, accelerations, motive_powers,
engine_coolant_temperatures, missing_powers, angle_slopes):
"""
Calculates the Willans factors.
:param co2_params_calibrated:
CO2 emission model parameters (a2, b2, a, b, c, l, l2, t, trg).
The missing parameters are set equal to zero.
:type co2_params_calibrated: lmfit.Parameters
:param engine_fuel_lower_heating_value:
Fuel lower heating value [kJ/kg].
:type engine_fuel_lower_heating_value: float
:param engine_stroke:
Engine stroke [mm].
:type engine_stroke: float
:param engine_capacity:
Engine capacity [cm3].
:type engine_capacity: float
:param min_engine_on_speed:
Minimum engine speed to consider the engine to be on [RPM].
:type min_engine_on_speed: float
:param fmep_model:
Engine FMEP model.
:type fmep_model: FMEP
:param engine_speeds_out:
Engine speed vector [RPM].
:type engine_speeds_out: numpy.array
:param engine_powers_out:
Engine power vector [kW].
:type engine_powers_out: numpy.array
:param times:
Time vector [s].
:type times: numpy.array
:param velocities:
Velocity vector [km/h].
:type velocities: numpy.array
:param accelerations:
Acceleration vector [m/s2].
:type accelerations: numpy.array
:param motive_powers:
Motive power [kW].
:type motive_powers: numpy.array
:param engine_coolant_temperatures:
Engine coolant temperature vector [°C].
:type engine_coolant_temperatures: numpy.array
:param missing_powers:
Missing engine power [kW].
:type missing_powers: numpy.array
:param angle_slopes:
Angle slope vector [rad].
:type angle_slopes: numpy.array
:return:
Willans factors:
- av_velocities [km/h]
- av_slope [rad]
- distance [km]
- init_temp [°C]
- av_temp [°C]
- end_temp [°C]
- av_vel_pos_mov_pow [kw/h]
- av_pos_motive_powers [kW]
- sec_pos_mov_pow [s]
- av_neg_motive_powers [kW]
- sec_neg_mov_pow [s]
- av_pos_accelerations [m/s2]
- av_engine_speeds_out_pos_pow [RPM]
- av_pos_engine_powers_out [kW]
- engine_bmep_pos_pow [bar]
- mean_piston_speed_pos_pow [m/s]
- fuel_mep_pos_pow [bar]
- fuel_consumption_pos_pow [g/sec]
- willans_a [g/kWh]
- willans_b [g/h]
- specific_fuel_consumption [g/kWh]
- indicated_efficiency [-]
- willans_efficiency [-]
:rtype: dict
"""
from .engine import calculate_mean_piston_speeds
from .engine.fc import calculate_brake_mean_effective_pressures
av = np.average
w = np.zeros_like(times, dtype=float)
t = (times[:-1] + times[1:]) / 2
# noinspection PyUnresolvedReferences
w[0], w[1:-1], w[-1] = t[0] - times[0], np.diff(t), times[-1] - t[-1]
f = {
'av_velocities': av(velocities, weights=w), # [km/h]
'av_slope': av(angle_slopes, weights=w),
'has_sufficient_power': 1 - av(missing_powers != 0, weights=w),
'max_power_required': max(engine_powers_out + missing_powers)
}
f['distance'] = f['av_velocities'] * (times[-1] - times[0]) / 3600.0 # [km]
b = engine_powers_out >= 0
if b.any():
p = co2_params_calibrated.valuesdict()
_w = w[b]
av_s = av(engine_speeds_out[b], weights=_w)
av_p = av(engine_powers_out[b], weights=_w)
av_mp = av(missing_powers[b], weights=_w)
n_p = calculate_brake_mean_effective_pressures(
av_s, av_p, engine_capacity, min_engine_on_speed
)
n_s = calculate_mean_piston_speeds(av_s, engine_stroke)
f_mep, wfa = fmep_model(p, n_s, n_p, 1)[:2]
c = engine_capacity / engine_fuel_lower_heating_value * av_s
fc = f_mep * c / 1200.0
ieff = av_p / (fc * engine_fuel_lower_heating_value) * 1000.0
willans_a = 3600000.0 / engine_fuel_lower_heating_value / wfa
willans_b = fmep_model(p, n_s, 0, 1)[0] * c * 3.0
sfc = willans_a + willans_b / av_p
willans_eff = 3600000.0 / (sfc * engine_fuel_lower_heating_value)
f.update({
'av_engine_speeds_out_pos_pow': av_s, # [RPM]
'av_pos_engine_powers_out': av_p, # [kW]
'av_missing_powers_pos_pow': av_mp, # [kW]
'engine_bmep_pos_pow': n_p, # [bar]
'mean_piston_speed_pos_pow': n_s, # [m/s]
'fuel_mep_pos_pow': f_mep, # [bar]
'fuel_consumption_pos_pow': fc, # [g/sec]
'willans_a': willans_a, # [g/kW]
'willans_b': willans_b, # [g]
'specific_fuel_consumption': sfc, # [g/kWh]
'indicated_efficiency': ieff, # [-]
'willans_efficiency': willans_eff # [-]
})
b = motive_powers > 0
if b.any():
_w = w[b]
f['av_vel_pos_mov_pow'] = av(velocities[b], weights=_w) # [km/h]
f['av_pos_motive_powers'] = av(motive_powers[b], weights=_w) # [kW]
f['sec_pos_mov_pow'] = np.sum(_w) # [s]
b = accelerations > 0
if b.any():
_w = w[b]
f['av_pos_accelerations'] = av(accelerations[b], weights=_w) # [m/s2]
b = motive_powers < 0
if b.any():
_w = w[b]
f['av_neg_motive_powers'] = av(motive_powers[b], weights=_w) # [kW]
f['sec_neg_mov_pow'] = np.sum(_w) # [s]
f['init_temp'] = engine_coolant_temperatures[0] # [°C]
f['av_temp'] = av(engine_coolant_temperatures, weights=w) # [°C]
f['end_temp'] = engine_coolant_temperatures[-1] # [°C]
return f