Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
174 changes: 174 additions & 0 deletions docs/scenario_inputs.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,174 @@
# Pre-Race Simulation Scenario Inputs

This document separates inputs provided by a user from the configuration parameters that define a scenario.

## User-Defined Inputs

| User input | How it is provided | Maps to |
|---|---|---|
| Car parameters | `car_params.json` | `CarConfig` |
| Track | `--location` or prompt | `TrackConfig` |
| Strategy | `--strategy` or prompt | `RaceConfig.strategy` |
| Aggressiveness | `--aggressiveness` | `RaceConfig.aggressiveness` |
| Energy safety scale | Interactive prompt | `RaceConfig.energy_safety_scale` |
| Fixed-speed sweep | `--speed-sweep` | Planning settings |
| Planning study | `--plan` | Planning settings |
| Weather source | Currently set in code | Weather settings |
| Race times, SOC, speed limits, timestep | Currently set in code | `RaceConfig` |

*For Car Parameters, the program automatically searches in `car_params.json` in the project root and pulls the configs from there.*
## Config/Scenario Parameters

These are the fields a future scenario configuration should contain. Values marked optional can use the listed default.

### Car Configuration

Source: `car_params.json`

| Parameter | Units | Required | Affects |
|---|---:|---|---|
| `mass` | kg | Yes | Rolling resistance, Regen energy, total energy use |
| `battery_capacity` | Wh | Yes | Available battery energy, SOC changes |
| `solar_panel_area` | m² | Yes | Solar power collected |
| `solar_panel_efficiency` | fraction | Yes | Solar power collected |
| `electrical_efficiency` | fraction | Yes | Driving power consumption |
| `C_dA` | m² | Yes | Aerodynamic drag, energy use |
| `tire_pressure` | pressure units | Yes | Rolling resistance, energy use |
| `regen_efficiency` | fraction | Yes | Regen energy |
| `rho` | kg/m³ | Yes | Aerodynamic drag |
| `g` | m/s² | Yes | Rolling resistance |

### Track Configuration

| Parameter | Units | Required | Affects |
|---|---:|---|---|
| `name` | text | Yes | Report and plot labels |
| `file_path_name` | text | Yes | Track identifier and output filenames |
| `location` | text | Yes | Human-readable location |
| `latitude`, `longitude` | degrees | Yes | Weather API location |
| `lap_distance_km` | km | Yes | Distance and lap count |
| `timezone` | IANA timezone | Yes | Local race and weather times |

Available track IDs: `shenandoah_speedway`, `virginia_international_raceway`, `brainerd_international_raceway`.

### Race and Battery Conditions

| Parameter | Units | Required | Default | Affects |
|---|---:|---|---:|---|
| `start_time_hour` | local hour | Yes | `10.0` | Race duration, weather window |
| `end_time_hour` | local hour | Yes | `18.0` | Race duration, weather window |
| `start_soc` | fraction | Yes | `1.0` | Starting energy, achievable distance |
| `target_soc` | fraction | No | `0.10` | Planned energy budget, SOC trajectory |
| `min_soc` | fraction | No | `0.10` | Early-stop safety threshold |
| `energy_safety_scale` | fraction | No | `1.0` | Energy reserve |

### Weather Configuration

| Parameter | Type | Required | Default | Affects |
|---|---|---|---|---|
| `source` | `api` / `synthetic` | Yes | API | Weather data used |
| `race_date` | date | No | Auto-selected | Forecast date |
| `random_seed` | integer | No | `7` in sweeps | Synthetic-weather generation |
| `GHI`, `cloud_cover` | weather data | Generated or API-provided | None | Solar charging, SOC trajectory |

The current API uses Open-Meteo shortwave radiation and cloud cover. API failure falls back to synthetic weather.

### Strategy and Speed

| Parameter | Units / values | Required | Default | Affects |
|---|---|---|---|---|
| `strategy` | `pi`, `stepped`, `interval-hold`, `fixed` | Yes | `pi` | Speed strategy |
| `aggressiveness` | scalar | No | Strategy-specific | Controller response strength |
| `fixed_speed_mps` | m/s | No | `15.0` | Fixed-strategy speed |
| `min_speed_mps` | m/s | No | `4.0` | Lower speed limit |
| `max_speed_mps` | m/s | No | `35.0` | Upper speed limit |
| `initial_speed_mps` | m/s | No | `20.0` | *Currently unused* |

Planning aggressiveness defaults: `pi=1.5`, `stepped=1.2`, `interval-hold=1.0`, `fixed=1.0`.

### Simulation and Planning

| Parameter | Type | Required | Default | Affects |
|---|---|---|---|---|
| `time_step_minutes` | minutes | No | `1.0` | Simulation update frequency |
| `use_api_weather` | boolean | No | `True` | Weather data source |
| `planning_enabled` | boolean | No | `False` | Single run versus planning study |
| `strategies` | list | No | All strategies | Strategies compared |
| `fixed_speed_values_mph` | list | No | `10`-`46`, step `2` | Speeds compared |

## Expected Planning Outputs

- Best fixed speed and strategy recommendation
- Total laps and distance
- Final and minimum SOC
- Average, minimum, and maximum speed
- Full-window completion status
- Time and laps when minimum SOC was reached

### Example Scenario Outlines
The following are examples of format files that can be implemented as YAML.

1. Scenario 1:
- Track: Shenandoah Raceway
- Strategy: fixed-speed sweep strategy comparison

```
scenario:
name: Shenandoah fixed-speed sweep
car_params: car_params.json
track: shenandoah_speedway

mode: sweep

race:
start_time_hour: 10.0
end_time_hour: 18.0
start_soc: 1.0
target_soc: 0.10
min_soc: 0.10

weather:
source: api

strategy:
name: fixed
aggressiveness: 1.0

planning:
fixed_speed_values_mph: [18, 22, 26, 30, 34, 38]

simulation:
time_step_minutes: 1.0
```

2. Scenario 2:
- Track: Brainerd
- Strategy: PI with aggressiveness = 0.9.

```
scenario:
name: Brainerd PI controller run
car_params: car_params.json
track: brainerd_international_raceway

mode: strategy

race:
start_time_hour: 10.0
end_time_hour: 18.0
start_soc: 1.0
target_soc: 0.10
min_soc: 0.10

strategy:
name: pi
aggressiveness: 0.9
min_speed_mps: 4.0
max_speed_mps: 35.0

weather:
source: api

simulation:
time_step_minutes: 1.0
```
4 changes: 4 additions & 0 deletions sim/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
@dataclass
class TrackConfig:
name: str
file_path_name: str
location: str
latitude: float
longitude: float
Expand Down Expand Up @@ -143,6 +144,7 @@ def get_available_tracks() -> List[TrackConfig]:
return [
TrackConfig(
name="Shenandoah Speedway",
file_path_name="shenandoah_speedway",
location="Page County, Virginia",
latitude=38.5110,
longitude=-78.6359,
Expand All @@ -151,6 +153,7 @@ def get_available_tracks() -> List[TrackConfig]:
),
TrackConfig(
name= "Virginia International Raceway (Patriot Course)",
file_path_name="virginia_international_raceway",
location="Alton, Virginia",
latitude=36.5666,
longitude=-79.2058,
Expand All @@ -159,6 +162,7 @@ def get_available_tracks() -> List[TrackConfig]:
),
TrackConfig(
name= "Brainerd International Raceway (Donnybrooke Course)",
file_path_name="brainerd_international_raceway",
location="Brainerd, Minnesota",
latitude=46.4176,
longitude=-94.2853,
Expand Down
40 changes: 22 additions & 18 deletions sim/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,8 @@ def parse_args():
parser = argparse.ArgumentParser(description="Modular laps race simulator")
parser.add_argument(
"--location",
choices=["shenandoah"],
default="shenandoah",
choices=["shenandoah_speedway", "virginia_international_raceway", "brainerd_international_raceway"],
default=None,
help="Race location selection (currently only Shenandoah)",
)
parser.add_argument(
Expand Down Expand Up @@ -126,22 +126,26 @@ def main():
car = CarConfig()
print("Using default car parameters")

print("Choose a track to test on:")
for i in range(len(tracks)):
print(f"({i+1}) {tracks[i].name}")
num = 1
while True:
inp = input()
if inp.isdigit():
num = int(inp)
if num <= 0 or num > len(tracks):
print("Invalid int")
else:
if args.location is not None:
track = next(track for track in tracks
if track.file_path_name == args.location)
else:
print("Choose a track to test on:")
for i, available_track in enumerate(tracks, start=1):
print(f"({i}) {available_track.name}")

num = 1
while True:
inp = input()
if inp.isdigit():
num = int(inp)
if num <= 0 or num > len(tracks):
print("Invalid int")
else:
break
elif inp == "":
break
elif inp == "":
break

track = tracks[num-1]
track = tracks[num-1]

if args.plan:
base_race = RaceConfig(
Expand Down Expand Up @@ -231,7 +235,7 @@ def main():
reporter.print_summary()

output_dir = os.path.join("plots", "laps_modular")
prefix = f"shenandoah_{selected_strategy}"
prefix = f"{track.file_path_name}_{selected_strategy}"
plotter = SimulationPlotter(results, track)
saved = save_all_plots(plotter, output_dir, prefix)

Expand Down