4、数字增益(Digital Gain):数字域乘法器的实现,以及量化噪声的放大效应
数字增益,说白了就是在数字域里把像素值乘上一个系数。听起来很简单对吧?但这里面的坑,比你想的要多得多。
我刚开始做ISP芯片时,觉得数字增益不就是个乘法器嘛,几行代码搞定。直到第一次看到输出图像上那些密密麻麻的噪点,我才意识到——数字增益是把双刃剑。
4.1 数字增益的本质
模拟增益是在ADC之前放大电压信号,数字增益则是在ADC量化之后,对数字码值做乘法。举个例子:
// 原始像素值(12-bit ADC输出)
pixel_in = 2048; // 对应50%满阱
// 数字增益 2.0x
pixel_out = pixel_in * 2.0; // 4096
// 数字增益 4.0x
pixel_out = pixel_in * 4.0; // 8192,但14-bit输出只能到16383
嗯,这里要注意:数字增益不会改变信噪比。为什么?因为信号和噪声都被放大了同样的倍数。
4.2 数字域乘法器的硬件实现
实际芯片里,我不会直接用浮点乘法器——那太奢侈了。常用的方案有几种:
| 实现方式 | 面积 | 精度 | 延迟 | 我推荐场景 |
|---|---|---|---|---|
| 定点乘法器(整数×定点小数) | 小 | 中 | 1-2周期 | 低功耗IoT |
| 查找表(LUT) | 极小 | 低 | 1周期 | 固定增益场景 |
| 浮点乘法器 | 大 | 高 | 3-5周期 | 高端相机 |
| 移位+加法 | 最小 | 受限 | 多周期 | 2的幂次增益 |
我个人习惯用定点乘法器。举个例子,增益1.5x可以表示为定点数1.1000(二进制),也就是1 + 0.5。硬件实现就是:
// 定点乘法:pixel_out = pixel_in * 1.5
// 1.5 = 1 + 0.5 = 左移0位 + 右移1位
pixel_out = pixel_in + (pixel_in >> 1);
你看,连乘法器都不需要,一个加法器加一个移位器就搞定了。
4.3 量化噪声的放大效应
这才是数字增益最要命的地方。你想想看,ADC量化时已经引入了量化噪声。数字增益放大信号的同时,也放大了这个噪声。
举个例子:12-bit ADC,量化步长是1 LSB。假设某个像素的真实值是100.3,ADC量化后是100。量化误差是0.3 LSB。
现在做4x数字增益:
- 理想情况: 100.3 × 4 = 401.2
- 实际情况: 100 × 4 = 400
- 量化误差放大: 0.3 × 4 = 1.2 LSB
看到了吗?量化误差从0.3 LSB变成了1.2 LSB。这就是量化噪声的放大效应。
4.4 量化噪声放大的数学本质
我们来算一笔账。假设ADC是N位,量化步长q = Vref / 2N。量化噪声的方差是q²/12。
经过数字增益G后:
- 信号功率: 放大G²倍
- 量化噪声功率: 也放大G²倍
- 信噪比: 不变!
这就是为什么我说数字增益不改善SNR。它只是把信号和噪声一起放大。
但问题在于——量化噪声不是白噪声。它有特定的频谱分布,尤其是在低光照下,量化步长相对于信号来说太大了,放大后会出现明显的量化伪影。
4.5 如何减轻量化噪声放大
我在实际项目中用过几种方法,效果还不错:
- 高位宽ADC + 低位宽输出
- ADC做14-bit,输出只取12-bit
- 多出来的2-bit相当于给数字增益留了余量
- 代价:ADC面积增加约30%
- 数字抖动(Dithering)
- 在量化前加一个小幅度的随机噪声
- 把量化噪声变成白噪声,视觉上更平滑
- 我习惯加0.5~1 LSB的均匀分布抖动
- 分段增益
- 模拟增益做粗调,数字增益做细调
- 数字增益不超过6dB(2x)
- 超过的部分交给模拟增益或后端处理
- 非线性映射
- 暗区用较小的数字增益
- 亮区用较大的数字增益
- 本质上是一种自适应增益控制
4.6 数字增益与模拟增益的配合策略
你想想看,模拟增益和数字增益怎么搭配最合理?我的经验是:
| 光照条件 | 模拟增益 | 数字增益 | 理由 |
|---|---|---|---|
| 充足光照(>100 lux) | 0 dB | 0 dB | 不需要额外增益 |
| 室内光照(10-100 lux) | 6-12 dB | 0-3 dB | 模拟增益优先,数字增益微调 |
| 低光照(1-10 lux) | 12-24 dB | 3-6 dB | 模拟增益为主,数字增益辅助 |
| 极低光照(<1 lux) | 24-36 dB | 6-12 dB | 两者都用,但数字增益不超过12dB |
我一般把数字增益的上限设在12dB(4x)。超过这个值,量化噪声就太明显了。这时候我会建议客户换更大光圈的镜头,或者用多帧降噪。
4.7 数字增益的流水线设计
在高速ISP芯片里,数字增益通常放在流水线的什么位置?我习惯这样安排:
// 典型的ISP数字增益流水线
// 阶段1: 黑电平校正 (BLC)
// 阶段2: 数字增益 (DG)
// 阶段3: 白平衡 (AWB)
// 阶段4: 去马赛克 (Demosaic)
// 阶段5: 色彩校正 (CCM)
// 阶段6: Gamma校正
// 为什么数字增益放在BLC之后?
// 因为BLC减去了暗电流,这时候做增益不会放大暗电流噪声
// 为什么放在AWB之前?
// 因为AWB是通道独立的增益,数字增益是全局增益
// 先做全局增益,再做通道增益,逻辑更清晰
4.8 数字增益的SVG流程图
下面这张图展示了数字增益在ISP流水线中的位置,以及量化噪声放大的过程:
4.9 实战中的避坑指南
最后,分享几个我亲身踩过的坑:
- 坑1:数字增益溢出
- 现象:高亮区域出现暗条纹
- 原因:乘法结果超过位宽,高位被截断
- 解决:加饱和保护,或者用更大的位宽做中间计算
- 坑2:量化噪声放大导致伪轮廓
- 现象:平滑区域出现阶梯状色带
- 原因:数字增益放大了量化步长
- 解决:加数字抖动,或者限制数字增益上限
- 坑3:增益切换时的跳变
- 现象:画面亮度突然变化
- 原因:模拟增益和数字增益切换不同步
- 解决:用渐变增益过渡,或者帧同步切换
数字增益是个好东西,但用不好就是灾难。记住:模拟增益是"雪中送炭",数字增益只是"锦上添花"。别指望用数字增益来弥补模拟前端的不足,那只会让问题更明显。