Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 9 additions & 4 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -181,9 +181,14 @@ jobs:
toolchain: cmake/hexagon-linux-musl.cmake
exclude: BadProfilesThrow|LatencyAndValidation
# rational: every EXPECT_THROW test (named *Throw*) is excluded on
# Hexagon for the unwind reason above; on the Arm legs
# bare_metal_main.cpp bakes in its own filter (the fine-grid
# sweeps of the long designs).
# Hexagon for the unwind reason above, with the host measurements
# (the coverage matrix's tone batteries, 182 chains in double per
# profile, and the relaxation tables' searches, which run every
# candidate length through the design grid: the 70 dB tables alone
# exceed the job's budget under qemu-hexagon); on the Arm legs
# bare_metal_main.cpp bakes in its own
# filter (the fine-grid sweeps of the long designs and the
# matrix suite).
- target: hexagon
title: Hexagon cross
engine: rational
Expand All @@ -192,7 +197,7 @@ jobs:
jobs: 4
build_type: Release
toolchain: cmake/hexagon-linux-musl.cmake
exclude: Throw
exclude: Throw|Matrix\.EveryRowMeets|RelaxationTablesAreTheSearch
- target: m55
title: Cortex-M55 cross
engine: rational
Expand Down
5 changes: 3 additions & 2 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,9 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co
over one substrate. `async/` (`tap::sr::async`) is the asynchronous near-unity converter that
*absorbs the clock*; `bridge/` (`tap::sr::bridge`) is the synchronous 44.1 ↔ 48 kHz converter that
*converts the number*; `rational/` (`tap::sr::rational`) is the synchronous small-factor L/M
converter within a rate family (L, M ∈ {2^a·3^b}), chains of Nyquist stages, at M3 of its plan
(ratio types, pinned designs and the single stages; the chains follow). All build on DspTap (`submodules/dsptap`,
converter within a rate family (L, M ∈ {2^a·3^b}), chains of Nyquist stages, at M4 of its plan
(ratio types, pinned designs, the single stages, the named chains and the 182-row coverage matrix;
fixed point and the C ABI follow). All build on DspTap (`submodules/dsptap`,
`tap::dsp`), pinned once at the root. Each engine has its own `README.md`, `PLAN.md` and `CLAUDE.md`;
read the engine's before touching its code.

Expand Down
10 changes: 8 additions & 2 deletions PLAN.md
Original file line number Diff line number Diff line change
Expand Up @@ -1014,8 +1014,14 @@ G13 and G14, plus G9 from 3.7.
tap/DspTap#50). M3 — the single stages for the whole vocabulary,
pinned against scipy, with DspTap's `accumulate_row` (tap/DspTap#51)
under the decimators' zero-skipping branch sum — landed
(`rational/PLAN.md` v0.6). Next: the chains and the generated 14 × 14
matrix under 2.1's rule (M4).
(`rational/PLAN.md` v0.6). M4 — the chains (`basic_chain<S, R...>`,
each stage designed at its design divisor; DspTap's `chain<>::flush`,
tap/DspTap#52) and the generated 14 × 14 matrix under 2.1's rule, every
one of the 182 rows measured and pinned, the cross rows through
`bridge` at every k — landed (`rational/PLAN.md` v0.7; the matrix was
regenerated from the measured lengths, 35 rows changed chain, the
ledger in its section 8). Next: the fixed-point profiles (M5), then the
C ABI, notebook and icount baselines with the family version 0.5.0 (M6).

---

Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ quantization, measurement instruments).
|---|---|---|---|
| **`async`** | `tap::sr::async` | Asynchronous, near-unity (±`max_deviation_ppm`, default 1000 ppm): two clock domains at nominally the same rate, one thread pushing at the input clock and one pulling at the output clock. **Absorbs the clock.** | [`async/`](async/README.md) |
| **`bridge`** | `tap::sr::bridge` | Synchronous 44.1 ↔ 48 kHz (160/147 up, 147/160 down) and the pair at 2× and 4× (88.2 ↔ 96, 176.4 ↔ 192), direction and rate scale fixed at compile time, speed-first with Q15/Q31 profiles for M33/M55-class targets. **Converts the number.** | [`bridge/`](bridge/README.md) |
| **`rational`** | `tap::sr::rational` | Synchronous small-factor L/M *within* a rate family (L, M ∈ {2^a·3^b}: ↑2, ↓3, 2/3, …), as chains of Nyquist (L-th-band) stages, the ratio a compile-time type. **Converts the number.** M1–M3 landed (ratio types, pinned designs, the single stages for every ratio of the vocabulary); the chains and the coverage matrix follow its plan. | [`rational/`](rational/README.md) |
| **`rational`** | `tap::sr::rational` | Synchronous small-factor L/M *within* a rate family (L, M ∈ {2^a·3^b}: ↑2, ↓3, 2/3, …), as chains of Nyquist (L-th-band) stages, the ratio a compile-time type. **Converts the number.** M1–M4 landed (ratio types, pinned designs, the single stages for every ratio of the vocabulary, the named chains and the 182-row coverage matrix generated from the measured lengths); fixed point and the C ABI follow its plan. | [`rational/`](rational/README.md) |

The engines never route by rate. The caller declares the clock topology by
choosing a type: `async` when the clocks are independent, `bridge` when the
Expand Down
30 changes: 20 additions & 10 deletions rational/CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,16 +19,21 @@ anything; do not re-derive what it settles (the compile-time ratio, one Nyquist
stage factoring by MACs then by stage count, `bridge` at the lowest k, the profile vocabulary,
latency as an exact rational).

Current state: **M3** — the tree, `ratio<L, M>` with its charter `static_assert`s and
Current state: **M4** — the tree, `ratio<L, M>` with its charter `static_assert`s and
`ratio_traits`, `profile` carrying the pinned taps per branch for every band of the vocabulary
(the M2 design spike, `notebooks/design_spike.ipynb`, executed; the pins found on a
16384-point grid and enforced by `tests/test_design.cpp`), `design_stage<R>` over
`tap::dsp::nyquist.h`, and the single stages: `basic_stage<S, R>` (`stage.h`) for every ratio
of the vocabulary with bridge's call shapes, `converter<R>` / `converter_q15<R>` /
16384-point grid and enforced by `tests/test_design.cpp`) and, since M4, the relaxation tables
(the pins at every design divisor the matrix uses, `profile::relaxed`), `design_stage<R>` over
`tap::dsp::nyquist.h`, the single stages — `basic_stage<S, R>` (`stage.h`) for every ratio of
the vocabulary with bridge's call shapes, `converter<R>` / `converter_q15<R>` /
`converter_q31<R>` (`converter.h`), pinned against committed scipy vectors
(`tests/reference/`, generated by `tools/reference/make_reference_vectors.py`). M4 (chains
and the matrix), M5 (fixed point) and M6 (C ABI, notebook, icount baselines; family version
0.5.0) follow in PLAN.md section 6.
(`tests/reference/`, generated by `tools/reference/make_reference_vectors.py`) — and the chains:
`basic_chain<S, R...>` (`chain.h`) over DspTap's `chain<>`, each stage designed at its design
divisor (PLAN.md 3.1), the 20 named multi-stage chains, and the 182-row coverage matrix
generated from the pinned lengths by `tools/coverage/matrix.py` (section 3 of the plan;
`tests/coverage/matrix_rows.h`) and pinned row by row by `tests/test_matrix.cpp` (the
cross-family rows through `tests/support/bridge_stage.h`). M5 (fixed point) and M6 (C ABI,
notebook, icount baselines; family version 0.5.0) follow in PLAN.md section 6.

## The charter constraints (load-bearing)

Expand All @@ -40,9 +45,14 @@ and the matrix), M5 (fixed point) and M6 (C ABI, notebook, icount baselines; fam
there is no `(in_hz, out_hz)` lookup here or in the C ABI (whose enumerators name chains). The
coverage matrix in PLAN.md documents chains; it dispatches nothing.
- **Speed-first, like `bridge`.** The ratio is a compile-time type, so every trip count and
schedule is a compile-time fact; the stage factoring is chosen by MACs (R3: ↑4 is two
half-bands, never one 4th-band stage); every inaudible quality-vs-speed trade goes to speed in
the default `economy` profile.
schedule is a compile-time fact; the stage factoring is chosen by MACs on the measured lengths
(R3: ↑4 is two half-bands, never one 4th-band stage; on the pinned lengths a relaxed
half-band saturates at m = 7, so third-band and mixed stages win where the transition is wide,
PLAN.md 2.1 and the S1 ledger); every inaudible quality-vs-speed trade goes to speed in the
default `economy` profile. A chain's stages are each designed at their own rate: the design
divisor (PLAN.md 3.1), computed by `chain.h` at compile time, with pinned lengths per divisor.
Change the matrix only through the generator, then regenerate the rows header and the plan's
tables.
- **One Nyquist filter per stage (R2, R4).** Length N = 2mL − 1, centre tap exactly 1, every
L-th tap from it exactly 0, every polyphase branch at DC gain 1 — `tap::dsp::nyquist.h`'s
contract, pinned by `test_design.cpp` through this engine's build. The up and down designs of
Expand Down
16 changes: 14 additions & 2 deletions rational/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,7 @@ endif()
# (L, M in {2^a * 3^b}), as fast as possible. Header-only C++20
# (include/tap/sr/rational/), built on the Tap family's shared substrate from
# DspTap (the L-th-band designer, the stage composition, sample-format traits,
# dot kernels, quantization). See PLAN.md for the charter and milestones; this
# is the M1 skeleton: the ratio types and the stage design.
# dot kernels, quantization). See PLAN.md for the charter and milestones.
# ==============================================================================

# Shared Tap-family substrate (tap::dsp), pinned once at the repository root
Expand Down Expand Up @@ -50,6 +49,19 @@ if(TAP_SR_RATIONAL_WERROR)
$<$<CXX_COMPILER_ID:MSVC>:/WX>)
endif()

# The sibling bridge engine, dev-only (never part of the shipped
# tap::sr::rational target): the coverage matrix's cross-family rows compose
# bridge's converter with this engine's stages (PLAN.md 3.5 / 3.6), through a
# test-side adapter. Consumed headers-only via include path, so this engine's
# code never links bridge's target (PLAN.md 4.2); tap::dsp serves its
# "tap/dsp/..." includes.
if(TAP_SR_BUILD_TESTS)
add_library(tap_sr_bridge_headers INTERFACE)
# SYSTEM: dependency headers are exempt from this engine's warning gates.
cmake_path(SET _tap_bridge_include NORMALIZE "${CMAKE_CURRENT_SOURCE_DIR}/../bridge/include")
target_include_directories(tap_sr_bridge_headers SYSTEM INTERFACE ${_tap_bridge_include})
endif()

if(TAP_SR_BUILD_TESTS)
enable_testing()
add_subdirectory(tests)
Expand Down
Loading
Loading