入行相机调试这几年,高通平台的Chromatix AEC是我打交道最多的一块。手机拍照第一眼好不好看,拼的就是曝光准不准、画面亮暗舒服不舒服,而背后绕不开两样东西:曝光表配置和传感器参数计算。很多刚转行做Tuning的同事拿到chromatix.xml就发懵——字段多、层级深,还和sensor驱动里的曝光寄存器参数纠缠在一起,调起来一头雾水。
这篇文章我打算把Chromatix AEC的完整逻辑捋一遍:从曝光表在自动曝光链路里的定位讲起,到传感器那些绕不开的数学公式,再到实际配置时的字段选择和标定流程,最后把我这些年踩过的坑和排查经验一并分享出来。内容偏中层,适合刚接触Camera Tuning的工程师、做sensor驱动的同学,也适合想深入理解相机自动曝光原理的嵌入式视觉从业者。哪怕你现在只看得懂一点点,照着思路走一遍,再回头打开chromatix.xml,感受会完全不一样。
1. 曝光表在AEC链路中的定位:先搞懂它在管什么
1.1 从一帧采集到曝光决策:AEC到底做了什么
我习惯把一个自动曝光周期拆成三拍:统计、决策、执行。第一拍,sensor把光信号转成电信号,RAW数据进ISP后,由AE统计模块算出一帧的亮度特征——通常是Y通道均值、分区块的亮度直方图,还有按权重区域统计的中心亮度和边缘亮度。第二拍,AEC算法拿到这些统计量,结合上一帧的曝光参数,估计当前场景的实际亮度水平,并判断画面是过曝了还是欠曝了。第三拍,算法决定下一帧用什么曝光时间、什么增益组合,写回sensor寄存器,完成一轮闭环。
这三拍听起来不复杂,但真正干过的人都知道,难点全在第二拍的“决策”上。这里并没有一个万能公式能覆盖所有sensor、所有镜头、所有光照条件。sensor的量子效率不一样,镜头的F数不一样,ISP的降噪能力不一样,甚至同一颗sensor在不同帧率下噪声表现都不同。所以高通平台选择了一个工程上非常务实的做法:把“亮度—曝光参数”的对应关系提前做成一张表,让AEC算法在运行时通过查表和插值来决策。
这张表,就是我们常说的曝光表,对应到Chromatix里就是AEC配置中最核心的一组数据。它的地位相当于一套“预设答案”,实验室里调好的参数组合,到用户手里遇到各种光线场景时,AEC就按照这套答案快速收敛。曝光表配得好,算法怎么跑都稳;配得烂,算法再努力也挽救不了忽明忽暗的画面。所以做Tuning的人经常说:调AEC本质上是调这张表,算法反而很少去动。
1.2 曝光表里到底存了什么:核心字段初窥
第一次打开Chromatix工具里的AEC表格时,很多人会看到密密麻麻的索引和数值。别怕,拆开看其实就几类东西。
第一类是亮度索引。常见的字段名类似EV Index、AEC Index、Luma Target等。它负责给不同亮度的场景编号,暗光场景在低索引,强光场景在高索引。这些索引在运行时就是查表的“行号”,AEC会根据前一帧的统计亮度,落在一个索引附近,然后读取该行对应的参数。
第二类是曝光参数组,通常包括曝光行数(Exposure Lines)、模拟增益(Analog Gain)、数字增益(Digital Gain)、短帧曝光比例(如果是HDR场景还会有不同时隙的曝光)。这几个值是一个组合,AEC查到索引之后,把这三个参数下发到sensor和ISP,就完成了一次曝光配置。
第三类是约束条件,常见的有最大曝光行数、最小曝光行数、数字增益上限、模拟增益上限、帧率限制等。约束条件决定了AEC在极限场景下能走到多远。比如夜景模式,你会允许模拟增益推到很高,但数字增益卡在2x以内,防止噪点爆炸;而白天场景则反过来,优先保证帧率,曝光行数不能超过某一阈值。
这里有个很多人忽略的关键点:曝光表里的索引通常不是线性的,而是按log分布组织的。因为人眼对亮度的感知是近似对数的,低照度区域稍微亮一点就有明显感知差异,高照度区域变化很大但视觉上差别不大。所以曝光表在暗部要更密,亮部可以拉稀一点。如果不懂这个逻辑,一上来就按线性间隔填表,后面必然后悔。
2. 传感器参数计算:所有曝光配置的数字地基
2.1 必须背下来的核心公式
很多人调曝光表时只盯着增益和曝光值,却忽略了传感器端其实是用“行”来计时的。曝光时间不是直接写“10毫秒”,而是换算成“多少行曝光”;帧率也不是只改驱动里的一个变量,而是由行长度和帧长度共同决定的。
这组公式是任何sensor调试绕不开的地基。我用最常见的定义写出来:
- 像素时钟 PCLK = MCLK × PLL倍频系数
- 行时间 Line_Time = HTS / PCLK
- 帧率 FPS = PCLK / (HTS × VTS)
- 曝光时间 Exposure_Time = Exposure_Lines × Line_Time
先解释一下这几个符号。MCLK是sensor的主时钟,一般由平台提供,常见值有19.2MHz、24MHz、26MHz;PLL倍频系数是sensor内部锁相环的配置,用来把低频的主时钟倍频到像素采样频率。HTS(Horizontal Timing Signal)就是一行有多少个像素时钟周期,也叫行长度;VTS(Vertical Timing Signal)就是一帧有多少行,也叫帧长度。
举个实际例子。假设一颗sensor的MCLK是24MHz,PLL倍频后PCLK跑到160MHz,HTS配成4000。那么:
- 行时间 = 4000 / 160MHz = 25微秒
- 如果VTS配成4000,帧率 = 160MHz / (4000 × 4000) = 10fps
- 此时如果曝光行数是1000行,曝光时间 = 1000 × 25微秒 = 25毫秒
这几个数一旦建立直觉,你再看驱动里的寄存器配置就不会觉得是一堆乱码了。sensor datasheet里通常会把HTS和VTS的取值范围、PCLK和MCLK的倍频表都给出来,调试的第一步就是把这些参数对清楚。我见过太多问题,最后追根溯源都是HTS填错一位导致PCLK计算偏差,整张曝光表的标定全部作废。
2.2 曝光行数到底怎么定:帧率与曝光上限的平衡
这里必须展开讲一个很多初学者容易踩的坑:曝光行数不是想设多少就设多少,它受VTS的天花板限制。
一个rolling shutter曝光的基本原理是,sensor逐行曝光,一帧内所有行的曝光结束时间不能超过这一帧的总行数范围。也就是说,曝光行数如果超过VTS,传感器硬件就会自动扩展帧长度,保证最后几行的曝光能被完整落下。但这样做的后果是实际帧率突然掉下来,实时预览帧率不稳,回放画面或者取景框都会卡顿。
所以在配置曝光表时,每个索引下的最大曝光行数,都必须和当前帧率下的VTS对齐。假设你想在30fps下工作,VTS对应的总行数如果按PCLK 160MHz算,一行25微秒,一帧33.3毫秒。要保证帧率不跌,曝光行数+消隐行数必须小于等于VTS。通常VTS等于有效行加上垂直消隐,最大曝光行数不建议超过VTS的90%左右,留一点余量给sensor内部处理时序。
反过来,当你需要拉高曝光时间的时候,就得考虑降低帧率。比如预览30fps,单帧33毫秒,去掉消隐,最大曝光可能只有30毫秒出头。如果暗光下一次曝光需要60毫秒,那就只能把VTS拉大,帧率降到15fps甚至更低。夜景模式就是这么干的,牺牲帧率换取亮度。很多芯片平台的AE策略里,会有“长曝光优先”和“帧率优先”两套模式,背后其实就是调节VTS和曝光行数的关系。
2.3 增益计算与dB换算
曝光时间只是曝光的“长度”维度,增益是另一个维度。sensor增益分模拟增益和数字增益。模拟增益在感光读出时放大信号,信噪比相对较好;数字增益在ADC之后做乘法,噪声也会被同步放大,所以能用模拟增益解决的问题,尽量不要依赖数字增益。
增益换算是曝光表配置里另一个高频操作。硬件增益值转dB,最常用的公式是:
Gain_dB = 20 × log10(Gain)
几个常见的换算值:
- 1x = 0dB
- 2x = 6.02dB
- 4x = 12.04dB
- 8x = 18.06dB
曝光表里通常以线性增益出现,但这个线性增益是“总增益”,等于模拟增益乘以数字增益。举个例子,曝光表某一行写总增益4x,你可以拆成模拟增益2x、数字增益2x,也可以拆成模拟增益4x、数字增益1x。两种方案画质表现差别很大,前者数字增益被放大的噪声相对少一些,后者全程用模拟增益,但可能受sensor模拟增益档位限制。
我自己的经验是,配置时优先把模拟增益推到8x甚至16x(视sensor能力),数字增益只用来补尾数,尽量别超过2x。超过2x之后,暗部噪点涨得肉眼可见。当然,如果场景特别暗,数字增益也可以再拉一拉,但这时一定要在曝光表里注明画质风险点,免得后来的人接手时一头雾水。
这里放一张参数速查表,方便大家日常对照:
| 参数 | 公式/来源 | 示例值 |
|---|---|---|
| MCLK | 主时钟输入 | 24 MHz |
| PCLK | MCLK × PLL倍频 | 160 MHz |
| HTS | 行长度 | 4000 PCLK |
| VTS | 帧长度 | 4000 lines |
| 行时间 | HTS / PCLK | 25 us |
| 帧率 | PCLK / (HTS × VTS) | 10 fps |
| 曝光行数 | 曝光时间 / 行时间 | 1000 lines |
| 曝光时间 | 曝光行数 × 行时间 | 25 ms |
| 总增益 | 模拟增益 × 数字增益 | 4x |
| 增益dB | 20 × log10(增益) | 12.04 dB |
3. 曝光表配置实操:从Chromatix字段到一帧好画面的落地
3.1 理解Chromatix里的AEC数据结构层级
高通平台的Chromatix看起来像一套庞大的配置文件树,但AEC相关的结构并没有想象中那么复杂。刚开始推荐先把AEC库的参数区分为两个层级:全局控制层和表格数据层。
全局控制层通常包括AEC的使能开关、工作模式(正常、HDR、夜景)、帧率策略、曝光优先级、防闪策略等。这些字段像“总指挥”,决定AEC算法在宏观上的行为。比如你把AE Exposure Priority设成优先维持帧率,算法在暗光下就会更早切到高增益,牺牲一点画质保住流畅度。
表格数据层就是前面说的曝光表本体。每一行是一条曝光索引记录,包含曝光行数、模拟增益、数字增益,以及可选的最大最小限制。部分平台还支持把表格按场景拆分,比如室内混合光源一套表、户外强光一套表,通过场景检测结果切换。
看Chromatix配置的时候,我习惯先按“全局字段→每条索引→限制条件”的顺序去读。全局字段定大方向,索引定具体参数,限制条件定边界。如果直接一头扎进几百行表格里,很容易把配置改乱。记住一句话:先看少数的几个全局开关对不对,再查表和sensor参数的物理含义对不对,最后才动手改数值。
3.2 曝光表参数配置示例与标定流程
下面用我调试过的一颗50MP sensor为例子,演示一张基础曝光表的搭建思路。这颗sensor的PCLK是160MHz,HTS是4200,行时间约26.25微秒,支持模拟增益最高32x,数字增益上限16x。预览模式跑30fps,VTS默认约3968行,最大曝光行数约3500行。
第一步,确定最低亮度和最高亮度的索引范围。暗光下限我按曝光时间100毫秒、总增益32x来定,强光上限按曝光时间1毫秒、总增益1x来定。这两个端点之间的动态范围接近100dB,按每1/3EV一档来划分,大概要40到50个索引点。
第二步,确定低频段的参数组合。以索引10代表暗光档为例,曝光行数我填80%(约2800行)左右,模拟增益推到16x,数字增益补2x,总增益32x。为什么不直接把模拟增益顶到32x?因为我实测这颗sensor在模拟增益超过16x后,暗电流和行噪声抖动明显,反而影响暗部画质。这类经验只能靠实测积累,datasheet上写的是支持范围,不代表画质最佳范围。
第三步,切中高频段的参数。当亮度上升到索引20附近,曝光行数降到200行左右,主要是为了压低运动模糊;模拟增益降到8x,数字增益降到1x。再往亮处走,曝光行数线性下降,增益逐步归到1x。到了强光索引,曝光行数可以低到100行甚至更少,但这时候要注意:曝光行数太短会带来另一个问题——行曝光时长太短,行方向上的光线响应不一致可能引入banding,一般不建议低于某条阈值。
这个流程走完,曝光表初版就算出来了。把初版烧进设备,再用积分球和灰阶卡做实拍验证,看哪些索引段的位置偏了,逐段微调。调表的本质就是“预设—实测—修正”的循环,多跑几轮自然就准了。
3.3 实战中的参数组合与优先级策略
曝光表的最终形态,不只是填数值那么简单,更重要的是定好“优先级策略”。我用一个很生活化的例子解释:一桌菜,食材就三样:曝光时间、模拟增益、数字增益。不同场景下该多放哪一样、少放哪一样,就是策略。
在明亮场景,优先压缩曝光行数。因为光线足够,短曝光也能正常出图,还能降低运动模糊,画面更干净。在中等光照,优先提高曝光行数到安全上限附近,因为曝光时间加长带来的增益需求下降,性价比最高。在暗光场景,曝光行数快到头了,开始抬高模拟增益,同时注意噪声。模拟增益顶到画质上限后,才允许数字增益介入收尾。
这个顺序我建议写进配置注释里。很多后来接手的工程师只看表格数值,看不出当时的策略意图,遇到一个暗光场景的曝光数据就去乱改,结果白天画质被连累。调试文档和代码注释不是给别人看的,是给几个月后的自己看的。
此外,防闪(Anti-Banding)必须在曝光表里体现。室内60Hz电网环境下,曝光时间尽量对齐8.33毫秒的整数倍;50Hz环境下对齐10毫秒的整数倍。一旦曝光时间落在这些周期之外,画面就会出现滚动明暗条纹,非常影响观感。很多sensor支持自动banding检测,但曝光表端也要配合,不要把有效曝光行数定在两个工频周期相冲突的位置上。
4. 常见问题与排查技巧实录
4.1 问题一:预览画面突然闪一下、亮度跳变
这是我遇到次数最多的一个问题,概率高达所有AEC问题的三分之一。现象是画面明明稳定,某一瞬间突然亮一下或者暗一下,然后马上恢复。排查思路先看曝光表的增益步进。如果某两个相邻索引之间,模拟增益从2x直接跳到8x,步进太大,AEC在临界亮度附近来回找平衡点时,画面就会有可见的跳动。
解决方法是把相邻索引的增益步进控制住,一般建议模拟增益每挡差不超过2倍,理想是1.5倍以内。同时可以在参数里增加smooth factor,让算法在切换曝光索引时做插值过渡,而不是瞬间跳变。还有一个容易忽略的点:曝光行数和增益同时切换时,总曝光量的变化可能不成比例,导致亮度跳变更明显。所以我一般建议先单独调曝光行数,等亮度接近目标后,再平滑切换增益,尽量避免两者同时大幅度变化。
4.2 问题二:高帧率模式下画面发暗
高帧率慢动作模式(比如240fps、360fps)下,单帧时间被压缩到4毫秒甚至更低,曝光行数可用的空间非常小。如果曝光表还是按普通模式那套参数,画面发暗几乎是必然的。这个时候就应该提高增益来补偿曝光时间的缩短,具体做法是单独给高帧率模式做一张曝光表,把各亮度索引的增益整体抬高,暗光场景甚至允许数字增益顶到4x以上,只要用户接受该模式下的噪点就好。
另外,高帧率模式还要注意sensor的短曝光线性区间。有些sensor在曝光行数小于一定阈值后,实际曝光量和理论值呈非线性关系,会导致曝光表完全失效。遇到这种情况,不要硬调参数,先查datasheet里的short exposure线性范围,把曝光行数的下限拉高,再用ND镜或者增益来补。
4.3 问题三:室内灯光下出现滚动横条纹
滚动横条纹十有八九和工频闪烁有关。先确认当前环境的电网频率是50Hz还是60Hz,国内和欧洲大部分是50Hz,美国日本等地是60Hz。再检查AEC防闪功能是否打开,以及曝光时间是否为对应周期的整数倍。有些场景下,防闪开启后画面仍轻微闪烁,可能和sensor的行时间与工频周期之间的余数有关,这时可以微调HTS,让行时间的整数倍更接近工频周期。
这个调HTS的方法算是个偏方,但非常实用。因为工频闪烁的本质是光源亮度在每半个周期内波动,只有当曝光窗口覆盖完整的整数个波动周期时,才能抵消亮度起伏。通过微调行时间,让曝光时间准确落在整数倍上,很多顽固的横条纹问题都能解决。当然,改HTS会影响帧率,改完之后要重新核对曝光表。
4.4 问题排查速查表
| 现象 | 可能原因 | 排查手段 |
|---|---|---|
| 画面忽明忽暗 | 增益步进过大 | 检查曝光表相邻索引增益差,增加平滑插值 |
| 高帧率发暗 | 曝光行数受限、增益不足 | 单独配置高帧率曝光表,拉高增益预算 |
| 室内滚动条纹 | 未开防闪或曝光未对齐工频周期 | 打开anti-banding,对齐50Hz/60Hz周期 |
| 帧率不稳定 | VTS与曝光行数冲突 | 检查最大曝光行数是否逼近VTS,留足余量 |
| 暗部噪点多 | 数字增益过高 | 优先提高模拟增益,数字增益控制在2x以内 |
| 亮部死白 | 高亮索引曝光行数超标 | 拉低高亮端曝光时间,检查最大曝光限制 |
最后再分享一个我个人的习惯。每次调完曝光表,我会把所有改动记录在一个简单表格里,包括改了什么、为什么改、实测效果如何。这件事看似繁琐,但在项目后期、换人接手、或者同一套代码适配多个项目时,价值远超想象。相机调试是个经验活,经验不沉淀下来,每次都是重头再来。Chromatix AEC的曝光表配置,看着是填数据,实际上填的是你对sensor、对场景、对画质的理解,这才是这份工作真正有意思的地方。