https://github.com/snu-hanaro/static-fire-toolkit
Convert thrust/pressure data obtained from static fire tests into refined, analysis-ready outputs suitable for performance analysis, burn rate estimates, and flight prediction through data post-processing.
https://github.com/snu-hanaro/static-fire-toolkit
aerospace aerospace-engineering dataprocessing engineering rocket
Last synced: 2 days ago
JSON representation
Convert thrust/pressure data obtained from static fire tests into refined, analysis-ready outputs suitable for performance analysis, burn rate estimates, and flight prediction through data post-processing.
- Host: GitHub
- URL: https://github.com/snu-hanaro/static-fire-toolkit
- Owner: snu-hanaro
- License: mit
- Created: 2025-09-13T04:56:39.000Z (9 months ago)
- Default Branch: main
- Last Pushed: 2026-02-06T19:43:37.000Z (5 months ago)
- Last Synced: 2026-02-07T05:18:12.345Z (5 months ago)
- Topics: aerospace, aerospace-engineering, dataprocessing, engineering, rocket
- Language: Python
- Homepage:
- Size: 15 MB
- Stars: 0
- Watchers: 1
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
- Code of conduct: docs/CODE_OF_CONDUCT.md
- Citation: CITATION.bib
- Agents: AGENTS.md
Awesome Lists containing this project
README

[](https://github.com/snu-hanaro/static-fire-toolkit/blob/main/LICENSE)
[](https://pypi.org/project/static-fire-toolkit/)
[](https://semver.org/)
[](https://pypi.python.org/pypi/static-fire-toolkit)
[](https://github.com/snu-hanaro/static-fire-toolkit/issues)
[](https://github.com/snu-hanaro/static-fire-toolkit/actions?query=workflow%3ACI)
[](https://pepy.tech/projects/static-fire-toolkit?timeRange=threeMonths&category=version&includeCIDownloads=true&granularity=daily&viewType=line&versions=1.0.1%2C1.0.0)
[](https://github.com/snu-hanaro/static-fire-toolkit/releases)
[](https://doi.org/10.5281/zenodo.17218595)
**HANARO SFT (Static-Fire Toolkit)** is an open-source command-line toolkit developed by the [Seoul National University Rocket Team **HANARO**](https://hanaro.snu.ac.kr/).
It provides a standardized workflow for processing **static-fire test data** from amateur and research solid rocket motors, focusing on **data cleaning, performance analysis, burn rate estimation, and visualization**.
While the library can be imported in Python, the **initial releases focus on the CLI interface**, making it straightforward to use as a standalone tool in test workflows.
## Features
- **CLI-based workflow** — run analysis directly from the terminal
- **Data processing** — clean and normalize raw thrust/pressure sensor logs
- **Performance metrics** — compute impulse, burn time, chamber pressure statistics
- **Burn rate estimation** — regression-based analysis for solid propellants
- **Visualization** — generate thrust/pressure plots for reports and documentation
## Requirements
- Python 3 (3.10+ required)
- Packages:
- numpy (>=2.0)
- scipy (>=1.13)
- pandas (>=2.0)
- matplotlib (>=3.10)
- openpyxl (>=3.1) # pandas read_excel engine
## Installation
From PyPI:
```bash
python3 -m pip install static-fire-toolkit
```
Or install from source:
```bash
git clone https://github.com/snu-hanaro/static-fire-toolkit.git
cd static-fire-toolkit
python3 -m pip install -e .
```
## Usage
### Required Directory Layout
```sh
root/ # run sft here (or specify this path using the --root option)
├─ global_config.xlsx # global configs
├─ config.xlsx # per-test configs
├─ data/
│ ├─ _pressure_raw/ # input pressure raw CSVs
│ └─ _thrust_raw/ # input thrust raw CSVs
├─ results/
│ ├─ burnrate/ # calculated burnrate CSVs
│ ├─ burnrate_graph/ # burnrate PNG/GIF plots
│ ├─ pressure/ # processed pressure CSVs
│ ├─ pressure_graph/ # pressure PNG plots
│ ├─ thrust/ # processed thrust CSVs
│ └─ thrust_graph/ # thrust PNG plots
└─ logs/ # logs for debugging
```
All commands assume the root contains `data/_pressure_raw`, `data/_thrust_raw`, and `config.xlsx`.
### CLI
Basic workflow (see `examples/` for a runnable set):
```bash
# End-to-end: thrust -> pressure -> burnrate
sft [--root ] process [--expt ] # e.g. sft --root examples process [--expt KNSB_250220]
# Stage-by-stage
sft [--root ] thrust [--expt ] # e.g. sft --root examples thrust --expt KNSB_250220
sft [--root ] pressure [--expt ] # e.g. sft --root examples pressure --expt KNSB_250220
sft [--root ] burnrate [--expt ] # e.g. sft --root examples burnrate --expt KNSB_250220
```
Run `sft --help` and `sft [--root ] info` for more details.
#### Examples from this repo:
- Input samples: [`examples/data/_thrust_raw/`](https://github.com/snu-hanaro/static-fire-toolkit/tree/main/examples/data/_thrust_raw), [`examples/data/_pressure_raw/`](https://github.com/snu-hanaro/static-fire-toolkit/tree/main/examples/data/_pressure_raw/), [`examples/config.xlsx`](https://github.com/snu-hanaro/static-fire-toolkit/blob/main/examples/config.xlsx), [`examples/global_config.py`](https://github.com/snu-hanaro/static-fire-toolkit/blob/main/examples/global_config.py)
- Output samples: [`examples/results/thrust/`](https://github.com/snu-hanaro/static-fire-toolkit/tree/main/examples/results/thrust), [`examples/results/pressure/`](https://github.com/snu-hanaro/static-fire-toolkit/tree/main/examples/results/pressure), [`examples/results/burnrate/`](https://github.com/snu-hanaro/static-fire-toolkit/tree/main/examples/results/burnrate)
#### Output preview (from `examples/`):





### Global Configuration: `global_config.py`
Define runtime parameters for parsing and processing. The following load-cell parameters are device-specific and must be explicitly set:
- sensitivity_mv_per_v (mV/V)
- rated_capacity_kgf (kgf)
- gain_internal_resistance_kohm (kOhm)
- gain_offset (V)
> [!NOTE]
> **How to Convert Voltage[V] to Thrust[N]**:
> - `gain = gain_offset + (gain_internal_resistance_kohm * 1000)[Ω] / gain_resistance[Ω]`
> - `bridge_output_mv [mV] = sensitivity_mv_per_v[mV/V] * excitation_voltage[V] * thrust[N] / (rated_capacity_kgf[kgf] * g[N/kgf])`
> - `measured_output_v = (bridge_output_mv / 1000)[V] * gain`
>
> ```
> thrust[N] = (bridge_output_mv / sensitivity_mv_per_v)[V] / excitation_voltage[V] * (rated_capacity_kgf * g)[N]
> = (measured_output_v * 1000 / gain)[mV] / sensitivity_mv_per_v[mV/V] / excitation_voltage[V]
> * (rated_capacity_kgf * g)[N]
> ```
>
Optional parsing controls (fallbacks apply if unspecified):
- thrust_sep, pressure_sep (CSV delimiter, default:`,`)
- thrust_header, pressure_header (header row index or None, default: `0`)
- thrust_time_col_idx, thrust_col_idx, pressure_time_col_idx, pressure_col_idx
[Example](https://github.com/snu-hanaro/static-fire-toolkit/blob/main/examples/global_config.py):
```python
# ------------ Load Cell (Required) ------------
rated_capacity_kgf = 500 # 정격하중: rated capacity of load cell, kgf
sensitivity_mv_per_v = 3 # 감도: sensitivity of load cell, mV/V
gain_internal_resistance_kohm = (
49.4 # amplifier-specific internal resistor of load cell, kΩ
)
gain_offset = 1 # gain offset of load cell
# ----------- Thrust Data Processing -----------
thrust_sep = "[,\t]" # separator for thrust data, character or Regex
thrust_header = None # header for thrust data (row number or None)
thrust_time_col_idx = 0 # index of time column
thrust_col_idx = 1 # index of thrust column
# ---------- Pressure Data Processing ----------
pressure_sep = ";" # separator for pressure data, character or Regex
pressure_header = 0 # header for pressure data (row number or None)
pressure_time_col_idx = 0 # index of datetime column
pressure_col_idx = 2 # index of pressure column
# ------------ Processing Params ---------------
frequency = 100 # Sampling rate, Hz
cutoff_frequency = 30 # LPF, Hz
lowpass_order = 5 # order for low pass filter
gaussian_weak_sigma = 1.5 # sigma for weak gaussian filter
gaussian_strong_sigma = 10 # sigma for strong gaussian filter
start_criteria = 0.2 # Criteria for the starting point of a meaningful interval in thrust data processing
end_criteria = 0.1 # Criteria for the ending point of a meaningful interval in thrust data processing
```
### Per-Test Configuration: `config.xlsx`
Record one row per test; the latest row is processed by default. Required columns:
| Column | Description | Example |
| :--- | :--- | :--- |
| index | Zero-based test index | 17 |
| date | Date in YYMMDD | 250220 |
| type | Propellant type | KNSB |
| expt_file_name | Experiment base name | KNSB_250220 |
| expt_excitation_voltage [V] | DAQ excitation voltage | 11.94 |
| expt_resistance [Ohm] | DAQ potentiometer resistance | 200.4 |
| totalmass [g] | Propellant total mass | 4996.3 |
| Nozzlediameter [mm] | Throat diameter | 20 |
| Outerdiameter [mm] | Grain OD | 90 |
| Innerdiameter [mm] | Grain ID | 30 |
| singlegrainheight [mm] | Single grain height | 104.5 |
| segment | Grain count | 5 |
> [!NOTE]
> `expt_file_name` (if present) is auto-filled based on the values of date and type — do not edit. Notes/remarks are optional.
> [!NOTE]
> If your sheet uses the legacy column name `expt_input_voltage [V]` instead of `expt_excitation_voltage [V]`, it will be used automatically as a fallback.
### Data I/O Format & Processing Pipeline
- **Inputs**:
- Raw Thrust Data: CSV
- Raw Pressure Data: CSV
- **Outputs**:
- Uniform-step processed CSVs at Δt = 1/`frequency` s: `time` + `thrust [N]` or `pressure [bar]`
- PNG plots of thrust and pressure curves
- **Filtering**:
- Thrust → low-pass filter + Gaussian smoothing
- Pressure → no filter (typically smooth enough)
- **Pressure Normalization**: adjust for local vs. standard atmospheric pressure at test time
- **Config**: `config.xlsx` stores test conditions (date/nozzle/grain, etc.)
> [!NOTE]
> **File-Naming Summary**:
> - Thrust raw: `TYPE_YYMMDD_thrust_raw.csv`
> - Thrust outputs: `TYPE_YYMMDD_thrust.csv`, `TYPE_YYMMDD_thrust.png`
> - Pressure raw: `TYPE_YYMMDD_pressure_raw.csv`
> - Pressure outputs: `TYPE_YYMMDD_pressure.csv`, `TYPE_YYMMDD_pressure.png`
### Thrust Data Processing
#### Thrust raw (`data/_thrust_raw/`)
- Filename: `TYPE_YYMMDD_thrust_raw.csv` (e.g., `KNSB_250220_thrust_raw.csv`)
- Default Format: comma-separated, 2 columns, with column labels (Configurable via [`global_config.py`](#global-configuration-global_configpy))
1. time (s)
2. voltage (V) (must be 1:1 linearly convertible to thrust)
- Important: treat raw CSV as read-only. Re-saving in third-party editor such as Excel may change encoding/separators.
Example (header + excerpt):
```csv
time,voltage(V)
246.42052460007835,1.34765625
246.42483200004790,1.455078125
```
#### Pipeline
1. Read the latest test row from `config.xlsx`
2. Load and Parse the matching raw thrust CSV from `_thrust_raw/`
3. Convert voltage to thrust
4. Extract combustion window; handle spikes/outliers
5. PCHIP interpolation to Δt = 1/`frequency` s
6. Apply low-pass + Gaussian filters
7. Save processed thrust CSV → `results/thrust/TYPE_YYMMDD_thrust.csv`
8. Save thrust plot PNG → `results/thrust_graph/TYPE_YYMMDD_thrust.png`
#### Output CSV schema
| time [s] | thrust [N] |
| :--- | :--- |
| 0.00 | 2.757… |
| 0.01 | 16.772… |
| 0.02 | 32.070… |
| … | … |
### Pressure Data Processing
#### Pressure raw (`data/_pressure_raw/`)
- Filename: `TYPE_YYMMDD_pressure_raw.csv`
- Default Format: comma-separated, 2 columns, with column labels (Configurable via [`global_config.py`](#global-configuration-global_configpy))
1. Datetime ([ISO 8601](https://www.iso.org/iso-8601-date-and-time-format.html) format recommended, not necessarily in exactly the same format. For more details, see the [`pandas.to_datetime` documentation](https://pandas.pydata.org/docs/reference/api/pandas.to_datetime.html).)
2. Pressure (Bar)
Example (header + excerpt):
```csv
Datetime,Pressure (Bar)
2025.2.20 22:34,1.159
2025.2.20 22:34,1.132
```
#### Pipeline
1. Read the latest test row from config.xlsx
2. Load the matching raw pressure CSV from `_pressure_raw/`
3. Load the processed thrust CSV to synchronize burn window
4. PCHIP interpolation to Δt = 1/`frequency` s
5. Atmospheric correction: adjust for local vs. standard atmospheric pressure at test time
6. No filtering (pressure changes are typically smooth)
7. Save processed pressure CSV → `results/pressure/TYPE_YYMMDD_pressure.csv`
8. Save pressure plot PNG → `results/pressure_graph/TYPE_YYMMDD_pressure.png`
#### Output CSV schema
| time [s] | pressure [bar] |
| :--- | :--- |
| 0.00 | 1.447… |
| 0.01 | 1.500… |
| 0.02 | 1.560… |
| … | … |
## Troubleshooting & Best Practices
- Do not edit raw CSVs. Excel re-save can alter encoding/delimiters → corrupted data. Keep raw files read-only.
- Configure your `global_config.py` and `config.xlsx` correctly.
- “Latest row” logic. The CLI processes the most recent test by default. To reprocess an older test, update `config.xlsx` or pass `--expt`. We plan to add batch processing feature in a future release.
- Debugging order: follow the stage order — load → windowing → interpolation → filters → correction → save. Most issues are path/filename mismatches, delimiter/headers, or NaNs from partial rows.
- Reproducibility: do not overwrite raw CSVs; version `config.xlsx`; keep outputs auto-versioned by type/date in filenames.
### How to Report Issues
If you encounter a problem, please open an issue with:
- The output of `sft info --root ` (global configurations, environment, and package details)
- The corresponding logs in the `logs/` directory
- If possible, a minimal sample (subset of `data/_thrust_raw`, `data/_pressure_raw`, and `config.xlsx`) that reproduces the issue
## FAQ
### Q1. Why filter thrust but not pressure?
Thrust often contains transient spikes/noise (mechanical shocks, DAQ artifacts), so smoothing helps. Pressure changes are typically gradual; avoiding filters prevents distortion of real variations.
### Q2. What does the pressure correction do?
It compensates for the difference between local atmospheric pressure at test time and standard atmosphere, enabling apples-to-apples comparisons across sessions.
## Development
### Specs & Issue Tracking
This project is document-first.
Authoritative project records live under:
- docs/context
- docs/log
- docs/work
- docs/specs
Do not treat these as auxiliary documentation.
### Tools used
- Ruff: linting & formatting
- pytest: testing
- coverage: test coverage reports
- pre-commit — enforce style checks before commits
- GitHub Actions — CI/CD (matrix testing across Python 3.10–3.13)
### Local setup
```bash
# Run linting
ruff check .
ruff format .
# Run tests
pytest -q
```
### CI/CD Strategy
- Branching: trunk-based development (main protected)
- Matrix testing: Python 3.10–3.13, both latest and [minimum dependencies](https://github.com/snu-hanaro/static-fire-toolkit/blob/main/constraints-min.txt)
- Tags:
- Signed tags by default
- Annotated tags allowed with --no-sign
- Structured tag messages including Summary / Highlights / Breaking / Fixes / Docs / Thanks / Artifacts
## Contributing
Please use Issues/PRs with templates. Recommended:
- Feature request & bug report templates
- Code style (e.g., black, ruff) & type hints
- Sample data policy (strip sensitive metadata)
## Author & Maintainers
- Author: Seoul National University Rocket Team HANARO
- Maintainer: [@yunseo-kim](https://github.com/yunseo-kim)
## Citing Static-Fire Toolkit
If *HANARO SFT (Static-Fire Toolkit)* contributes to a project that leads to a scientific publication, please acknowledge this fact by citing [the published software](#static-fire-toolkit-on-zenodo):
### Static-Fire Toolkit on Zenodo
The following DOI represents *all* Static-Fire Toolkit versions.
You may cite it directly, or visit [Zenodo]((https://doi.org/10.5281/zenodo.17218595)) to find the DOI of the specific version you used.
[](https://doi.org/10.5281/zenodo.17218595)
BibTeX bibliography file: [CITATION.bib](https://raw.githubusercontent.com/snu-hanaro/static-fire-toolkit/refs/heads/main/CITATION.bib)
```
@software{hanaro-sft,
author = {Kim, Yunseo and
Seo, Jiwan and
Yun, Junghyeon},
title = {Static-Fire Toolkit},
month = sep,
year = 2025,
publisher = {Zenodo},
version = {latest},
doi = {10.5281/zenodo.17218595},
url = {https://doi.org/10.5281/zenodo.17218595},
}
```
- **Chicago**: Kim, Yunseo, Jiwan Seo, and Junghyeon Yun. “Static-fire Toolkit”. Zenodo, 2025. https://doi.org/10.5281/zenodo.17218595.
- **IEEE**: [1] Y. Kim, J. Seoand J. Yun, “Static-Fire Toolkit”. Zenodo, 2025. doi: 10.5281/zenodo.17218595.
- **ACS**: Kim, Y.; Seo, J.; Yun, J. Static-Fire Toolkit; Zenodo, 2025. https://doi.org/10.5281/zenodo.17218595.
- **APS**: [1] Y. Kim, J. Seo, and J. Yun, Static-Fire Toolkit (Zenodo, 2025), https://doi.org/10.5281/zenodo.17218595.
#### By version (past releases)
##### v1.0.1
[](https://doi.org/10.5281/zenodo.17218872)
##### v1.0.0
[](https://doi.org/10.5281/zenodo.17218596)
## License
This project is licensed under the [MIT License](https://github.com/snu-hanaro/static-fire-toolkit/blob/main/LICENSE).