Source code for suboptimumg.compsim.custom_run

import enum
from enum import Enum

from ..log_analysis import (
    CUMULATIVE_DISTANCE,
    GROUND_SPEED,
    POS_X,
    POS_Y,
    add_cumulative_distance,
)
from ..plotting.gps_visualization import (
    plot_time_delta_comparison_traces,
    plot_track_heatmap,
)
from ..plotting.plotting_constants import (
    ColorbarConfig,
    FontConfig,
    LayoutConfig,
)
from ..track import *
from ..vehicle import Car
from .lap import *
from .models import *
from .utils import energy_data


[docs] class OverlayOptions(str, Enum): VELOCITY = "lap_vels" ACCELERATION = "lap_accs" MOTOR_TORQUE = "lap_eff_motor_torques" POWER = "lap_powers"
[docs] class CustomRun: def __init__( self, mycar: Car, track: Track, ): self.mycar = mycar self.track = track self.sim_results_no_coast: LapsimResults | None = None self.sim_results_coast: LapsimResults | None = None
[docs] def run( self, extract_internal_data: bool = False, initial_velocity: float = -1 ) -> LapsimResults: """ Simulates a run along the custom track. Sets the sim_results attribute for future use. Parameters ---------- extract_internal_data : bool, optional Whether to extract internal data during the simulation, by default False. initial_velocity : float, optional Starting velocity seed (m/s). ``-1`` (default) lets the solver pick seeds purely from the v_max profile. Returns ------- LapsimResults Results from running the custom track. """ print("Running simulation on custom track...") self.sim_results_no_coast = lapsim( mycar=self.mycar, track=self.track, use_coast=False, extract_internal_data=extract_internal_data, initial_velocity=initial_velocity, ) self.sim_results_coast = lapsim( mycar=self.mycar, track=self.track, use_coast=True, extract_internal_data=extract_internal_data, initial_velocity=initial_velocity, ) return self.sim_results_no_coast, self.sim_results_coast
[docs] def print_results_summary(self) -> None: """ Print a summary of the custom run results. """ if self.sim_results_no_coast is None or self.sim_results_coast is None: self.run() distance = round(self.track.cumulative_dist[-1], 2) print(f"{'Distance:':<10} {str(distance) + ' m':<10} ") time_no_coast = round(self.sim_results_no_coast.lap_t[-1], 2) time_coast = round(self.sim_results_coast.lap_t[-1], 2) _, regened_energy_no_coast, consumed_energy_no_coast = energy_data( self.sim_results_no_coast.lap_t, self.sim_results_no_coast.lap_powers, ) _, regened_energy_coast, consumed_energy_coast = energy_data( self.sim_results_coast.lap_t, self.sim_results_coast.lap_powers ) print("\nNO COAST") print(f"{'Laptime:':<10} {str(time_no_coast) + ' s':<10}") print( f"{'Net Energy:':<10} {str(round(consumed_energy_no_coast, 3)) + ' kWh':<10} {'Regen:':<8} {str(round(regened_energy_no_coast, 3)) + ' kWh':<10}" ) print("\nCOAST") print(f"{'Laptime:':<10} {str(time_coast) + ' s':<10}") print( f"{'Net Energy:':<10} {str(round(consumed_energy_coast, 3)) + ' kWh':<10} {'Regen:':<8} {str(round(regened_energy_coast, 3)) + ' kWh':<10}" )
[docs] def plot_real_lap_comparison( self, real_lap_data: SingleRunData, real_data_key: str, qss_var: OverlayOptions, *, layout_config: LayoutConfig = DEFAULT_LAYOUT_CONFIG, font_config: FontConfig = DEFAULT_FONT_CONFIG, colorbar_config: ColorbarConfig = DEFAULT_COLORBAR_CONFIG, ) -> go.Figure: """ Prints a comparison of the simulated lap with a real lap(s) from PERDA. Parameters ---------- real_lap_data : SingleRunData SingleRunData representing a single real lap to compare against. real_data_key : str The key for the real lap data to use for comparison. qss_var : OverlayOptions The QSS variable to overlay on the plot. layout_config : LayoutConfig, optional font_config : FontConfig, optional colorbar_config : ColorbarConfig, optional """ missing = [c for c in (POS_X, POS_Y) if c not in real_lap_data] if missing: raise KeyError( f"plot_real_lap_comparison: missing variables(s) {missing}.\n" f"Try running preprocess_gps on the real_lap_data" ) if self.sim_results_no_coast is None or self.sim_results_coast is None: self.run() di = real_lap_data[real_data_key] _, di_aligned = left_join_data_instances(real_lap_data[POS_X], [di]) qss_data = getattr(self.sim_results_coast, qss_var.value) return plot_track_heatmap( baseline_pos_x=self.track.x_m, baseline_pos_y=self.track.y_m, baseline_var=qss_data, comparison_pos_x=real_lap_data[POS_X].value_np, comparison_pos_y=real_lap_data[POS_Y].value_np, comparison_var=di_aligned.value_np, variable_name=qss_var.name, baseline_label=f"{qss_var.value} (QSS)", comparison_label=f"{real_data_key} (Real Data)", title=f"Simulated {qss_var.name} vs Real Lap Data", layout_config=layout_config, font_config=font_config, colorbar_config=colorbar_config, )
[docs] def plot_real_lap_time_delta_traces( self, real_laps: list[SingleRunData], real_data_key: str, qss_var: OverlayOptions, layout_config: LayoutConfig = DEFAULT_LAYOUT_CONFIG, font_config: FontConfig = DEFAULT_FONT_CONFIG, ) -> go.Figure: """ Plots comparisons of the simulated lap with multiple real laps from PERDA. Parameters ---------- real_laps : list[SingleRunData] List of SingleRunData representing real laps to compare against. real_data_key : str The key for the real lap data to use for comparison. qss_var : OverlayOptions The QSS variable to overlay on the plot. layout_config : LayoutConfig, optional font_config : FontConfig, optional colorbar_config : ColorbarConfig, optional """ missing = [i + 1 for i, lap in enumerate(real_laps) if GROUND_SPEED not in lap] if missing: raise KeyError( f"plot_real_lap_comparison: laps missing groundspeed variables {missing} (1-indexed).\n" f"Try running add_groundspeed on all real_laps" ) if self.sim_results_no_coast is None or self.sim_results_coast is None: self.run() for lap in real_laps: if CUMULATIVE_DISTANCE not in lap: add_cumulative_distance(lap) laps = { "QSS": ( self.track.get_dist_from_start_array(), getattr(self.sim_results_coast, qss_var.value), self.sim_results_coast.lap_vels, ) } for i, lap in enumerate(real_laps): cum_dist, vel, var = left_join_data_instances( lap[CUMULATIVE_DISTANCE], [lap[GROUND_SPEED], lap[real_data_key]] ) laps[f"Lap {i+1}"] = ( cum_dist.value_np, vel.value_np, var.value_np, ) return plot_time_delta_comparison_traces( laps=laps, variable_name=real_data_key, reference_lap="QSS", layout_config=layout_config, font_config=font_config, )