Files
impakt/README.md

560 lines
18 KiB
Markdown
Raw Permalink Normal View History

2026-04-10 14:37:34 -04:00
# Impakt
**Crash test data analysis, visualization, and reporting.**
Impakt is a modular, scriptable Python toolkit for working with automotive crash test data. It reads ISO 13499 MME data natively, provides non-destructive signal processing, interactive web-based visualization, injury criteria calculation, and protocol-compliant report generation for Euro NCAP, US NCAP, and IIHS.
2026-04-10 14:46:53 -04:00
## Quick Start
```bash
# Install
uv sync --dev
2026-04-11 15:20:27 -04:00
# Run tests (258 tests, 70% coverage)
2026-04-10 14:46:53 -04:00
uv run pytest tests/
# View test metadata
uv run impakt info tests/mme_data/3239
# Launch web UI
uv run impakt serve tests/mme_data/3239
# Python scripting
uv run python -c "
from impakt import Session
s = Session.open('tests/mme_data/3239')
print(s) # Session(3239, 133 channels)
2026-04-11 15:20:27 -04:00
# Fluent transforms
ch = s.channel('11HEAD0000H3ACXP').transform.cfc(1000).transform.y_align()
print(f'Peak: {ch.peak:.1f} {ch.unit}')
# One-call protocol evaluation
result = s.evaluate('euro_ncap')
print(f'{result.stars} stars ({result.percentage:.0f}%)')
2026-04-10 14:46:53 -04:00
"
```
> See [[docs/STATUS.md]] for detailed project state, known issues, and next steps.
2026-04-10 14:37:34 -04:00
---
## Contents
- [[#Design Principles]]
- [[#Architecture Overview]]
2026-04-11 15:20:27 -04:00
- [[#Configuration System]]
2026-04-10 14:37:34 -04:00
- [[#Module Breakdown]]
2026-04-11 15:20:27 -04:00
- [[#impakt.config — Configuration]]
2026-04-10 14:37:34 -04:00
- [[#impakt.io — Data IO]]
- [[#impakt.channel — Channel Model]]
- [[#impakt.transform — Signal Processing]]
- [[#impakt.criteria — Injury Criteria]]
- [[#impakt.protocol — Rating Protocols]]
- [[#impakt.plot — Visualization]]
2026-04-11 15:20:27 -04:00
- [[#impakt.report — Report Generation]]
2026-04-10 14:37:34 -04:00
- [[#impakt.template — Templates and Sessions]]
- [[#impakt.web — Web UI]]
- [[#impakt.plugin — Plugin System]]
- [[#impakt.script — Scripting API]]
- [[#Data Flow]]
2026-04-11 15:20:27 -04:00
- [[#Configuration Layers]]
2026-04-10 14:37:34 -04:00
- [[#ISO Channel Naming Intelligence]]
- [[#Directory Structure]]
- [[#Scripting Examples]]
---
## Design Principles
2026-04-11 15:20:27 -04:00
1. **Immutable raw data.** Original MME files are never modified. All state — sessions, configuration, cached results — lives in a `.impakt/` subfolder alongside the test data.
2. **Non-destructive transforms.** Filtering, alignment, and math operations produce new channel views via `TransformChain`. The chain is serializable and reproducible.
3. **Scriptable first.** Every operation available in the UI is accessible through a Python API. The web UI calls the same `Session` and `PlotEngine` used by scripts.
4. **Layered configuration.** All behavior is configurable via YAML files at three levels: package defaults, user defaults (`~/.impakt/`), and per-test session overrides (`.impakt/`).
5. **Template-driven workflow.** Reusable templates define channel selections, filter chains, corridors, and report configs. Sessions bind templates to specific test data.
6. **Protocol-aware.** Built-in Euro NCAP, US NCAP, and IIHS scoring with versioned YAML threshold files.
7. **Plugin-extensible.** Custom readers, transforms, criteria, and protocols registered via entry points, directory scanning, or API.
2026-04-10 14:37:34 -04:00
---
## Architecture Overview
```mermaid
graph TB
subgraph "Data Layer"
IO[impakt.io]
CH[impakt.channel]
end
subgraph "Processing Layer"
TR[impakt.transform]
CR[impakt.criteria]
PR[impakt.protocol]
end
subgraph "Presentation Layer"
PL[impakt.plot]
RP[impakt.report]
WB[impakt.web]
end
subgraph "Orchestration Layer"
2026-04-11 15:20:27 -04:00
CF[impakt.config]
2026-04-10 14:37:34 -04:00
TM[impakt.template]
SC[impakt.script]
PG[impakt.plugin]
end
2026-04-11 15:20:27 -04:00
IO -->|"parse MME"| CH
2026-04-10 14:37:34 -04:00
CH -->|"channel data"| TR
TR -->|"filtered/aligned"| CR
CR -->|"injury values"| PR
PR -->|"scores & ratings"| RP
CH -->|"raw & derived"| PL
TR -->|"processed"| PL
CR -->|"criteria results"| PL
PL -->|"figures"| RP
PL -->|"interactive plots"| WB
2026-04-11 15:20:27 -04:00
CF -.->|"configures"| PL
CF -.->|"configures"| TR
CF -.->|"configures"| CR
CF -.->|"configures"| PR
2026-04-10 14:37:34 -04:00
SC -->|"drives"| TM
SC -->|"drives"| IO
SC -->|"drives"| TR
SC -->|"drives"| PL
PG -.->|"extends"| IO
PG -.->|"extends"| TR
PG -.->|"extends"| CR
PG -.->|"extends"| PR
WB -->|"calls"| SC
```
---
2026-04-11 15:20:27 -04:00
## Configuration System
All configurable behavior is defined in YAML files with three-layer resolution:
```mermaid
graph LR
PKG["Package Defaults\nsrc/impakt/defaults/config.yaml"] --> USER["User Defaults\n~/.impakt/config.yaml"]
USER --> SESSION["Session Overrides\n<test_dir>/.impakt/config.yaml"]
SESSION --> ACTIVE["Active Config"]
style PKG fill:#e1f5fe
style USER fill:#fff9c4
style SESSION fill:#c8e6c9
style ACTIVE fill:#f3e5f5
```
**Configurable sections:**
| Section | Examples |
|---|---|
| `plot` | Color palette, line widths, focus styling, margins, cursor colors, grid, resampling |
| `transforms` | Default CFC class, Y-align, X-align method |
| `criteria` | Channel patterns for auto-detection (per criterion, glob-style) |
| `protocols` | Default protocol, version mapping, threshold file locations |
| `session` | Auto-save behavior, `.impakt/` directory name |
| `web` | Default layout, cursor poll interval, port |
When a session is saved, configuration and protocol thresholds are copied into the test's `.impakt/` folder, making it self-contained and reproducible.
---
2026-04-10 14:37:34 -04:00
## Module Breakdown
2026-04-11 15:20:27 -04:00
### impakt.config — Configuration
2026-04-10 14:37:34 -04:00
2026-04-11 15:20:27 -04:00
Layered YAML configuration with typed Python dataclasses.
2026-04-10 14:37:34 -04:00
2026-04-11 15:20:27 -04:00
```python
from impakt.config import Config
config = Config.load(session_path="tests/mme_data/3239")
config.plot.line_width # 1.5 (from package default)
config.transforms.default_cfc # None (no filter by default)
config.protocols.default # "euro_ncap"
2026-04-10 14:37:34 -04:00
2026-04-11 15:20:27 -04:00
config.transforms.default_cfc = 600
config.save_session("tests/mme_data/3239") # writes .impakt/config.yaml
```
### impakt.io — Data IO
Reads crash test data via the `ReaderProtocol`. The `MMEReader` handles real ISO 13499 format (`.mme` master + `.chn` index + `.NNN` data files) and simplified INI format.
2026-04-10 14:37:34 -04:00
```mermaid
classDiagram
class ReaderProtocol {
<<protocol>>
+read(path: Path) TestData
+supports(path: Path) bool
+metadata(path: Path) TestMetadata
}
2026-04-11 15:20:27 -04:00
class MMEReader
class TDMSReader
class CSVReader
2026-04-10 14:37:34 -04:00
class ReaderRegistry {
+register(reader: ReaderProtocol)
+detect(path: Path) ReaderProtocol
+read(path: Path) TestData
}
ReaderProtocol <|.. MMEReader
ReaderProtocol <|.. TDMSReader
ReaderProtocol <|.. CSVReader
ReaderRegistry o-- ReaderProtocol
```
2026-04-11 15:20:27 -04:00
Tested against 5 real ISO 13499 datasets from NHTSA/Calspan, BASt, Volkswagen, and UTAC.
2026-04-10 14:37:34 -04:00
### impakt.channel — Channel Model
2026-04-11 15:20:27 -04:00
Immutable `Channel` objects wrapping NumPy time-series data with ISO channel code intelligence.
2026-04-10 14:37:34 -04:00
2026-04-11 15:20:27 -04:00
The `ChannelCode` parser auto-detects 14-char and 16-char ISO codes:
2026-04-10 14:37:34 -04:00
2026-04-11 15:20:27 -04:00
| Format | Example | Positions 11-12 |
2026-04-10 14:37:34 -04:00
|---|---|---|
2026-04-11 15:20:27 -04:00
| 16-char (with dummy) | `11HEAD0000H3ACXP` | `H3` = Hybrid III |
| 14-char (simplified) | `11HEAD0000ACXA` | `AC` = Acceleration |
2026-04-10 14:37:34 -04:00
2026-04-11 15:20:27 -04:00
**Auto-grouping:** Channels sharing all fields except direction (X/Y/Z) are grouped for one-call resultant computation.
2026-04-10 14:37:34 -04:00
2026-04-11 15:20:27 -04:00
### impakt.transform — Signal Processing
2026-04-10 14:37:34 -04:00
2026-04-11 15:20:27 -04:00
Non-destructive pipeline via `TransformChain`. Each transform produces a new `Channel`.
2026-04-10 14:37:34 -04:00
2026-04-11 15:20:27 -04:00
| Transform | Description |
|---|---|
| `CFCFilter` | SAE J211 CFC filtering (4th-order Butterworth, zero-phase) |
| `XAlign` | Time-zero shifting (manual, threshold, trigger) |
| `YAlign` | Zero-offset correction from baseline window |
| `Resultant` | Vector magnitude from X/Y/Z components |
| `MathExpr` | Free-form math with safe numpy evaluation |
| `Trim` | Extract time range |
| `Resample` | Change sample rate (Fourier-based) |
2026-04-10 14:37:34 -04:00
### impakt.criteria — Injury Criteria
2026-04-11 15:20:27 -04:00
Auto-detection of channels by ISO naming patterns, with configurable patterns in `config.yaml`.
2026-04-10 14:37:34 -04:00
2026-04-11 15:20:27 -04:00
| Criterion | Method | Reference |
|---|---|---|
| **HIC15/36** | Cumulative integration, optimal window search | FMVSS 208 |
| **3ms Clip** | Cumulative exceedance | SAE J211 |
| **Nij** | 4 modes (NTE/NTF/NCE/NCF), per-dummy intercepts | FMVSS 208 |
| **Chest Deflection** | Peak sternal displacement | FMVSS 208 |
| **Femur Load** | Peak compressive axial force | FMVSS 208 |
| **Tibia Index** | M/Mc + F/Fc with intercepts | Euro NCAP |
| **Viscous Criterion** | V(t) * C(t) | Euro NCAP |
2026-04-10 14:37:34 -04:00
### impakt.protocol — Rating Protocols
2026-04-11 15:20:27 -04:00
Versioned YAML threshold files loaded from `defaults/protocols/`, `~/.impakt/protocols/`, or `<test>/.impakt/protocols/`.
2026-04-10 14:37:34 -04:00
2026-04-11 15:20:27 -04:00
| Protocol | Output |
|---|---|
| **Euro NCAP** | Stars (0-5), body region colors (Green/Yellow/Orange/Brown/Red), points |
| **US NCAP** | Stars (1-5), injury probability per body region |
| **IIHS** | Good/Acceptable/Marginal/Poor per body region, overall rating |
2026-04-10 14:37:34 -04:00
### impakt.plot — Visualization
2026-04-11 15:20:27 -04:00
Single rendering path via `PlotEngine.render(PlotSpec)`. Both the scripting API and web UI construct `PlotSpec` objects and delegate to the same engine.
2026-04-10 14:37:34 -04:00
2026-04-11 15:20:27 -04:00
- **Compact mode** for web UI (no legend, tight margins, disabled hover)
- **Standard mode** for scripting (full tooltips, legend)
- **FigureResampler** integration for LTTB downsampling on zoom/pan
- **Focus channel** rendering (amber highlight, rendered on top)
- **Corridor fills** (upper/lower bands from CSV or programmatic)
2026-04-10 14:37:34 -04:00
2026-04-11 15:20:27 -04:00
### impakt.report — Report Generation
2026-04-10 14:37:34 -04:00
2026-04-11 15:20:27 -04:00
Jinja2 HTML templates rendered to PDF via WeasyPrint. Three report types: plot sheets, injury summary, and full protocol reports.
2026-04-10 14:37:34 -04:00
### impakt.template — Templates and Sessions
| Concept | **Template** | **Session** |
|---|---|---|
2026-04-11 15:20:27 -04:00
| Lives in | `~/.impakt/templates/` | `<test_dir>/.impakt/` |
| Contains | Channel patterns, filter chains, corridors, protocol config | Template ref + overrides + config + cached results |
| Purpose | Reusable recipe | Per-test instance with user modifications |
2026-04-10 14:37:34 -04:00
### impakt.web — Web UI
2026-04-11 15:20:27 -04:00
Dash application with two tabs:
2026-04-10 14:37:34 -04:00
2026-04-11 15:20:27 -04:00
**Data Tab:**
- Resizable left panel (draggable splitter) with channel grid + transform controls
- Channel grid: flat sortable DataTable, wildcard filter, facet dropdowns, consistent color coding
- Plot area with multi-pane layout (1x1 through 3x1)
- Channel Values table: combined statistics + live cursor values (#, ISO Code, Description, Unit, Min@Time, Max@Time, X1, X2, Cursor)
- Custom JS cursor tracker (mousemove → pixel-to-data-X conversion)
2026-04-10 14:37:34 -04:00
2026-04-11 15:20:27 -04:00
**Analysis Tab:**
- Injury criteria auto-computation with protocol scoring
- Math expression builder with variable binding
- Template management (library browser, save/apply/delete)
- Corridor upload (CSV)
- Export (CSV, PNG/SVG/PDF, protocol report)
2026-04-10 14:37:34 -04:00
### impakt.plugin — Plugin System
2026-04-11 15:20:27 -04:00
Entry point + directory + API discovery. `PluginRegistry.register_reader()` forwards to the IO registry. Plugins discovered on first `Session.open()`.
2026-04-10 14:37:34 -04:00
### impakt.script — Scripting API
2026-04-11 15:20:27 -04:00
`Session` is the primary entry point. The web UI's `AppState` holds `Session` objects — the same code path for scripts and UI.
2026-04-10 14:37:34 -04:00
---
## Data Flow
```mermaid
graph TB
2026-04-11 15:20:27 -04:00
MME["MME Directory\n(immutable)"] -->|"impakt.io"| TD[TestData]
TD --> CH[Channels]
CH -->|"TransformChain"| TCH[Transformed Channels]
TCH -->|"criteria"| CR[CriterionResults]
CR -->|"protocol"| SC[ProtocolResult]
2026-04-10 14:37:34 -04:00
2026-04-11 15:20:27 -04:00
CH & TCH -->|"PlotSpec"| PE[PlotEngine]
PE --> FIG[Plotly Figure]
2026-04-10 14:37:34 -04:00
2026-04-11 15:20:27 -04:00
SC --> RP[Report Engine]
FIG --> RP
RP --> PDF[PDF/HTML]
2026-04-10 14:37:34 -04:00
2026-04-11 15:20:27 -04:00
CFG["Config\n(layered YAML)"] -.-> PE
CFG -.-> CR
CFG -.-> SC
TD -.->|"state"| IMPAKT[".impakt/"]
IMPAKT -.->|"restore"| TD
2026-04-10 14:37:34 -04:00
style MME fill:#e1f5fe
2026-04-11 15:20:27 -04:00
style IMPAKT fill:#fff9c4
2026-04-10 14:37:34 -04:00
style PDF fill:#c8e6c9
2026-04-11 15:20:27 -04:00
style CFG fill:#f3e5f5
2026-04-10 14:37:34 -04:00
```
---
2026-04-11 15:20:27 -04:00
## Configuration Layers
2026-04-10 14:37:34 -04:00
```mermaid
graph TB
2026-04-11 15:20:27 -04:00
subgraph "Package (shipped with pip install)"
PKG_CFG[defaults/config.yaml]
PKG_PROTO[defaults/protocols/*.yaml]
2026-04-10 14:37:34 -04:00
end
2026-04-11 15:20:27 -04:00
subgraph "User (~/.impakt/)"
USR_CFG[config.yaml]
USR_PROTO[protocols/*.yaml]
USR_TMPL[templates/*.yaml]
USR_CORR[corridors/*.csv]
2026-04-10 14:37:34 -04:00
end
2026-04-11 15:20:27 -04:00
subgraph "Test Session (<test_dir>/.impakt/)"
SES_CFG[config.yaml]
SES_PROTO[protocols/*.yaml]
SES_SESS[session.yaml]
SES_CORR[corridors/]
SES_DER[derived/]
2026-04-10 14:37:34 -04:00
end
2026-04-11 15:20:27 -04:00
PKG_CFG -->|"overridden by"| USR_CFG
USR_CFG -->|"overridden by"| SES_CFG
2026-04-10 14:37:34 -04:00
2026-04-11 15:20:27 -04:00
PKG_PROTO -->|"copied to"| USR_PROTO
USR_PROTO -->|"copied to"| SES_PROTO
2026-04-10 14:37:34 -04:00
```
2026-04-11 15:20:27 -04:00
**Save Session** copies config + protocols into the test's `.impakt/` folder. The test directory becomes self-contained and reproducible.
2026-04-10 14:37:34 -04:00
---
## ISO Channel Naming Intelligence
```mermaid
graph LR
2026-04-11 15:20:27 -04:00
RAW["11HEAD0000H3ACXP"] --> PARSER[ChannelCode Parser]
2026-04-10 14:37:34 -04:00
2026-04-11 15:20:27 -04:00
PARSER --> OBJ["Object: 11\nDriver"]
PARSER --> LOC["Location: HEAD"]
2026-04-10 14:37:34 -04:00
PARSER --> FINE["Fine: 0000\nCenter of Gravity"]
2026-04-11 15:20:27 -04:00
PARSER --> DUMMY["Dummy: H3\nHybrid III"]
2026-04-10 14:37:34 -04:00
PARSER --> MEAS["Measurement: AC\nAcceleration"]
2026-04-11 15:20:27 -04:00
PARSER --> DIR["Direction: X"]
PARSER --> SENSE["Sense: P"]
2026-04-10 14:37:34 -04:00
2026-04-11 15:20:27 -04:00
OBJ & LOC & FINE & DUMMY & MEAS & DIR --> GROUP["Group Key\n(X/Y/Z family)"]
2026-04-10 14:37:34 -04:00
2026-04-11 15:20:27 -04:00
GROUP --> AUTO["Auto-features:\n- Resultant computation\n- Criteria channel matching\n- Channel grid placement\n- Human-readable labels"]
2026-04-10 14:37:34 -04:00
```
---
## Directory Structure
```
impakt/
2026-04-11 15:20:27 -04:00
├── pyproject.toml # PEP 621, uv dependency-groups
├── uv.lock
├── .gitignore
├── README.md # This file
├── BRAINSTORM.md # Feature ideas (80+)
├── docs/
│ ├── STATUS.md # Detailed project state
│ └── QA-*.md # Quality assessment scorecards
├── research/
│ └── landscape.md # Competitive landscape analysis
├── src/impakt/
│ ├── __init__.py # exports Session, Template
│ ├── config/ # Layered YAML configuration
│ │ ├── __init__.py
│ │ └── model.py # Config, PlotConfig, TransformConfig, etc.
│ ├── defaults/ # Package-level defaults (shipped)
│ │ ├── config.yaml # All configurable fields with comments
│ │ └── protocols/ # Euro NCAP, IIHS threshold YAMLs
│ ├── channel/ # Data model + ISO naming
│ │ ├── code.py # ChannelCode parser (14/16-char auto-detect)
│ │ ├── model.py # Channel, ChannelGroup, TestData, TestMetadata
│ │ ├── group.py # Auto-grouping utilities
│ │ └── lookup.py # ISO naming lookup tables (150+ entries)
│ ├── io/ # Data readers
│ │ ├── reader.py # ReaderProtocol, ReaderRegistry
│ │ ├── mme.py # ISO 13499 MME reader (real + simplified)
│ │ ├── tdms.py # TDMS stub
│ │ └── csv.py # CSV stub
│ ├── transform/ # Signal processing
│ │ ├── base.py # Transform protocol, TransformChain
│ │ ├── cfc.py # SAE J211 CFC filter
│ │ ├── align.py # X-align, Y-align
│ │ ├── resultant.py # Vector magnitude
│ │ ├── math_expr.py # Safe math expressions
│ │ └── resample.py # Trim, Resample
│ ├── criteria/ # Injury criteria calculations
│ ├── protocol/ # Rating protocol scorers
│ │ ├── thresholds/ # Versioned YAML threshold files
│ │ └── *.py # Euro NCAP, US NCAP, IIHS
│ ├── plot/ # Plotly rendering engine
│ │ ├── engine.py # PlotEngine (single rendering path)
│ │ ├── spec.py # PlotSpec, ChannelRef, Corridor
│ │ └── export.py # Image/HTML export
│ ├── report/ # PDF/HTML report generation
│ │ ├── engine.py # Jinja2 + WeasyPrint
│ │ └── templates/ # HTML report templates
│ ├── template/ # Template + session persistence
│ ├── web/ # Dash web application
│ │ ├── app.py # App factory
│ │ ├── state.py # AppState (holds Sessions server-side)
│ │ ├── layout.py # Two-tab layout (Data + Analysis)
│ │ ├── components/ # 10 reusable UI components
│ │ ├── callbacks/ # 9 feature-specific callback modules
│ │ └── assets/ # CSS, JS (splitter, cursor tracker)
│ ├── plugin/ # Plugin registry + discovery
│ └── script/ # Session API + CLI
│ ├── api.py # Session, ChannelHandle, Template
│ └── cli.py # impakt serve/info/channels/evaluate
2026-04-10 14:37:34 -04:00
├── tests/
2026-04-11 15:20:27 -04:00
│ ├── fixtures/ # Synthetic MME test data (26 channels)
│ ├── mme_data/ # 5 real ISO 13499 datasets
│ └── test_*/ # 258 tests across all modules
2026-04-10 14:37:34 -04:00
```
---
## Scripting Examples
2026-04-11 15:20:27 -04:00
### One-call evaluation
2026-04-10 14:37:34 -04:00
```python
from impakt import Session
2026-04-11 15:20:27 -04:00
s = Session.open("tests/mme_data/3239")
# Auto-detect channels and score against Euro NCAP
result = s.evaluate("euro_ncap")
print(result.summary())
# Euro NCAP 2024
# Rating: ***** (5/5 stars)
# Score: 14.0/16.0 (88%)
# Head: 233.08 [green] (4.0/4.0)
# Chest: 44.04 g [yellow] (3.0/4.0)
# ...
```
2026-04-10 14:37:34 -04:00
2026-04-11 15:20:27 -04:00
### Fluent transform chaining
2026-04-10 14:37:34 -04:00
2026-04-11 15:20:27 -04:00
```python
from impakt import Session
2026-04-10 14:37:34 -04:00
2026-04-11 15:20:27 -04:00
s = Session.open("tests/mme_data/3239")
# Each transform returns a ChannelHandle — fully chainable
ch = (
s.channel("11HEAD0000H3ACXP")
.transform.cfc(1000)
.transform.y_align()
.transform.trim(t_start=0.0, t_end=0.1)
)
print(f"Peak: {ch.peak:.1f} {ch.unit}")
2026-04-10 14:37:34 -04:00
```
2026-04-11 15:20:27 -04:00
### Configuration override
2026-04-10 14:37:34 -04:00
```python
from impakt import Session
2026-04-11 15:20:27 -04:00
s = Session.open("tests/mme_data/3239")
2026-04-10 14:37:34 -04:00
2026-04-11 15:20:27 -04:00
# Override default CFC for this session
s.config.transforms.default_cfc = 600
s.config.plot.line_width = 2.0
s.save_config() # writes to 3239/.impakt/config.yaml
2026-04-10 14:37:34 -04:00
```
### Custom math channel
```python
from impakt import Session
from impakt.transform import math_expr
2026-04-11 15:20:27 -04:00
s = Session.open("tests/mme_data/3239")
2026-04-10 14:37:34 -04:00
custom = math_expr(
2026-04-11 15:20:27 -04:00
expression="sqrt(a**2 + b**2)",
2026-04-10 14:37:34 -04:00
channels={
2026-04-11 15:20:27 -04:00
"a": s.channel("11HEAD0000H3ACXP").raw,
"b": s.channel("11HEAD0000H3ACZP").raw,
2026-04-10 14:37:34 -04:00
},
2026-04-11 15:20:27 -04:00
name="Head XZ Resultant",
unit="m/s²",
2026-04-10 14:37:34 -04:00
)
2026-04-11 15:20:27 -04:00
print(f"Peak: {custom.peak:.1f} {custom.unit}")
2026-04-10 14:37:34 -04:00
```
2026-04-11 15:20:27 -04:00
### Launch web UI
2026-04-10 14:37:34 -04:00
```python
from impakt.web import serve
from impakt import Session
2026-04-11 15:20:27 -04:00
s = Session.open("tests/mme_data/3239")
serve(s, port=8050)
2026-04-10 14:37:34 -04:00
# Opens browser at http://localhost:8050
```