Add rate-map battery model and examples#6
Open
karakayahuseyin wants to merge 12 commits into
Open
Conversation
There was a problem hiding this comment.
Pull request overview
This PR introduces a lightweight, manufacturer-data-driven battery modeling layer (fixed-voltage and rate-map) and wires it into the propulsion operating-point solver so battery voltage/current outputs reflect the active battery model and state of charge.
Changes:
- Added
pythrust.batterymodels (FixedVoltageBattery,RateMapBattery) plusBatteryState/BatteryPoint, including JSON dataset loading and mission stepping utilities. - Integrated dynamic battery voltage behavior into
PropulsionSolver, expandedOperatingPointto include battery voltage/current/C-rate/efficiency, and updated OpenMDAO wrapper outputs. - Added battery-focused tests, examples, and expanded documentation/MkDocs nav to cover the new battery model and refreshed visuals.
Reviewed changes
Copilot reviewed 37 out of 43 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| tests/test_solver.py | Adds solver assertions + new tests for rate-map battery integration behavior. |
| tests/test_models.py | Updates imports to new dataclass module structure; extends OperatingPoint test fields. |
| tests/test_battery.py | New unit tests for fixed-voltage aliasing, rate-map point evaluation, stepping, and JSON loading. |
| scripts/generate_readme_plots.py | Refreshes README plot generation and adds a rate-map mission plot. |
| README.md | Switches images to repo-relative paths and updates “Feature Visuals” section labeling. |
| pythrust/propulsion/solver.py | Integrates battery state/point evaluation into the RPM root solve and exposes battery outputs on OperatingPoint. |
| pythrust/propulsion/models/system.py | New SystemSpec module as part of dataclass reorganization. |
| pythrust/propulsion/models/propeller.py | New PropellerSpec module as part of dataclass reorganization. |
| pythrust/propulsion/models/operating_point.py | New OperatingPoint module with added battery output fields. |
| pythrust/propulsion/models/motor.py | New MotorSpec module as part of dataclass reorganization. |
| pythrust/propulsion/models/battery.py | Adds compatibility alias BatterySpec = FixedVoltageBattery. |
| pythrust/propulsion/models/init.py | Re-exports reorganized propulsion dataclasses. |
| pythrust/propulsion/models.py | Removes monolithic models module in favor of the models/ package. |
| pythrust/openmdao/components.py | Updates OpenMDAO output to use op.battery_current_a directly. |
| pythrust/battery/state.py | Introduces BatteryState and BatteryPoint dataclasses. |
| pythrust/battery/rate_map.py | Adds equivalent-circuit rate-map battery model + JSON loader + stepping utilities. |
| pythrust/battery/fixed.py | Adds fixed-voltage battery model replacing the historical BatterySpec. |
| pythrust/battery/init.py | Exposes public battery API surface. |
| mkdocs.yml | Enables Markdown extensions needed for new docs layout and adds battery docs to nav. |
| examples/simulate_pybamm_mission.py | Removes PyBaMM-based example script. |
| examples/select_motor.py | Replaced by the renamed/updated motor selection example. |
| examples/select_motor_from_database.py | New updated motor selection example using OpenMDAO + database search. |
| examples/rate_map_battery_point_states.py | New example showing point-state queries on the rate-map battery model. |
| examples/rate_map_battery_mission.py | New example coupling RateMapBattery to PropulsionSolver over mission segments. |
| examples/optimize_and_plot_propulsion.py | Replaced by the updated OpenMDAO hover optimization example. |
| examples/openmdao_hover_optimization.py | New/updated OpenMDAO optimization + sweep example with refreshed plotting. |
| examples/calibrate_system_resistance.py | Updates calibration example to use FixedVoltageBattery and improves CLI instructions/output. |
| docs/usage.md | Updates solver usage docs to include battery models/state + new fields + mermaid diagram. |
| docs/theory.md | Extends theory to include battery model equations and updated coupled equilibrium expression. |
| docs/motor_calibration.md | Updates battery import/usage for calibration workflow. |
| docs/index.md | Refreshes landing page structure and feature visuals including battery capability. |
| docs/getting_started.md | Updates getting started snippets and example commands to new scripts/battery API. |
| docs/examples.md | Reorganizes examples page and documents the new battery examples. |
| docs/development.md | Updates development guide example commands and plot regeneration steps. |
| docs/battery_model.md | New detailed battery model documentation (fixed-voltage + rate-map + dataset format). |
| docs/api_reference.md | Adds battery model API reference details and documents new OperatingPoint fields. |
| data/batteries/example_liion_cell.json | Adds synthetic Li-ion cell dataset used by tests and examples. |
Comments suppressed due to low confidence (1)
pythrust/propulsion/solver.py:263
- The infeasibility checks overwrite
reasonas they run, so a later check (e.g., battery infeasible / invalid efficiency) can mask an earlier, more direct failure likecurrent_limit. This makesinfeasible_reasonnon-deterministic with respect to severity/priority and can hide the actual first constraint violated.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Comment on lines
+5
to
+24
| from dataclasses import dataclass | ||
| from typing import Optional | ||
|
|
||
|
|
||
| @dataclass(frozen=True) | ||
| class BatteryState: | ||
| """Battery state for mission or point-performance analysis.""" | ||
|
|
||
| soc: float = 1.0 | ||
|
|
||
| def __post_init__(self) -> None: | ||
| if self.soc < 0.0 or self.soc > 1.0: | ||
| raise ValueError("soc must be between 0 and 1") | ||
|
|
||
| @classmethod | ||
| def from_dod(cls, dod: float) -> "BatteryState": | ||
| """Build a battery state from depth of discharge.""" | ||
| if dod < 0.0 or dod > 1.0: | ||
| raise ValueError("dod must be between 0 and 1") | ||
| return cls(soc=1.0 - dod) |
Comment on lines
+231
to
+242
| if cell_current_a > self.max_current_a: | ||
| feasible = False | ||
| reason = "current_limit" | ||
| if cell_voltage_v < self.cutoff_voltage_v: | ||
| feasible = False | ||
| reason = "voltage_cutoff" | ||
| if cell_voltage_v > self.charge_voltage_v: | ||
| feasible = False | ||
| reason = "voltage_limit" | ||
| if state.dod < 0.0 or state.dod > 1.0: | ||
| feasible = False | ||
| reason = "state_limit" |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Validation
python -m pytest -q→ 45 passedmkdocs build --strict→ passedexamples/rate_map_battery_point_states.pyexamples/rate_map_battery_mission.pyexamples/calibrate_system_resistance.pyexamples/select_motor_from_database.pyexamples/openmdao_hover_optimization.pyNotes
BatterySpecremains as a compatibility alias forFixedVoltageBattery.Closes #3