Reusable structural engineering building blocks for Python applications.
Timoshenko packages common structural calculations, modal analysis, sensor workflows, and monitoring components so applications can reuse them instead of rebuilding the same foundations for every project. It is an embeddable Python library, not a hosted monitoring service or a general finite-element solver.
Alpha: the API may still change between releases. Every behavior change is listed in the changelog.
python -m pip install timoshenko-engineThe distribution is named timoshenko-engine; the import package is
timoshenko. Optional MQTT support is an extra:
python -m pip install "timoshenko-engine[mqtt]"For the synchronous PostgreSQL history backend, install
timoshenko-engine[postgres]. SQLite is included with Python and needs no
extra dependency.
Compare measured vibration with a reference model. This example simulates a record in which both modes are 5% below the model:
import numpy as np
import timoshenko as tm
structure = tm.Structure(
structure_id="building-01",
story_masses_kg=[120_000.0, 110_000.0],
story_stiffness_n_m=[85_000_000.0, 70_000_000.0],
)
print(structure.natural_frequencies_hz) # (2.626, 6.476)
fs = 100.0
t = np.arange(60_000) / fs
f1, f2 = (0.95 * f for f in structure.natural_frequencies_hz)
signal = np.sin(2 * np.pi * f1 * t) + 0.4 * np.sin(2 * np.pi * f2 * t)
sensors = tm.SensorData(signal, sampling_hz=fs, unit="m/s^2")
result = tm.monitor(structure, sensors, review_threshold_pct=3.0)
print(result.structure.update_scale_factor) # 0.903, since stiffness scales with frequency squared
for change in result.health.mode_changes:
print(change.mode_number, change.change_pct) # 1 -5.0, then 2 -5.0
print(result.health.review_recommended) # TrueReal records load from CSV or JSON with
tm.load_sensors("acceleration.csv", sampling_hz=100.0, column="acc"). The
steps inside tm.monitor are also available separately as tm.modal.identify,
tm.update, and tm.health.assess. The review flag is raised only when you
pass a threshold: a meaningful value depends on the structure and its
environmental variability, so the engine does not choose one.
Closed-form functions take and return SI units and validate their inputs:
import timoshenko as tm
section = tm.rectangle_section(width_m=0.3, height_m=0.6)
beam = tm.simply_supported_uniform_load(
20_000.0,
6.0,
30e9,
section.second_moment_y_m4,
shear_modulus_pa=12.5e9,
area_m2=section.area_m2,
)
print(beam.bending_m, beam.shear_m) # 2.083 mm bending, 0.048 mm shear
frequency = tm.propagate_uncertainty(
tm.natural_frequency_hz,
{"mass_kg": 250.0, "stiffness_n_m": 4e5},
standard_uncertainties={"mass_kg": 5.0, "stiffness_n_m": 8e3},
)
print(frequency.estimate, frequency.standard_uncertainty) # 6.366 Hz ± 0.090 HzPlanar members can also be assembled into a small-displacement linear frame model. Supports, nodal loads, local uniform loads and member masses are explicit model inputs. See 2D frame analysis for the stiffness, mass and scope assumptions.
| Area | Components |
|---|---|
| Engineering calculations | Section properties (including polygons with holes), beam deflection with shear, torsion, Euler buckling, plane stress, thin-wall pressure, SDOF vibration, Rayleigh damping, and GUM / Monte Carlo uncertainty |
| Structural models | Lumped-mass shear buildings; linear 2D trusses and frames with static, modal, P-delta and buckling analysis; and linear 3D trusses and frames with static, modal and ideal buckling analysis |
| Modal analysis | Single-channel peak picking, optional EFDD damping, multi-channel FDD, covariance-driven SSI and asynchronous channel alignment |
| Model comparison | Frequency and MAC tools, global and per-story stiffness updating, environmental frequency normalization, and evidence-oriented health assessment |
| Time history | Newmark average-acceleration response with optional Rayleigh damping and base acceleration for 2D and 3D models |
| Monitoring | Bounded rolling-window sessions, restart from SQLite or PostgreSQL history, and source adapters for CSV, MQTT, and OGC SensorThings |
| Data and reporting | Project manifests with SHA-256 provenance, SQLite and optional PostgreSQL history, and standalone HTML reports |
Sensor collection, alarm policy, and engineering interpretation remain with the application that embeds Timoshenko.
Frequency domain decomposition needs synchronized channels with a common
sample rate and unit. FDD can optionally estimate damping with EFDD; use
covariance-driven SSI when you also need a pole-stability screening indicator.
For asynchronous sources, tm.align_multichannel can apply explicit clock
offsets and calibration before resampling onto one shared grid:
signals = tm.load_multichannel_csv(
"aligned_accelerometers.csv",
columns=["deck_left", "deck_center", "deck_right"],
sampling_hz=100.0,
units=["m/s^2"] * 3,
)
fdd = tm.identify_fdd(signals, nperseg=1024, max_modes=5)
for mode in fdd.modes:
print(mode.frequency_hz, mode.shape_real)Pass estimate_damping=True to request EFDD damping estimates; unresolved
estimates are returned as None. See advanced OMA and channel alignment.
A host application feeds timestamped observation batches. The session aligns samples to the sample grid, waits for a fresh contiguous window after gaps, and analyzes every configured hop:
session = tm.MonitoringSession(
structure,
sensor_ids=["deck-left", "deck-right"],
units=["m/s^2", "m/s^2"],
sampling_hz=100.0,
window_samples=2048,
hop_samples=512,
analysis_options={"nperseg": 512, "max_modes": 4},
review_threshold_pct=5.0,
)
result = session.ingest(batch) # batch: tm.ObservationBatch from your gateway or a source adapter
for report in result.reports:
tm.report.save_html(report, "reports/latest.html")The session does not open network connections or run in the background. Use
tm.SessionRunner with a source such as tm.CSVObservationSource or
tm.MqttObservationSource to drive it.
The full documentation is at timoshenko.readthedocs.io. Good places to start:
- API reference
- Numerical methods and limits
- Architecture
- Monitoring sessions and source adapters
- Runnable examples, including a cross-check of PyNite shear-deformable beams
- Changelog
- Timoshenko is alpha software and is not a structural safety certification tool.
- The shear-building model is a small lumped-mass reference model, not a full FEM solver.
- Modal identification is a screening estimate. A single sensor may miss a mode near a modal node; unpaired peaks are reported rather than compared with the wrong mode.
- Damping is a screening estimate. Peak-picking requires a resolved half-power bandwidth; EFDD and SSI damping can be sensitive to record length, mode overlap and model settings.
tm.updateapplies one stiffness scale to all stories.tm.update_story_stiffnessfits individual story scales from a complete ordered modal set, but neither method locates or sizes damage reliably without an identifiable model and engineering review.- The 3D solver uses dense matrices, prismatic Euler-Bernoulli frame members, ideal restraints and nodal loads. It does not analyze plates, shells, nonlinear response or design-code compliance.
- A frequency shift is evidence for human review, not a damage verdict. Temperature, sensor placement, boundary conditions, and other effects also shift measured frequencies.
- Closed-form mechanics and section functions rely on their documented ideal assumptions. They are not code-compliance checks.
python -m pip install -e ".[test,lint]"
python -m pytest --cov
python -m ruff check .
python -m ruff format --check .
python -m mypyTo preview the documentation site:
python -m pip install -e ".[docs]"
python -m mkdocs serveBug reports and pull requests are welcome in the
issue tracker. See
CONTRIBUTING.md
for the checks a pull request needs to pass; issues labelled
good first issue
are small, self-contained starting points.
If you use Timoshenko in research, please cite it with its DOI,
10.5281/zenodo.22968739, which
always resolves to the latest release; each release also has its own DOI on
Zenodo. The metadata is in
CITATION.cff,
which GitHub's "Cite this repository" button reads.
Apache License 2.0. See LICENSE.
