Expand description
bhtune-core — the pure, I/O-free domain crate.
This crate holds (once implemented — see AGENTS.md for phase status):
- The MRFT (Modified Relay Feedback Test) tuning algorithm, as a pure
state machine:
fn step(&mut self, tick: Tick) -> Vec<Action>. No clock reads, no network calls, no UI access — that constraint is what makes it possible to replay a recorded trace and assert the engine produces bit-identical results across changes. - The tuning-constant lookup matrices and PID unit conversion math.
- The domain data model: tag maps, loop configuration, DCS/PLC template semantics, and the enums that model PID parameter types and controller direction.
Deliberately has no I/O, no async, and no clock reads (chrono’s clock/now
features are disabled workspace-wide, so Utc::now() cannot even compile here — see
core-mrft in AGENTS.md). This is a narrower rule than “no dependencies”: toml is a
real dependency (template-catalog), justified because parsing an include_str!-
embedded &'static str is not I/O; the optional, feature-gated utoipa dependency
(openapi-contract) is justified the same way — a compile-time derive macro that
describes a type’s shape, with zero runtime behavior of its own. Anything added here
must be justified by the pure domain logic itself (or, for utoipa, by describing it
accurately to a consumer), not by a consumer’s I/O or presentation needs — those belong
in bhtune-driver, bhtune-db, bhtune-cli, or bhtune-server.
Re-exports§
pub use constants::ResponseLevel;pub use constants::TuningConstants;pub use constants::lookup;pub use controller_type::ControllerType;pub use direction::ControllerDirection;pub use loop_config::LoopConfig;pub use loop_config::LoopConfigError;pub use mrft::Action;pub use mrft::InitialReadings;pub use mrft::MrftCompat;pub use mrft::MrftEngine;pub use mrft::MrftState;pub use mrft::Tick;pub use pid_config::DerivativeType;pub use pid_config::IntegralType;pub use pid_config::ProportionalType;pub use pid_config::TimeUnit;pub use process_type::ProcessType;pub use range::MvRange;pub use range::PvRange;pub use range::RangeError;pub use tags::LoopTags;pub use tags::TagOrValue;pub use tags::TagOverrides;pub use tags::TagOverridesError;pub use tags::derive_tag;pub use template::DcsTemplate;pub use template::built_in_templates;pub use tuning_math::CheckedTuningResult;pub use tuning_math::OpcWriteValues;pub use tuning_math::Oscillation;pub use tuning_math::PidParameters;pub use tuning_math::TuningMathCompat;pub use tuning_math::TuningResult;pub use tuning_math::TuningResultInvalidReason;pub use tuning_math::TuningResultStatus;pub use tuning_math::calculate_all;pub use tuning_math::calculate_all_checked;pub use tuning_math::calculate_pid_parameters;pub use tuning_math::calculate_tuning_result;pub use tuning_math::measure_oscillation;pub use tuning_math::opc_write_values;
Modules§
- constants
- Tuning-constant lookup matrices: per-process-type, per-response-level, per-controller type multipliers used to turn a measured relay-test oscillation into Kp/Ti/Td.
- controller_
type - The controller structures a tuning run can target: Proportional-only, Proportional + Integral, or full PID.
- direction
- Controller action direction: whether increasing the manipulated variable increases or decreases the process variable. Determines which way the relay steps during MRFT.
- loop_
config - Per-run test configuration: process type, controller type, relay amplitude, and MRFT cycle/timing parameters.
- mrft
- The MRFT (Modified Relay Feedback Test) engine: the pure, I/O-free relay-switching state
machine at the heart of bhtune. See
AGENTS.md’s “Key architectural decisions” for why this must never read a clock, perform network I/O, or touch a UI. - pid_
config - Enums for how a DCS/PLC expresses PID parameters, avoiding the fragile pattern of
comparing live values against magic display strings (
"Kp - Proportional Gain", etc.). - process_
type - The process types the tuning-constant matrices are calibrated for.
- range
- Validated PV/MV range types – the boundary a live OPC DA read or a CLI flag override
must pass through before an untrusted number is treated as a range with a known,
trustworthy shape (finite bounds, correctly ordered, non-zero span). See AGENTS.md’s
“Live-plant safety hardening” section for the review finding this closes (
--cycles-count 0panicking mid-run was the same finding’s other symptom: no externally supplied number reached the engine validated). - tags
- OPC tag-name derivation: expands a single PV tag into the full tag set a loop needs, using the active DCS/PLC template’s suffix conventions.
- template
- DCS/PLC template semantics: one instance per control-system convention (Yokogawa,
Honeywell, etc.), describing how that DCS expresses PID parameters and the OPC
item-name suffix convention used to derive a full tag set from a single PV tag (see
crate::tags::derive_tag). - tuning_
math - Tuning-constant math: turns a completed MRFT run’s peaks/troughs/switch-times into Kp/Ti/Td
for all three
ResponseLevels, then into the PID parameters in whatever representation/units a DCS/PLC template expects.