Skip to content

Releases: striderZA/Tiny-RF-Simulator

v0.28.2

Choose a tag to compare

@github-actions github-actions released this 13 Oct 04:39
960161f

[0.28.2] - 2026-10-12

Added

  • Swap placed library components in place (#200) — the Properties panel's Part dropdown replaces a placed library component with another part, taking its parameters from the new part's library definition. The successor keeps its id, canvas position, selection, links (reattached by port index), probes, group membership, and Network Analyzer and Power Meter pins; a swapped PFB keeps its IQ Plot and Channelizer Grid visibility for the current session. A swap is refused, with the reason shown and the circuit unchanged, when the new part lacks a connected, probed, or instrument port, when a link would break the physical link policy, or when the part cannot be built.
  • Active project Git status in the header (#206) — the menu header shows the active circuit project's commit and counts of staged, unstaged, untracked, and conflicted paths; hover for the branch and full status. The status is read from the saved project's repository, or the working directory for an untitled project. Git queries run off the UI thread and fail soft when Git or the status is unavailable.
  • User manual, part 1 of 3 (#192) — MkDocs manual source under manual/pages/ with home, install, and guided tutorial pages, built under a strict gate.

Changed

  • README download and build sections (#192) — Quick Start points to the release archives, developer build steps move under their own heading, and the feature list covers receiver requirements and IIP3 checks.

Testing

  • Cover the swap command and its app-level carry-over, including PFB visibility and the Network Analyzer and Power Meter pin remap (test_component_swap, test_component_swap_app) (#200).
  • Restore the window flags test_project_json changes in the shared app.ini, so test_ui no longer depends on the saved layout (#200).
  • Add Git parsing, process, monitor, and header-width regression coverage (#206).

v0.28.1

Choose a tag to compare

@github-actions github-actions released this 12 Oct 04:52
96d8718

[0.28.1] - 2026-10-12

Fixed

  • Test flow results show applied condition values (#197) — result rows and JSON exports report the value a component actually applied after normalization. A requested ADC decimation of 3, for example, now reports the applied value 2.
  • Test flow restores components on applied-state failures (#197) — if an engine throws while the run reads back its applied state, the run restores the components to their pre-run state and returns a serialize_failed error.

Testing

  • Cover normalized condition values in rows and JSON, rollback after an applied-state readback failure, and agent error mapping for serialize_failed (#197).
  • Add perf_app, an opt-in timing harness (EXCLUDE_FROM_ALL, not a ctest target) for frame CPU, bounded inputs, startup, project load, and agent tool calls (#196).

v0.28.0

Choose a tag to compare

@github-actions github-actions released this 11 Oct 17:41
bee9c7d

[0.28.0] - 2026-10-11

Added

  • Agent interface (MCP) — an MCP client such as Claude Code can read and edit the circuit in an open RF Simulator window. Keep the window running, open View > Agent, and enable Agent Server, then point the client at the rf-sim-mcp bridge that ships beside the simulator. Agents can read the circuit and component parameters, apply up to 64 edits per call with checkpoints, discover component types and library parts, run port measurements, network-analyzer sweeps, receiver measurements, and test flows, and read contained data files. Agents cannot open, save, or name files. The Agent panel lists recent agent activity and checkpoints, and reverts to a checkpoint only after confirmation. (#190)

Changed

  • Release archives include rf-sim-mcp — the Linux tarball now holds rf-sim-mcp beside rf-simulator-linux at its root, and the Windows zip adds rf-sim-mcp.exe beside tiny-rf-simulator.exe.

Fixed

  • Out-of-range values stay as loaded (#182) — numeric fields in the inspector and the analyzer and generator widgets show a value outside their limits as it is, flagged with an amber field and a tooltip naming the range, and log it once. Previously the limit replaced the value on the next frame or edit. Edits are still clamped into the limits.
  • Ideal filter cutoffs are required per filter type (#181) — low-pass and high-pass library definitions must include fc_low_Hz, and band-pass and band-stop definitions must include both fc_low_Hz and fc_high_Hz with the low cutoff below the high one. Definitions that omit them are now refused instead of silently using the 100 and 200 MHz engine defaults. The New/Edit Component form shows only the cutoffs the chosen type uses.
  • S-parameter picker in the component form (#184) — the component form now exposes the S-parameter picker.
  • Legacy S-parameter entries load their file (#190) — projects and libraries saved before the sparam_filepath rename use their S-parameter file in amplifier, equalizer, and ideal filter components instead of the manual model. A loaded file without a forward index now uses S21, not S11.
  • Agent edits no longer abort on collapsed groups (#190) — an agent edit that checkpoints a project with a collapsed group no longer aborts the app.

Testing

  • Add agent protocol, API, bridge, and app-host coverage (ctest --test-dir build -R 'test_agent_|test_mcp_bridge'), plus the standalone test_sparam_legacy_key case for legacy S-parameter keys.
  • Pin component parameter serialization mappings (#174).

v0.27.0

Choose a tag to compare

@github-actions github-actions released this 06 Oct 18:14
ebb0add

[0.27.0] - 2026-10-06

Added

  • Receiver output power and IIP3 requirements — add optional output-power limits at a selected reference tone and two-tone IIP3 tests with configurable tone spacing and input-level sweeps. The Receiver Requirements panel evaluates and reports both alongside gain and noise-figure limits, with configuration persisted in project files.

Fixed

  • Network Analyzer and Receiver Requirements through switched filter banks — a 1:2 switch feeding parallel branches that rejoin at a 2:1 switch is now measured instead of reporting no data (#169). Analyzer gain follows the selected switch throws (or, where the selected filter passes no tone, any leakage from the other branch), and its noise figure includes the unselected branch's noise leaking through isolation; receiver output power and IIP3 measure the same circuit. Combiners, merges fed by a source outside the measured path, and a Point A component that feeds the bank through more than one output port still report no data.

Testing

  • Cover receiver output-power and IIP3 measurement/evaluation, partial IIP3 sweeps, project persistence, and panel integration.
  • Add switched-filter-bank coverage: analyzer gain and noise figure against the live engines (matched, flipped, and mismatched throws; low-isolation noise), an IdealFilter bank whose gain reads the other branch's leakage in the selected filter's stopband, the shared path discovery and runner (both branches wired in topological order, rejected topologies, malformed paths), receiver output power and IIP3 through a bank, and the production app clone adapter.
  • Make the Receiver Requirements pause/resume UI test deterministic in optimized builds: it caps the receiver engine's chain runs per frame, because a Release build otherwise finished the whole sweep before the test hid the view. Unit coverage pins the per-update cap.

v0.26.1

Choose a tag to compare

@github-actions github-actions released this 04 Oct 19:41
fff4239

[0.26.1] - 2026-10-04

Fixed

  • Component Library Edit action — clicking Edit on a user-defined component opens it in the editor without inserting a new instance into the circuit.

v0.26.0

Choose a tag to compare

@github-actions github-actions released this 02 Oct 20:54
45065db

[0.26.0] - 2026-10-02

Added

  • Receiver Requirements panel — configure a frequency band, acceptable gain range, and maximum noise figure, then compare the analyzer sweep against those limits with per-metric and overall pass, fail, or incomplete status. Requirements persist with the project.

Changed

  • UI-independent circuit runtime — move graph/component ownership, topology edits, and signal updates into CircuitRuntime, separating editor-specific actions into GraphEditorActions. Project loading routes topology changes through the runtime.

Testing

  • Add receiver-requirements evaluation, project-persistence, and panel workflow coverage, plus headless circuit-runtime and graph-editor-action tests.

v0.25.1

Choose a tag to compare

@github-actions github-actions released this 01 Oct 18:27
71b0f98

[0.25.1] - 2026-10-01

Added

  • PFB integrated channel noise and SNR — the PFB inspector reports the active channel's integrated noise power and effective noise bandwidth, and its hover SNR compares the strongest channel tone against that integrated noise, independent of analyzer RBW.

Fixed

  • Network Analyzer through 2:1 RF switches — follow the exact linked input and output ports along the measured path, so a singly-fed switch reports the response of the connected throw. Dual-fed switches and combiner paths remain unsupported and report no data.

Testing

  • Add Network Analyzer coverage for both switch throws, unsupported dual-fed switch paths, and the production app clone adapter.
  • Add PFB coverage for channel-integrated noise and hover SNR in test_node_hover_snr and test_pfb_filter_design.

v0.25.0

Choose a tag to compare

@github-actions github-actions released this 25 Sep 15:18
2c39de7

[0.25.0] - 2026-09-25

Added

  • Test Flow authoring — the Test Flow panel (View > Test Flow) no longer only runs a hand-written flow; it writes one, closing issue #155. Pick a component and one of its real serialize() keys from a combo that lists every key with its JSON type and current value, seed the values from the live circuit, add/update/remove conditions and measurements, Save Flow... it, and Reload to pick up a hand edit without re-picking the file. New from Circuit scaffolds a draft from the live circuit — a measurement on the first component with an output port, port 0, power_dBm, the form pre-filled from the first sweepable key and its current value — so a working file is one Add-condition click away, and every id and path in the form is read from the circuit rather than invented. A non-numeric key is listed but disabled with its JSON type as the reason, and a condition whose path does not resolve is marked red and answered with the sweepable keys that engine's serialize() does expose (up to kMaxPathHints), because a mistyped serialize() key, never an inspector label, is the likeliest authoring mistake.

Changed

  • Flow authoring rules live in the harness, not the panel — test_flow/ gains describeConditionPaths() (every scalar leaf of a component's serialize() snapshot with its JSON type and current value, containers descended and never listed; only the entries it marks numeric are paths resolveConditionSlot() accepts, so a picker built on it cannot offer a path applyConditionValue() would refuse), buildFlowDocument()/writeFlowFile() (the document LoadFlowFile() reads back, ids and paths verbatim, written atomically via temp + rename so a failed write cannot truncate a hand-authored flow), and parseConditionValues()/formatConditionValues() (the values field's grammar and its shortest round-trip inverse, refusing rather than skipping a token that is not a complete finite number). The panel keeps adding no second copy of the document shape, value grammar, or applicability rules, and the harness keeps its no-ImGui/no-simulator::app rule.
  • A draft is the single thing edited, validated and run — edits land in an in-tool draft and spec() is the one accessor preview(), run() and saveFlow() read, so the panel cannot validate one flow and run another; addCondition()/updateCondition()/addMeasurement() check each candidate through ValidateFlow() and report its own wording, plus the loader's duplicate-target/duplicate-reading rules that ValidateFlow() does not check, so a refusal at the form is the verdict Run would give later and a draft the panel runs is also a file that loads back. A load clears the draft (the file is the truth again); a circuit reload keeps it and preview() revalidates it against the replacement circuit.
  • app/AGENTS.md and test_flow/AGENTS.md document the authoring contract: the spec()/draft boundary, circuit-sourced references, the form's use of ValidateFlow(), and the values-field buffer growth.

Fixed

  • A refused authoring edit no longer creates a draft — the duplicate-target and duplicate-reading checks and the remove/update index checks now run against the effective spec before any draft is materialised, so draftActive() keeps meaning "unsaved edits exist" and a rejected click cannot flip the panel into that state.
  • The values field no longer truncates a long sweep — its ImGui buffer grows from the model text (kValuesBufferHeadroom past its end) instead of using a fixed 256 bytes, which had let a long sweep's seeded text be truncated on the next keystroke and the truncation stored back, silently dropping values from a list the harness would then run as if it were complete.
  • Discarding unsaved edits is stated, not silent — a load (and reloadFlow(), which goes through it) reports in the status that the in-tool edits were discarded, and New from Circuit reports when it replaced a draft.

Testing

  • Add four [issue155] cases to tests/test_issue87_flow.cpp: the offered paths are exactly the sweepable leaves of serialize() (discovery and resolver agree, including that resolving touches nothing), a built document is the flow LoadFlowFile() reads back, a mistyped value list is refused rather than partially accepted, and a failed write leaves the previous file byte-identical.
  • Extend tests/test_test_flow_widget.cpp with the authoring contract over real headless frames and clicks: a flow scaffolded from the circuit saves, loads back and runs (with registry-id pinning), an authored condition is refused exactly where the harness would refuse it, the form seeds the current value and the draft is what runs, reload re-reads the selected file and drops the draft, a circuit reload keeps the draft and revalidates it, a scaffold needs something to measure, a refused edit never creates a draft, a 200-value list survives the form round trip, and the authoring buttons drive their own actions.

v0.24.4

Choose a tag to compare

@github-actions github-actions released this 25 Sep 12:46
b05492e

[0.24.4] - 2026-09-25

Added

  • Test Flow runner panel — View > Test Flow opens an app-owned panel that runs the JSON test flows of the headless harness (test_flow/) against the live circuit: pick a flow file, see its conditions and measurements resolved against the loaded components, run it, read the per-row results, and export them as JSON. The panel never forms its own opinion of a flow — its pre-flight is the harness's own ValidateFlow() pass, exhaustive over every condition value and reporting every issue in RunFlow()'s check order and wording, with Run disabled until that list is empty — so a flow the panel offers is a flow the harness accepts, and a mistyped path (a serialize() key such as atten_dB, not the inspector's attenuation_dB label) or a value the resolved slot cannot take is named before the click instead of failing the run. A run is net-neutral: every engine is serialized before execution and restored afterwards, each independently so one failure cannot strand the rest, the graph's input pointers are rewired, and component state, links and the project's dirty flag are exactly what they were. A restoration failure is the exception — it is latched and reported, the run's result is suppressed, and further runs are refused until the circuit is reloaded (newProject(), a successful load, or a failed load that reset the circuit, all clear it). An unmeasurable sample renders as N/A and exports as JSON null rather than failing the run, and the panel's selection, load state and last result are session-only while the panel toggle persists with the other window states.
  • Node hover SNR — the node-body hover tooltip now carries the strongest-tone SNR of the hovered component's first output, measured through the new SpectrumAnalyzerEngine::computeStrongestToneSNRdB() with the analyzer's current RBW, so changing the spectrum analyzer's resolution bandwidth changes the hover row. The tooltip prints SNR: <value> dB, or SNR: -- when the measurement is unavailable (no finite tone, no strictly ascending two-bin grid, a tone outside the swept span, a non-positive RBW); the call is read-only and never touches the analyzer's render caches, VBW or trace history, and a multi-output part still exposes its other outputs through the existing Ctrl+click probe hint. Pin, link and collapsed-subcircuit tooltips are unchanged and carry no SNR row.

Changed

  • The flow pre-flight is shared, not reimplemented — ValidateFlow(spec, components) is the harness's condition and measurement resolution pass exposed as a reusable call, and RunFlow() is now a caller of it that reports the first issue verbatim; an attached UI therefore cannot drift from the harness's verdicts in either order or wording.
  • Value checking is split from writing — resolveConditionSlot() resolves a condition's path once per condition and reports the slot kind it found, and conditionSlotAccepts() applies the value rules to that kind with no JSON involved, which are exactly the rules applyConditionValue() enforces. Checking a whole sweep therefore costs one path parse plus arithmetic instead of a serialize, clone and patch per value (a 10000-value sweep measures ~0.1 ms, affordable on every frame), and RunFlow()'s own pre-flight drops from ~14.7 µs per value to that same check.
  • One click cannot hang the window — the panel refuses a sweep above kMaxRunRows (10000) before it snapshots anything, because the cartesian product executes synchronously on the UI thread (10000 rows measured ~4 s on a two-node circuit in an unoptimized build), and the results table is height-bounded and row-clipped (34 ms per frame at 10000 rows against 0.27 ms bounded). The row ceiling and the current issue are shown in the panel, so a disabled Run always has a visible reason.
  • Flow addressing is documented, not implicit — flow conditions[].component is an IComponentEngine::id(), assigned from a base of 100 in saved order, so a clean save/load reproduces the ids while any deletion or re-order shifts every later one; because ids stay dense, a stale reference can silently bind to a different component of the same type. Both test_flow/AGENTS.md and app/AGENTS.md now state this, along with the pre-flight, row-ceiling and table contracts.

Testing

  • Add three standalone test targets (the established pattern for keeping coverage out of the MinGW TEST_CASE registration ceiling): tests/test_spectrum_analyzer_snr.cpp (RBW sensitivity, full stored tone power on real-domain and complex-baseband spectra, extreme finite tone levels whose watt conversion underflows or overflows, unavailable-input guards, nonuniform-grid and tie-bin lookup, and the read-only contract against render caches and trace history), tests/test_node_hover_snr.cpp (the app's hover adapter: registry summary passthrough, the analyzer SNR of the node's first output only — an output-1 read would be ~20 dB off and is asserted against — and the empty-optional fallback), and tests/test_test_flow_widget.cpp (the panel contract in full, below).
  • Add tests/test_test_flow_widget.cpp coverage for the snapshot/restore boundary around RunFlow() (a clean sweep and an ordinary failure both leave every component's serialize() state, every graph link and the dirty flag untouched; a restoration failure is a distinct latched failure with no result that may leave the throwing component at its swept state, cleared only by resetAfterCircuitReload()), the app's failed-load switch, preview id/port resolution, the saturating expected row count, N/A rendering, export success/failure, reload revalidation of the retained selection, and draw callback dispatch. The pre-flight is pinned against a mistyped or type-inapplicable path — including a fractional value sitting between two acceptable ones, the case a sampled pre-flight would miss — the kMaxRunRows refusal is asserted through an engine that counts deserialize() calls (nothing may be executed), and frame-cost guards cover both the exhaustive pre-flight over 10000 values and the bounded table.
  • Extend tests/test_issue87_flow.cpp with the ValidateFlow() contract (no issues for a runnable flow, one FlowError per failing reference in RunFlow()'s order and wording with RunFlow() reporting the first verbatim, and a value rejected mid-list rejected the same way) and the resolveConditionSlot()/conditionSlotAccepts() split it rests on, including a value-by-value equivalence loop asserting the check agrees with the write on outcome, message and the exact JSON type written, and that resolving touches nothing.
  • Extend test_engine/ui_tests.cpp with the tooltip-window visibility case's node-body data assertions (non-empty summary plus a populated analyzer SNR from the app callback the widget renders) and the View > Test Flow menu/window integration; the panel's own model is covered by the headless standalone target.

v0.24.3

Choose a tag to compare

@github-actions github-actions released this 22 Sep 18:50
e1a5103

[0.24.3] - 2026-09-22

Fixed

  • Extension menu label ambiguity — a duplicate (location, label) pair across two extension manifests is now rejected at parse time instead of keeping an entry that cannot be addressed: the menu label is the action's only run-time identifier (ExternalToolRequest::action_label) and the ImGui item is keyed on it, so two entries sharing a label could launch the wrong tool. The Tools menu and Extensions panel now also suffix the item id with the manifest id and action index (the pattern the Extensions panel already used) so distinct entries never share one ImGui id, while still handing the raw label to runExternalTool() as the dispatch key.
  • S-parameter copy path traversal — the component-authoring save path joined the raw part number onto the library destination directory, so a part number containing separators or .. wrote the picked S-param file outside the chosen root. The data-file name now comes from sanitizePathSegment() (moved beside the library code so app.cpp and ComponentFormModel share it) and the copy destination is built by dataFileCopyDestination(), which refuses any name that is not a bare file name with a visible form error.

Documentation

  • Release CRLF-trap recipe — the release-pipeline guidance in the root AGENTS.md is now a runnable recipe: read the committed bytes with git cat-file blob HEAD~1:CMakeLists.txt, require git diff HEAD~1 --stat -- CMakeLists.txt to print 2 +-, and restore + byte-replace + --amend if the MSYS sed had rewritten the file to LF-only.

Testing

  • Add tests/test_issue130_extension_menu_labels.cpp as its own standalone executable (matching the existing pattern that keeps extension coverage out of tests.exe and the MinGW TEST_CASE registration ceiling): duplicate labels are rejected and unique ids are assigned.
  • Extend tests/test_path_containment.cpp with authoring save-path coverage driven through new testOpenNewComponentForm/testOpenEditComponentForm/testSetComponentFormDestinationRoot/testComponentFormModel/testSaveComponentForm accessors: the new-entry case asserts the saved JSON path, persisted data-file name, copied bytes, refused traversal target, and an instantiate-with-S-params round trip of the saved entry; the edit case asserts the copy replaces the previous revision in the entry's own directory and that a chosen destination root stays uncreated.