35 traffic classes across 9 protocol families shipped. Archives ROADMAP, REQUIREMENTS, and phase directories to milestones/v1.2-*. Updates README with new protocol families, sound design table, and [groups] TOML config documentation. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
121 lines
6.6 KiB
Markdown
121 lines
6.6 KiB
Markdown
---
|
|
phase: 09-frequency-design-and-group-architecture
|
|
plan: "01"
|
|
subsystem: synth
|
|
tags: [frequency-design, group-architecture, config, oscillator-fix]
|
|
dependency_graph:
|
|
requires: [08-01]
|
|
provides: [FreqConfig.Group, rebalanced-ClassFreqConfigs, oscillator-normalization-fix]
|
|
affects: [synth, config, bank_test, config_test]
|
|
tech_stack:
|
|
added: []
|
|
patterns:
|
|
- "Major-second ladder Hz allocation for family-band frequency design"
|
|
- "math.Abs normalization for alternating-sign harmonic series in additive oscillator"
|
|
key_files:
|
|
created: []
|
|
modified:
|
|
- synth/config.go
|
|
- synth/config_test.go
|
|
- synth/oscillator.go
|
|
- synth/bank_test.go
|
|
- config/config_test.go
|
|
decisions:
|
|
- "Group field added to FreqConfig as a string (not enum) — extensible for Phase 10 new family names without code changes"
|
|
- "Within-family spacing satisfies major second (1.122 ratio): 65->73 = 1.123, 73->82 = 1.123, 82->133 = 1.622 (Infrastructure skips slots reserved for Phase 10), 150->169 = 1.127 (Web), 771->866 = 1.123 (Unknown)"
|
|
- "Oscillator normalization fixed to use math.Abs — alternating-sign harmonics (triangle wave) were causing output to exceed [-1,1] bounds when using WaveformPresetHarmonics"
|
|
metrics:
|
|
duration: "6m 30s"
|
|
completed: "2026-03-27"
|
|
tasks_completed: 2
|
|
files_modified: 5
|
|
---
|
|
|
|
# Phase 9 Plan 1: Frequency Design and Group Architecture Summary
|
|
|
|
FreqConfig gains a Group string field; all 14 ClassFreqConfigs entries rebalanced to major-second ladder in family frequency bands (65-1375 Hz), with family-specific waveforms. Oscillator normalization bug fixed for alternating-sign harmonic series.
|
|
|
|
## What Was Built
|
|
|
|
### Task 1: Add Group field to FreqConfig and rebalance ClassFreqConfigs
|
|
|
|
`synth/config.go` was updated with:
|
|
|
|
1. `Group string` field added to `FreqConfig` struct after `WaveformType`
|
|
2. Frequency allocation table comment block documenting all 32 designed slots (Phase 9 + Phase 10 placeholders)
|
|
3. Stale `NumLayers` and `GainPerLayer` constants removed (Phase 8 cleanup carried forward)
|
|
4. All 14 `ClassFreqConfigs` entries rebalanced to the major-second ladder:
|
|
- Infrastructure (Triangle, 65-133 Hz): ICMP=65, NTP=73, DHCP=82, DNS=133
|
|
- Web (Sawtooth, 150-169 Hz): HTTPS=150, HTTP=169
|
|
- Mail (Triangle, 214 Hz): SMTP=214
|
|
- Remote Access (Square, 343 Hz): SSH=343
|
|
- Unknown (Custom harmonics, 771-1375 Hz): Unknown1=771, Unknown2=866, Unknown3=972, Unknown4=1091, OtherTCP=1225, OtherUDP=1375
|
|
|
|
Non-Unknown entries use `WaveformPresetHarmonics`; Unknown entries retain hand-tuned `{1,1.0},{2,0.8},{3,0.4}` with `WaveformType` left as zero value (`WaveformCustom`) so `bank.go` uses stored harmonics directly.
|
|
|
|
### Task 2: Update synth tests and fix oscillator normalization bug
|
|
|
|
`synth/config_test.go`:
|
|
- `TestGroupFieldPopulated` added: iterates all ClassFreqConfigs entries, fails if any have empty Group
|
|
- `TestHarmonicsNonEmpty` threshold changed from `< 2` to `< 1` (accepts single-harmonic sine entries for Phase 10 SIP)
|
|
|
|
**Auto-fix (Rule 1 - Bug): Oscillator normalization for alternating-sign harmonics**
|
|
|
|
Found during Task 2 verification: `TestNewBankCustomConfigNoClip` was failing with `L=-1.023`. Root cause: `oscillator.go` `Advance()` accumulated `totalWeight += h.Amplitude` (signed sum), but `WaveformPresetHarmonics(WaveformTriangle, ...)` produces alternating-sign amplitudes. The signed sum (~0.916 for 65 Hz triangle with 170 harmonics) is much smaller than the absolute sum (~1.232), causing the normalization denominator to be deflated, which inflated output amplitude beyond [-1, 1].
|
|
|
|
Fix: changed to `totalWeight += math.Abs(h.Amplitude)` in `oscillator.go`. The old config used positive-only amplitudes `{k, 1/k}` so the bug was latent. The new `WaveformPresetHarmonics(WaveformTriangle, ...)` exposed it.
|
|
|
|
**Test updates (Rule 1 - Bug):**
|
|
- `synth/bank_test.go`: `TestStereoPan` updated from ClassDHCP (new pan=0.1, right-biased) to ClassSSH (pan=-0.7, wide-left); `TestNewBankCustomConfigNoClip` passes after oscillator fix
|
|
- `config/config_test.go`: `TestLoadPartialOverrideFrequency` changed from hardcoded `WaveformCustom` to `synth.ClassFreqConfigs[classify.ClassICMP].WaveformType` (ICMP is now WaveformTriangle); `TestAutoFreqSkipsBuiltins` changed from hardcoded 175.0 to `synth.ClassFreqConfigs[classify.ClassHTTPS].BaseHz` (now 150.0)
|
|
|
|
## Verification Results
|
|
|
|
```
|
|
go build ./synth/... → exit 0
|
|
go test ./synth/... -v -count=1 → 42 tests PASS
|
|
go test ./... → all 7 packages PASS
|
|
grep -c 'Group:' synth/config.go → 14
|
|
grep 'Group string' synth/config.go → FOUND
|
|
grep -c 'BaseHz: 65.0' synth/config.go → ICMP confirmed
|
|
grep '// Frequency Allocation Table' synth/config.go → FOUND
|
|
```
|
|
|
|
## Deviations from Plan
|
|
|
|
### Auto-fixed Issues
|
|
|
|
**1. [Rule 1 - Bug] Fixed oscillator normalization for alternating-sign harmonic amplitudes**
|
|
- **Found during:** Task 2 verification (`go test ./synth/...`)
|
|
- **Issue:** `oscillator.Advance()` used `totalWeight += h.Amplitude` (signed sum). Triangle wave harmonics from `WaveformPresetHarmonics` alternate signs (1, -1/9, 1/25, -1/49...), making signed total ~0.916 vs absolute total ~1.232. This caused 34% undercount, so output exceeded [-1, 1] bounds.
|
|
- **Fix:** Changed to `totalWeight += math.Abs(h.Amplitude)` in `synth/oscillator.go`
|
|
- **Files modified:** `synth/oscillator.go`, `synth/bank_test.go`, `config/config_test.go`
|
|
- **Commit:** c97682d
|
|
|
|
**2. [Rule 1 - Bug] Updated TestStereoPan for new ClassDHCP pan value**
|
|
- **Found during:** Task 2 verification
|
|
- **Issue:** TestStereoPan expected ClassDHCP to be left-panned (old pan=-0.75) but new config has pan=0.1 (right-biased)
|
|
- **Fix:** Changed test to use ClassSSH (pan=-0.7, clearly left-biased in new config)
|
|
- **Files modified:** `synth/bank_test.go`
|
|
- **Commit:** c97682d
|
|
|
|
**3. [Rule 1 - Bug] Updated config_test.go for new default values**
|
|
- **Found during:** Task 2 running `go test ./...`
|
|
- **Issue:** Two config tests had hardcoded values from old defaults (ICMP WaveformCustom, HTTPS BaseHz=175.0)
|
|
- **Fix:** Changed assertions to derive expected values from `synth.ClassFreqConfigs` defaults
|
|
- **Files modified:** `config/config_test.go`
|
|
- **Commit:** c97682d
|
|
|
|
## Known Stubs
|
|
|
|
None. All 14 ClassFreqConfigs entries have populated Group, Hz, waveform, and harmonics. Phase 10 slot placeholders are documented in comments only.
|
|
|
|
## Self-Check: PASSED
|
|
|
|
- synth/config.go: FOUND
|
|
- synth/config_test.go: FOUND
|
|
- synth/oscillator.go: FOUND
|
|
- 09-01-SUMMARY.md: FOUND
|
|
- Commit 812f0de: FOUND (feat: Group field + rebalanced ClassFreqConfigs)
|
|
- Commit c97682d: FOUND (fix: TestGroupFieldPopulated + oscillator normalization + test updates)
|