app+docs: 参考帧窗口参数化(baselineFrames, 默认4)——实测延长到8会把开快门帧收进参考导致不稳定;结论:需快门感知的参考收集

This commit is contained in:
ZXCLI
2026-10-06 04:47:36 +08:00
parent 1d6c5e3e55
commit 3510bdc774
4 changed files with 43 additions and 12 deletions
@@ -20,6 +20,16 @@ class RenderPipeline(
private val ffcPeriod: Int = 1800, private val ffcPeriod: Int = 1800,
private val ffcDrift: Int = 250, private val ffcDrift: Int = 250,
private val warmFrames: Int = 20, private val warmFrames: Int = 20,
/**
* Number of *settled* shutter frames averaged into the FFC reference.
*
* The official core feeds every frame of the shutter window into
* `CAccumulator` (`CFunctions::PushBaselineRaw`), so its reference is much
* cleaner than a short 4-frame average — which is why the official image
* shows less residual FPN (fewer stripes) at the same frame-to-frame noise.
* Default 4 keeps the byte-exact C reference behaviour (tests).
*/
private val baselineFrames: Int = 4,
private val cdfPivot75: Boolean = true, private val cdfPivot75: Boolean = true,
private val force75: Boolean = true, private val force75: Boolean = true,
/** FFC command callback: param 0 = FFC(0), 1 = FFC(1). */ /** FFC command callback: param 0 = FFC(0), 1 = FFC(1). */
@@ -224,8 +234,9 @@ class RenderPipeline(
for (i in 0 until npix) refAcc[i] += frame[i] for (i in 0 until npix) refAcc[i] += frame[i]
} }
refCnt++ refCnt++
if (refCnt >= 4) { if (refCnt >= baselineFrames.coerceIn(1, 64)) {
for (i in 0 until npix) ref[i] = refAcc[i] shr 2 val n = refCnt
for (i in 0 until npix) ref[i] = refAcc[i] / n
refCnt = 0 refCnt = 0
hasRef = true hasRef = true
} }
@@ -609,15 +620,16 @@ class RenderPipeline(
if (idx == 1) rebuildTables(shutterAtFfc) if (idx == 1) rebuildTables(shutterAtFfc)
return 1 return 1
} }
if (idx <= 9) { val refEnd = 5 + baselineFrames.coerceIn(1, 64)
if (idx == 9) onFfc?.invoke(1) if (idx <= refEnd) {
if (idx == refEnd) onFfc?.invoke(1)
if (idx == 6) { if (idx == 6) {
refCnt = 0 refCnt = 0
hasRef = false hasRef = false
} }
return 2 // ref collection window return 2 // ref collection window
} }
if (idx <= 13) return 1 if (idx <= refEnd + 4) return 1
// normal frame: FFC condition // normal frame: FFC condition
var drift = shutterIn - shutterAtFfc var drift = shutterIn - shutterAtFfc
if (drift < 0) drift = -drift if (drift < 0) drift = -drift
@@ -324,6 +324,11 @@ class IrSession(context: Context) {
// off the two distributions coincide (median 50 vs 61, mean 80 vs 82). // off the two distributions coincide (median 50 vs 61, mean 80 vs 82).
// See docs/android_app/rendering_diff_phone_20261006.md §8. // See docs/android_app/rendering_diff_phone_20261006.md §8.
cdfPivot75 = false, cdfPivot75 = false,
// baselineFrames stays at the verified 4: extending the window to 8 made
// the output *unstable* (frame-to-frame gray noise 3.95 -> 8.8), i.e. the
// device re-opens the shutter earlier than our schedule assumes, so the
// extra frames poison the reference. A shutter-aware reference
// collection is the follow-up (docs/android_app/rendering_diff_phone_20261006.md §9.4).
onFfc = { param -> onFfc = { param ->
sendCmd( sendCmd(
MagProtocol.cmd8(MagProtocol.CMD_SET_SHUTTER_STATE, param), MagProtocol.cmd8(MagProtocol.CMD_SET_SHUTTER_STATE, param),
Binary file not shown.
@@ -241,10 +241,24 @@ raw 帧**逐个推进 `CAccumulator`(`Reset(pixels, baseLineAcc=4, 0)`,mode
每次 FFC `Restart`)→ 参考帧是"长窗口指数平均";而我们 `refPush` 只做**4 帧等权平均** → 每次 FFC `Restart`)→ 参考帧是"长窗口指数平均";而我们 `refPush` 只做**4 帧等权平均** →
参考帧噪声显著更大 → 残余条纹更多 ✗。 参考帧噪声显著更大 → 残余条纹更多 ✗。
### 9.4 下一步(精确) ### 9.4 参考帧窗口的实测与教训(已参数化,默认仍 4 帧)
1. 把我们的参考帧收集改成与官方一致:FFC 窗口内**逐帧 IIR 累积**(权重 = `CAccumulator` 把参考窗口从 4 帧延长到 8 帧(`RenderPipeline.baselineFrames`)后实测:
的 mode,来自 BasePara2.baseLineAcc=4;窗口长度按官方 baseline 状态持续时长),
`IrSession`/`RenderPipeline` 的黄金测试继续用文档化的旧配置(默认 4 帧等权)以免破坏 C 对齐; | 配置 | 灰度空间 HF | 灰度帧间噪声 |
2. 装机用同一套灰度域指标回归:目标空间 HF ≈0.34(±20%)、帧间噪声保持不变; |---|---|---|
| 官方 App | 0.34 / 0.26 | 4.12 / 1.80 |
| 我们 baseline=4(原状) | 0.76 / 0.80 | 4.02 / 3.95 |
| 我们 baseline=8 | 0.77 / 0.84 | **9.91 / 8.83(变差 ✗)** |
→ **不能盲目延长窗口**:设备和我们的 FFC 时序里,快门窗口比"6…13 帧"短,
多收的帧实际是**开快门**帧,把参考污染了(输出不稳定)。参考帧收集必须
**感知快门状态**(例如按帧统计判断快门是否关闭),而不是按固定帧号取。
### 9.5 下一步(精确)
1. 参考帧收集改成**快门感知**:在 FFC(0) 之后逐帧判断"是否仍为闭合快门帧"
(可用帧统计/与前一帧的差异判断),把**所有闭合帧**都累积进参考(对齐官方
`PushBaselineRaw` 的语义),FFC(1) 之后重置;
2. 用同一套灰度指标回归:目标空间 HF ≈0.34、帧间噪声 ≤4;
3. 之后同步 csdk(pivot + 温度链 + 参考累积)。 3. 之后同步 csdk(pivot + 温度链 + 参考累积)。