Skip to content

Repository files navigation

EV Driver Behaviour Simulator 🚗⚡️

An agent-based simulator for modelling electric-vehicle (EV) charging behaviour across a heterogeneous driver population.

This repository is a submission for a Technical Exercise in an energy flexibility company. It focuses on delivering a flexible, reproducible environment that can generate both individual-level traces (plug-in times, state-of-charge) and population-level insights (load flexibility, SoC distributions).


🌟 Interactive Dashboard

Run a full simulation and explore the results instantly in a web-based dashboard.

# install uv
brew install uv

# create and activate the venv
uv venv
source .venv/bin/activate

# Install dependencies
uv sync

# Launch the UI
streamlit run dashboard.py

On the left, tweak:

  • Population size (10–1000 agents)
  • Simulation duration (1–30 days)
  • Random seed (reproducibility)
  • Which agent's trace to inspect
  • override the default config.py settings

Press Run Simulation and watch metrics & Plotly graphs populate in real time—no extra coding required.


🧩 Architecture

Module Responsibility
evsim/agent.py DriverAgent class: Manages agent state (SoC, plug status), coordinates component models, and handles events.
evsim/models/driving_model.py DrivingModel class: Handles daily driving energy planning and step-by-step energy consumption simulation based on agent archetype.
evsim/models/schedule_model.py ScheduleModel class: Manages plug-in/plug-out timing based on archetype schedules, randomness, and plug-in frequency logic.
evsim/models/charging_model.py ChargingModel class: Simulates energy addition to the battery when plugged in, considering charger power, efficiency, and optional tapering.
evsim/simulation.py Simulator class: Orchestrates the population of agents, manages simulation time, records events, and computes aggregate stats.
evsim/utils.py Helper functions for parsing, file I/O, time handling, and post-simulation flexibility calculations.
evsim/config.py Central configuration parameters for simulation behavior, constants, and file paths.
data/ev_archetypes.csv Defines statistical profiles for different driver types (mileage, battery/charger specs, schedules).
main.py CLI wrapper for running simulations.
dashboard.py Streamlit web application for interactive simulation runs and results exploration.

⚙️ How it Works

  1. Configuration & Archetypes: The simulation starts by loading parameters from evsim/config.py and driver archetypes from data/ev_archetypes.csv. Archetypes define statistical profiles for different driver types (e.g., "Commuter", "High Mileage") including annual mileage, battery/charger specs, and typical plug-in/out schedules.
  2. Agent Population: The Simulator creates a specified number of DriverAgent instances based on the loaded archetypes and their population mix. Each agent represents a single EV and driver.
  3. Time-Stepped Simulation: The Simulator advances time step by step (e.g., every 30 minutes) from the configured start to end date.
  4. Agent Behavior: In each time step, every DriverAgent updates its state:
    • Scheduling (ScheduleModel): Checks if it's time to plug in or out based on its archetype's schedule, plus configurable randomness (e.g., PLUG_TIME_STD_DEV_MINUTES, PROB_SKIP_PLUG_IN). Handles logic for infrequent plug-ins. (See: evsim/models/schedule_model.py)
    • Driving (DrivingModel): Plans daily trips based on annual mileage (scaled for weekday/weekend), generating random trip times/distances. If currently driving, consumes energy from the battery based on vehicle efficiency. (Note: Weekday vs. weekend driving patterns, like average trips and distances, can be adjusted in config.py). (See: evsim/models/driving_model.py)
    • Charging (ChargingModel): If plugged in, adds energy to the battery based on charger power (config.CHARGING_EFFICIENCY, config.ENABLE_CHARGING_TAPER). (See: evsim/models/charging_model.py)
    • State Update: Updates internal state like soc_percent, is_plugged_in, is_driving.
  5. Event & Data Logging: The Simulator listens for events (like 'plug' and 'unplug') generated by agents. It records these events, along with population-level statistics (average SoC, number plugged in, etc.) and optionally detailed agent states at each time step.
  6. Results: After the simulation finishes, the collected data (plug events, population stats, agent states) is available as pandas DataFrames and can be saved to CSV files in the results/ directory. Flexibility metrics can also be calculated, representing the potential time window (in hours) during which an EV's charging could be shifted without impacting the driver, based on plug duration and energy needs.
graph TD
    A[Start Simulation] --> B(Load Config & Archetypes);
    B --> C{Create Agent Population};
    C --> D{Initialize Time Step Loop};
    D --> E{For Each Agent};
    E -- Time Step --> F(ScheduleModel Update);
    F --> G(DrivingModel Update);
    G --> H(ChargingModel Update);
    H --> I(Update Agent State);
    I --> J(Log Events & Stats);
    E -- Next Agent --> F;
    J -- Next Time Step --> D;
    D -- Simulation End --> K(Generate Results);
    K --> L[End Simulation];
Loading

📝 Assumptions & Design Decisions

  • Daily Driving Energy Model: Instead of modeling individual trips, the simulation calculates a total daily driving energy need for each agent. This need is based on the agent's archetype (average daily kWh), scaled for weekday/weekend differences, and adjusted using a random factor drawn from a Normal distribution (controlled by config.TOTAL_DAILY_DISTANCE_STD_DEV). Energy is consumed incrementally during unplugged periods throughout the day. This simplifies the model while retaining daily variability.
  • Charging logic: Agents obey personal schedules but may skip with probability PROB_SKIP_PLUG_IN; SoC tapering mimics slower top-offs near target.
  • Target SoC variance: Normally distributed ±TARGET_SOC_STD_DEV_PERCENT to avoid unrealistic lock-step charging.
  • Focus vs scope: Prioritised behavioural richness over grid-side physics (no network constraints, tariffs). No external data dependencies—pure Python for easy review.

🔧 Extensibility

  • Add new archetypes by editing data/ev_archetypes.csv.
  • Add tariff optimisation by reading day-ahead prices inside DriverAgent.step().
  • Scale further via Dask / Ray for large agent populations or longer simulations.

🏛️ Design Analysis

Rationale for Current Architecture

  • Modularity & Separation of Concerns: The core components (Simulator, DriverAgent, and the individual models: ScheduleModel, DrivingModel, ChargingModel) have distinct responsibilities. This structure promotes clarity, testability, and easier modification. For example, enhancing driving logic primarily impacts evsim/models/driving_model.py, while changes to plug-in timing affect evsim/models/schedule_model.py.
  • Agent-Based Approach: Modeling individual DriverAgents captures heterogeneous behaviors and allows emergent population-level patterns (e.g., aggregate load profiles) to arise naturally from individual actions coordinated by their respective models.
  • Configurability: Centralizing parameters in evsim/config.py and agent profiles in data/ev_archetypes.csv enables easy experimentation with different scenarios without modifying core simulation logic.
  • Extensibility: The modular structure provides clear extension points. New behavioral models (e.g., price sensitivity) could be integrated into DriverAgent by adding new component models or modifying existing ones, and new driver types only require CSV updates.
  • Observability: Logging detailed events and statistics provides the necessary data for analysis, visualization (dashboard.py), and understanding simulation dynamics.

Potential Areas for Improvement

  • Model Sophistication:
    • Driving: Incorporate route specifics, traffic, standard driving cycles, or integrate real-world travel survey data (e.g., NHTS survey) for more detailed energy consumption, eg this paper. (See: evsim/models/driving_model.py)
    • Charging: Model charger types more explicitly, variable efficiency, battery degradation, or thermal effects. (See: evsim/models/charging_model.py)
  • Grid Interaction: Integrate models of grid constraints (maybe feeder capacity, transformer limits) or grid services (demand response, V2G) for power system studies.
  • Decision Making: Add logic for the driving agents to respond to dynamic electricity prices, or have some form of range anxiety.
  • Performance/Scalability: Explore parallelization techniques (e.g., Dask, Ray) for very large agent populations

✍️ Author Notes

My goal was to balance realism, clarity and extensibility—the dashboard lets stakeholders see the emergent behaviour instantly.

Feedback welcome! 🙌

About

Agent-based simulator for modelling electric-vehicle (EV) charging behaviour across a heterogeneous driver population.

Topics

Resources

Stars

Watchers

Forks

Releases

Packages

Contributors

Languages