一、问题描述
tuning同学按照公式配置固定30fps的曝光表后,实际出帧略小于30fps。
二、公式说明
帧长与曝光时长的关系: 帧长 >= 曝光时长 + blanking时长
环境较暗(需要最大曝光,即ExposureTime + Blanking Time = Frame Time)时的整个计算流程为:
- tuning根据驱动中配置的verticalOffset值计算出Blanking time,填入曝光表:
BlankingTime = lineReadOutTime * verticalOffset
= 1 / fps / fll * verticalOffset
/* verticalOffset: sensor特性,需要framelength >= linecount + verticalOffset; */
- AEC库通过 帧长 - Blanking time 得到能支持的最大曝光时间输出:
问题场景需要固定30fps,即minFPS = 30fps
计算过程:
- hal部分拿到曝光时间后,转换成linecount,传入驱动写入sensor寄存器,控制采样时的曝光时间
汇集代码总结转换关系为:
VTPixelClock = static_cast<UINT64>(pResData->lineLengthPixelClock * pResData->frameLengthLines * pResData->frameRate);
lineReadoutTime = (lineLengthPixelClock * NanoSecondsPerSecond) / VTPixelClock;
DOUBLE lineCount = = static_cast<DOUBLE>(exposureTimeNS) / GetLineReadoutTime(resolutionIndex, inputSeamlessType);
简化后:
lineCount = exposureTimeNS * pResData->frameLengthLines * pResData->frameRate / NanoSecondsPerSecond
- linecount计算完成后,比较 linecount + verticalOffset 与xml中配置的frameLengthLines值,取较大值写入sensor framelength 寄存器,这个值实际决定了sensor出帧的帧率。
frameLength = max(linecount + verticalOffset, pResData->frameLengthLines);
三、实际计算过程
Blanking time = NanoSecondsPerSecond / (pResData->frameRate * pResData->frameLengthLines) * verticalOffset
= 1000000000÷30.14÷2044×20 =324643(ns)
Exposure time = NanoSecondsPerSecond / minFps - Blanking time
= 1000000000 / 30 - 324643
= 33008690.333333333(此处AEC库实际输出33008692)
lineCount = exposureTimeNS * pResData->frameLengthLines * pResData->frameRate / NanoSecondsPerSecond
= 33008692 * 2044 * 30.14 / 1000000000
= 2033.538760743 (实际传出2034)
frameLength = max(linecount + verticalOffset, pResData->frameLengthLines);
= max(2034 + 20, 2044)
= 2054
- 此时再用frameLength值反推帧率:
cur fps = (pResData->frameLengthLines * pResData->lineLengthPixelClock * pResData->frameRate) / (pResData->lineLengthPixelClock * frameLength)
= (pResData->frameLengthLines * pResData->frameRate) / frameLength
= 2044 * 30.14 / 2054
= 29.993261928
可以看到实际计算结果中fps 略小于30fps。
四、问题点分析
一般情况下固定30fps时,我们都倾向于使用setting中配置的framelength,通过framelength反推曝光时间:
Exposure Time = linecount * NanoSecondsPerSecond / (pResData->frameRate * pResData->frameLengthLines)
= (pResData->frameLengthLines - verticalOffset) * NanoSecondsPerSecond / (pResData->frameRate * pResData->frameLengthLines)
= (pResData->frameLengthLines * NanoSecondsPerSecond / (pResData->frameRate * pResData->frameLengthLines)) - (verticalOffset * NanoSecondsPerSecond / (pResData->frameRate * pResData->frameLengthLines))
= NanoSecondsPerSecond/pResData->frameRate - Blanking time
= 1000000000/30.14 - 324643
= 32853857.331785003
对比此处的公式与三、2的公式:
Exposure time = NanoSecondsPerSecond / minFps - Blanking time
Vs
Exposure time = NanoSecondsPerSecond / pResData->frameRate - Blanking time
就可以看到差异点主要在fps的取值不同,导致了计算出的曝光时间不同。
- 使用公式推导验证:
1s: NanoSecondsPerSecond
fll: pResData->frameLengthLines
ll: pResData->lineLengthPixelClock
fps: pResData->frameRate
vO: verticalOffset
vtclk: VTPixelClock
汇总第二点的所有公式并简化过程如下:
linecount = ((1s/minFPS) - (1s/fps/fll*vO))/lineReadoutTime
= ((1s/minFPS) - (1s/vtclk*ll*vO))/(1s*ll/vtclk)
= (1s/minFPS)/(1s*ll/vtclk) - (1s/vtclk*ll*vO)/(1s*ll/vtclk)
= vtclk/(ll*minFPS) - vO
= (fll*ll*fps)/(ll*minFPS) - vO
= fll*(fps/minFPS) - vO
可以看到,当sensor setting中配置的pResData->frameRate值与minFPS差异较大时,就会出现tuning配置根据verticalOffset计算的值,但一套流程之后,实际写入的framelength值大于sensor setting中配置的pResData->frameLengthLines值。加上精度损失,就有可能出现实际帧率略小于30fps的情况。