Skip to content

feat(ft8): add native multistream QSO and WW Digi contest support - #91

Open
boybook wants to merge 23 commits into
mainfrom
codex/ww-digi-multistream
Open

feat(ft8): add native multistream QSO and WW Digi contest support#91
boybook wants to merge 23 commits into
mainfrom
codex/ww-digi-multistream

Conversation

@boybook

@boybook boybook commented Aug 25, 2026

Copy link
Copy Markdown
Owner

概要

本 PR 原生加入 WW Digi FT4/FT8 比赛模式,并补齐它所依赖的通用基础能力:

  • 单个操作员内的稳定子流身份与一次决策多条发射报文
  • 单操作员多子流和多操作员共用的全局 RF 混音、功率回退与物理完成链路
  • 从现有辅助队列中抽出的可复用并行 QSO 协调器
  • 符合“每个新目标必须由操作员发起”的 WW Digi 手动授权交互
  • 通用 ADIF 持久化、比赛账本投影和 Cabrillo 3.0 输出
  • 操作员组件对真实多子流发射内容、状态和频率的完整展示

本次没有把并行通联做成 WW Digi 的特例。Host 负责 RF 准入、物理帧、混音、持久化和安全边界;插件负责协议状态机、队列策略和比赛语义。

规则与日志格式参考:

设计约束

  1. 每个新通联目标必须由操作员点击加入队列;插件不会自动选择 CQ 或来呼作为新目标。
  2. 一次人工动作只授权相应目标进入队列,不授权未来未知目标。
  3. WW Digi 默认最多并行 3 路;操作员级上限默认 3,可手动配置为 1 至 5,最终取操作员上限与策略上限的较小值。
  4. 单操作员多子流与既有多操作员发射必须进入同一物理混音链路,不能绕开全局功率约束。
  5. QSO 只有在 Host 接受决策、实际发射得到物理确认并且通用日志持久化成功后,才从活动队列释放。
  6. 旧的单流插件和 TX1 至 TX6 操作方式必须保持兼容。

架构数据流

操作员点击目标
  -> 带 authorizationId 的队列项
  -> ParallelQSOCoordinator 分配稳定 ProtocolLane
  -> StrategyRuntime.getTransmissions() 返回完整 transmission set
  -> DecisionOrchestrator 校验策略上限、操作员上限和目标预约
  -> RadioOperatorManager 原子准入该操作员的完整子流集合
  -> WSJTXEncodeWorkQueue 按 operatorId + streamId 编码独立 track
  -> DigitalFrameCoordinator 形成不可变物理帧
  -> AudioMixer 对所有操作员和子流做全局线性混音
  -> TransmissionPipeline 播放并返回逐流物理回执
  -> ProtocolLane 推进协议状态并产生 QSO completion effect
  -> 通用日志持久化
  -> 插件收到 settlement,更新比赛账本并释放队列项

1. 子流与批量传输模型

Plugin API 与 Contracts

  • 新增稳定 streamId,并以 operatorId + streamId 组成 Host 内部 trackId
  • StrategyTransmission 同时携带子流身份、精确报文和音频中心频率。
  • StrategyDecisionResult.transmissions 允许一次决策返回多条报文;旧策略仍可只实现 transmission / getTransmitText(),由 Host 映射到 default 子流。
  • StrategyStreamSnapshot 独立投影每条子流的协议状态、目标、网格、频率和 QSO lifecycle epoch。
  • StreamPhysicalReceipt 将物理确认按子流返回插件,协议不能仅因“已排队”就推进发射次数。
  • QSO completion/failure、持久化 settlement 和 lifecycle 事件均可携带 streamId
  • 策略声明增加 parallelTargetQueuequeueActivationmanualInitiation 和策略级并发上限。

Host 原子性

  • 同一操作员一次决策产生的完整 transmission set 作为一个准入单元处理。
  • 任意子流包含未解码占位符、过期 decision epoch、重复发射保护失败或周期不合法时,整组拒绝,不会只发剩余子流。
  • 已 prepared/committed 的混合帧中任一参与者变化时,重建完整物理帧,避免旧波形和新意图拼接。
  • 同一物理帧仍可容纳多个操作员;一个操作员的整组失败不会错误移除其他仍合法的操作员。
  • 严重音频输出失败后按每个 track 保留原始意图并重排到下个合法周期。

生命周期与目标预约

  • 目标预约从“一个操作员一个目标”扩展为每个 stream 独立目标,同时仍阻止同呼号操作员并发争抢同一远端。
  • QSO lifecycle、未保存恢复、持久化重试和物理完成均按 stream 隔离。
  • preserve-distinct 持久化策略允许比赛中的重复 QSO 保留为独立记录,不被原有五分钟邻近 QSO 合并逻辑吞并。
  • 多条 QSO completion 由 Host 按操作员顺序提交;每条写入使用日志本 revision guard,单条失败会保留未保存状态并阻止错误进入下一生命周期。

2. 全局 RF 混音与功率/IMD 边界

  • FrameAudioRepository 和物理帧由 operator 维度扩展到 track 维度,支持一个操作员贡献多条音频波形。
  • 单路混音保持原始逐样本波形不变,避免改变既有发射电平。
  • 多路混音先按各轨 RMS 做等功率分配,再将总 RMS 目标设置为最强输入参考值回退 6 dB。
  • 若全局峰值仍超过 0.95,只对整帧做统一线性回退;不使用 limiter、compressor 或逐样本 clipping,以免主动制造互调产物。
  • 混音结果记录 track 数、目标/实际 RMS、峰值、crest factor、最终线性增益、每轨增益、中心频率和最小间隔,供后续假负载校准与诊断使用。
  • Host 在全部操作员和子流范围校验音频范围及最小间隔:FT8 60 Hz、FT4 100 Hz。
  • 现有多操作员混音没有被禁用;它与单操作员多子流共享完全相同的准入、帧和功率控制机制。

软件只能约束送入声卡/调制链路的线性 PCM,不能证明真实发射机、ALC、功放和天线系统的 RF IMD 合规。假负载校准向导留作后续工作。

3. 可复用并行 QSO 队列

新增 _shared/parallel-qso,将“队列调度”和“具体通联协议”拆开:

  • ParallelQSOCoordinator 管理有版本号的队列、稳定 lane 绑定、补位、重排、删除、清空、checkpoint/restore 和逐流 settlement。
  • ProtocolLane<TData> 只负责一个目标的协议状态机、下一条报文、物理回执和 QSO effect。
  • Coordinator 保证同时活动的 lane 使用兼容的 TX 周期,并按配置容量从已授权队列补位。
  • 任一 speculative decision 抛错时由既有 checkpoint/restore 边界整体回滚,不留下半更新的队列或子流状态。

辅助队列迁移

  • 现有辅助队列改用同一 Coordinator,并通过 StandardQSOProtocolLane 保留标准 TX1 至 TX5 协议语义。
  • 默认仍为 1 路,可配置为 1 至 3 路。
  • queueActivation: immediate 保持首个目标可启动空闲操作员的既有体验。
  • 受既有设置控制的自动来呼入队、优先级、等待状态和 CQ 回退继续保留。

WW Digi 差异

  • queueActivation: operator-toggle:加入目标只排队,不自动打开 TX 开关。
  • manualInitiation: 1:新目标只能由操作员双击/点击加入;requestCall() 明确拒绝自动起呼入口。
  • 已人工授权的等待目标可以在 lane 空闲后自动补位,因为补位不创造新的通联对象。
  • 空队列且 TX 已由操作员打开时发送 CQ WW <CALL> <GRID>

4. WW Digi 通联协议

专用 lane 支持 WW Digi 四位网格交换,并兼容对端使用标准报告流程的情况。

主动选择 CQ:

RX  CQ WW JA1AAA PM95
TX  JA1AAA BG5DRB OL32
RX  BG5DRB JA1AAA R PM95
TX  JA1AAA BG5DRB RR73

人工选择直接来呼:

RX  BG5DRB JA1AAA PM95
TX  JA1AAA BG5DRB R OL32
RX  BG5DRB JA1AAA RR73

兼容标准报告路径:

RX  BG5DRB JA1AAA -08
TX  JA1AAA BG5DRB R-10
RX  BG5DRB JA1AAA RR73

每条 lane 独立维护 wait-r-gridwait-rr73wait-standard-finalsend-rr73closingreview

  • 只接收匹配该 lane 目标和本机呼号的报文。
  • 只有逐流物理回执才增加发射次数或确认最终 RR73 已发出。
  • 完成后等待通用日志 settlement;持久化失败进入 review,不会静默释放目标。
  • 超过最大尝试次数的目标保留为 no-response,由操作员显式重试并生成新的 authorizationId。
  • 最终 RR73 后保留有界重发 lease,处理对端重复 R-grid 的常见收尾情况。

5. 应用交互与状态呈现

行为 辅助队列 WW Digi
默认并行数 1,可配置 1 至 3 3,可配置 1 至 3
加入首个目标 可立即启动 只入队,等待操作员打开 TX
自动选择来呼/CQ 保留既有设置控制 禁止
空队列 TX 标准 QSO CQ CQ WW <CALL> <GRID>
活动目标补位 支持 仅从已人工授权队列补位
协议 标准报告流程 网格交换,兼容标准报告收尾

前端调整:

  • 队列表可同时标记多个活动目标,并显示 stream、音频频率、等待/活动/closing/no-response/review 状态。
  • 操作员状态新增 Host 权威 currentTransmissions 投影;显式空数组不会回退到陈旧 TX slot。
  • TX 进度条显示实际待发射报文,多路时汇总全部报文并保留完整 tooltip。
  • 并行策略不再显示误导性的 TX6 下拉框;展开区以只读列表展示每路 ID、协议状态、目标、频率和精确文本。
  • 传统单流策略继续使用原有可编辑 TX1 至 TX6 UI;旧服务端省略新字段时仍回退 legacy slot。
  • 操作员设置新增 1 至 5 路的全局并发上限,新操作员默认 3。
  • Device UI 同样投影全部当前子流报文,不再只取一个 legacy slot。

6. 通用日志、比赛账本与 Cabrillo

通用 ADIF

  • 比赛 QSO 继续首先写入通用日志本,并携带 CONTEST_ID=WW-DIGI
  • ADIF 编解码与 Plugin API ADIF 工具均支持 CONTEST_ID 往返。
  • 每个并发 QSO 使用 preserve-distinct,确保同波段重复 QSO 保持为独立日志记录。

插件比赛账本

  • 插件按“操作员 + 比赛年份”保存独立账本投影,记录通用 QSO ID、streamId、authorizationId 和 included/X-QSO 状态。
  • 加载插件或操作员点击“重新对账”时,按比赛 24 小时窗口分页扫描通用日志恢复账本。
  • 对账只接受 CONTEST_ID=WW-DIGI、FT4/FT8、六个比赛波段、有效本机呼号和四位发送网格的记录。
  • 账本写入或对账失败会标记 degraded;在重新对账成功前禁止下载 Cabrillo,避免输出已知不完整日志。

Cabrillo 3.0

  • 下载时从健康账本确定性生成 .log,采用 CRLF 行尾。
  • 输出 CONTEST: WW-DIGICATEGORY-MODE: DIGI、band/power/location 等头字段。
  • QSO 行使用实际 RF 频率、FT4/FT8 的 DG 模式和双方四位网格;缺失接收交换写为 ZZ00
  • Dupe 按“对方呼号 + 波段”跨 FT4/FT8 判定,仍保留为普通 QSO,不删除。
  • 操作员可以显式将记录切换为 X-QSO,但 Dupe 不会自动变成 X-QSO。
  • 非美国/加拿大呼号的 LOCATION 默认 DX;美加参赛者需要填写有效 section。
  • 比赛面板提供 UTC 列表、Dupe 状态、Included/X-QSO 切换、重新对账和 Cabrillo 下载。

兼容性与失败安全

  • 旧单流 StrategyRuntime 不需要实现任何新方法,Host 自动生成 default stream。
  • TX1 至 TX6 编辑、标准 QSO、辅助队列单路默认行为和多操作员并发均保留。
  • partial decode / <...> 防线在完整 transmission set 上继续执行;任何一条非法会拒绝整组。
  • 物理失败、过期 decision、同文保护和频率变更均以 track 为单位重排或重建,但物理帧本身保持原子。
  • QSO 写入失败不会被当作成功 settlement;相关 lane 保持 review/unsaved 状态。
  • 比赛账本不是通用日志的第二事实源;它是可从 ADIF 日志重建、用于 Cabrillo 输出的独立投影。

当前边界

  • 尚未计算距离分、两位网格系数、总分或 CLAIMED-SCORE,最终分数由官方日志检查器计算。
  • 插件暂未在 RF 发射入口强制比赛日期、比赛波段或功率级别;比赛窗口和波段目前在账本/输出侧严格校验。
  • 仅生成 Cabrillo,不负责官网上传、提交截止提醒或提交状态跟踪。
  • Cabrillo 类别当前固定为 SINGLE-OP / ONE / DIGI / FIXED,仅开放 band、power 和 location;尚不支持多人比赛类别。
  • 同一次决策产生的多个 QSO 按操作员串行持久化,每条写入有 revision guard 和未保存恢复,但不是跨多条 QSO 的单个原子事务。
  • 插件不会每次 QSO 直接追加独立 .log 文件;它保存可对账账本,并在下载时生成 Cabrillo。
  • 普通呼号与 slash token 已覆盖;特殊哈希及更复杂复合呼号流程尚未专项验证。
  • 软件 RMS/峰值约束不能替代真实发射机的假负载频谱和 IMD 测试;校准向导未包含在本 PR。

Reviewer 导航

  • packages/plugin-api/src/runtime.ts:多子流 StrategyRuntime 公共契约
  • packages/builtin-plugins/src/_shared/parallel-qso/:可复用并行队列协调器
  • packages/builtin-plugins/src/ww-digi/:比赛协议、运行时、账本、Cabrillo 与面板
  • packages/server/src/plugin/DecisionOrchestrator.ts:决策校验、上限与逐流 settlement
  • packages/server/src/operator/RadioOperatorManager.ts:批量准入、持久化与失败恢复
  • packages/server/src/transmission/:track-aware 物理帧生命周期
  • packages/server/src/audio/AudioMixer.ts:全局线性功率归一与指标
  • packages/web/src/components/radio/operators/:队列和操作员多流交互

验证

  • yarn build:12/12 workspace tasks 通过
  • yarn workspace @tx5dr/contracts test:125/125
  • yarn workspace @tx5dr/core test:191/191
  • yarn workspace @tx5dr/plugin-api test:53/53
  • yarn workspace @tx5dr/builtin-plugins test:262/262
  • 受影响 Server 9 个测试文件:254/254
  • yarn workspace @tx5dr/web test:550/550
  • yarn lint:0 errors;保留 9 个既有 warnings
  • yarn check:i18n:通过
  • git diff --check:通过
  • 已认证 Electron 实测:WW Digi CQ 实际报文显示在 TX 进度条;并行策略不再显示虚假 TX6;展开区正确显示 stream、频率和报文且无布局遮挡

@boybook
boybook force-pushed the codex/ww-digi-multistream branch 2 times, most recently from 729bd4c to 48a7eba Compare August 25, 2026 13:19

boybook commented Aug 25, 2026

Copy link
Copy Markdown
Owner Author

补充标准频率硬限制(23ef7dc3):

  • FT8/FT4 标准拨盘频率表与 ±1500 Hz 判定已下沉到 Core,由 Web Alert 和 Server 共用。
  • 当操作员使用 WW Digi 且当前命中标准频率时,操作员列表显示高亮 Alert,并禁止从关闭状态开启 TX;策略配置、队列整理和历史日志仍可使用。
  • Server 在 startOperator、预编码准入、初次 PTT validateStart 和 active-lease replacement 最终播放前均重新检查;CAT 竞态不能绕过 RF 门。
  • WebSocket 在恢复 transmit-control 插件前先做无副作用预检。

验证:Core 195/195、Web 565/565、RadioOperatorManager 80/80、TransmissionPipeline 21/21、PhysicalTxCoordinator 28/28;整仓构建 12/12、lint 0 error、i18n 与 diff check 通过。

@boybook
boybook force-pushed the codex/ww-digi-multistream branch 2 times, most recently from 37920a6 to 7061dd1 Compare August 28, 2026 16:28
@boybook
boybook force-pushed the codex/ww-digi-multistream branch from 7061dd1 to b901452 Compare August 28, 2026 17:38
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant