suboptimumg.vehicle.powertrain.powertrain#

class suboptimumg.vehicle.powertrain.powertrain.Motor(vehicle_model)[source]#

Bases: object

Models motor torque output, efficiency, and power limits.

Notes

The efficiency map, rpm/torque normalization parameters, and the power-limit grids are precomputed once at construction time (when use_efficiency_lut is set) so that the runtime hot path only needs a single np.interp lookup instead of a bisection loop. Call build_power_limit_table again if motor parameters are mutated at runtime.

Parameters:

vehicle_model (VehicleModel)

build_power_limit_table(n_rpm=200)[source]#

Precompute the DC-power-limited max motor torque at each rpm.

Parameters:

n_rpm (int) – Number of RPM points to precompute between 0 and max_rpm.

Return type:

None

Notes

At a given rpm, the binding DC constraint is tau * omega / eta_elec(rpm, tau) <= pow_lim, which is implicit in tau because eta_elec depends on tau via the LUT. This inverts the constraint once by bisecting tau in [0, tau_curve(rpm)] at each rpm in a fixed grid, then looks the result up with np.interp at runtime.

At rpm=0 there is no power binding (omega=0 implies P_DC=0 for any tau), so the static torque curve dominates. Where the static curve already fits under pow_lim, no inversion is needed (this also provides a cheap early-out when full torque is already under the power limit at a given rpm). The bisection itself relies on P_DC(tau) being non-decreasing in tau, because eta_elec is bounded (eval_efficiency_map clips to [0.66, 0.99]), so the tau term dominates as tau approaches 0.

Rebuild this table if pow_lim, moc_efficiency, or the LUT itself changes after construction.

calculate_max_ground_force_and_motor_power(v, ratio)[source]#

Calculates force and power output by the motor.

Parameters:
  • v (float) – Velocity of the vehicle (m/s)

  • ratio (float) – Gear ratio

Returns:

  • ground_force (float) – Force at the ground (N)

  • motor_power (float) – Motor shaft power output (W)

Return type:

tuple[float, float]

Notes

The torque the motor can deliver is constrained by two things: the static torque curve tau_curve(rpm), and the DC-bus power limit pow_lim, via tau * omega / eta_elec(rpm, tau) <= pow_lim, which is circular in tau because eta_elec depends on tau. When use_efficiency_lut is True this is resolved by an inverse lookup built once at init in build_power_limit_table.

Only chain/diff efficiencies sit between shaft and wheel, so the wheel torque uses mechanical_efficiency (not the full chain). The inverter and motor losses are upstream of the shaft and affect battery draw, not wheel torque.

electrical_efficiency(rpm, torque)[source]#

Loss factor between DC bus and motor shaft.

Parameters:
  • rpm (float) – Motor RPM (used if LUT is enabled)

  • torque (float) – Motor torque (used if LUT is enabled)

Returns:

Motor efficiency * MOC efficiency

Return type:

float

Notes

Covers the inverter (moc_efficiency) and the motor itself. When an efficiency LUT is in use and both rpm and torque are supplied, the motor’s contribution is pulled from the (rpm, torque) map; otherwise the scalar motor_efficiency is used.

eval_efficiency_map(rpm, torque)[source]#

Evaluate the 2D efficiency map at a given (rpm, torque) point.

Parameters:
  • rpm (float) – Motor RPM

  • torque (float) – Motor torque

Returns:

Motor efficiency (0.66 to 0.99)

Return type:

float

Notes

Inputs outside the fitted rpm/torque range are clamped to the nearest in-range value before evaluating the polynomial, and the result is scaled down by an exponential penalty based on how far outside the range the original inputs were.

fit_efficiency_data(points, degv, degt)[source]#

Fit a 2D polynomial z = f(x, y) to data points [[x, y, z], …].

Parameters:
  • points (list of lists) – Each inner list is [rpm, torque, efficiency] for a data point.

  • degv (int) – Degree of the polynomial in the rpm (x) direction.

  • degt (int) – Degree of the polynomial in the torque (y) direction.

Returns:

Coefficient matrix C[i,j] for x^i y^j.

Return type:

NDArray[np.float64]

Notes

If the efficiency surface has an especially unusual shape, a higher fit degree may be needed. Keep degrees even, and as low as possible, to limit evaluation complexity.

get_torque_at_rpm(motor_rpm)[source]#

Get motor torque at a given RPM using piecewise function.

The torque curve has three regions: 1. Flat region (0 to fw_rpm): constant max torque 2. Linear decay (fw_rpm to max_rpm): torque decreases linearly 3. Zero region (above max_rpm): no torque

Parameters:

motor_rpm (float) – Motor RPM

Returns:

Motor torque at the given RPM (Nm)

Return type:

float

mechanical_efficiency()[source]#

Loss factor between motor shaft and wheel.

Returns:

Combined chain and differential efficiency (0.0 to 1.0)

Return type:

float

Notes

Only the components that physically sit downstream of the shaft act here: the chain/belt and the diff. The inverter and motor losses are electrical and do not reduce wheel torque; they show up as extra DC current draw and are accounted for in electrical_efficiency.

powertrain_efficiency(rpm, torque)[source]#

Full DC-bus-to-ground efficiency, used by callers converting between battery power and wheel power (or vice versa).

Parameters:
  • rpm (float) – Motor RPM (used if efficiency_method is ‘indiv’)

  • torque (float) – Motor torque (used if efficiency_method is ‘indiv’)

Returns:

Overall powertrain efficiency (0.0 to 1.0)

Return type:

float

Notes

Equals electrical_efficiency * mechanical_efficiency when in ‘indiv’ mode. In ‘sys’ mode the lumped system_efficiency parameter is used directly. Diff efficiency is currently fixed at 100% (TODO).

v_to_rpm(v, ratio)[source]#

Convert vehicle velocity to motor RPM given the gear ratio.

Parameters:
  • v (float) – Velocity of the vehicle (m/s)

  • ratio (float) – Gear ratio

Returns:

Motor RPM

Return type:

float

class suboptimumg.vehicle.powertrain.powertrain.Powertrain(vehicle_model)[source]#

Bases: object

Models the full powertrain, composed of a motor.

Parameters:

vehicle_model (VehicleModel)