高精度数据采集:24位Sigma-Delta ADC的噪声抑制与校准算法(Offset/Gain Calibration)
扫描二维码
随时随地手机看文章
在医疗电子、工业称重及环境监测等应用中,24位Sigma-Delta ADC(如ADS1256、AD7124)提供了极高的理论分辨率。然而,在实际应用中,“噪声”和“漂移”会让高分辨率沦为摆设。本文将聚焦PCB级的噪声抑制与固件层的校准算法,探讨如何从“有噪声的原始码值”中提取真实的物理量。
一、噪声抑制:从PCB布局开始
24位ADC的LSB极其微小(例如5V参考下约为298nV),任何布局疏忽都会引入噪声。
1.1 模拟与数字的“楚河汉界”
Sigma-Delta ADC对电源和地平面的干扰极为敏感。正确的分割策略是成功的一半。
// PCB布局约束(设计规则检查DRC)
#define ANALOG_GND_POLYGON (0.5mm from digital_gnd)
#define DIGITAL_GND_POLYGON (0.5mm from analog_gnd)
#define AGND_DGND_CONNECTION "single_point_under_ADC_pad"
// 关键布线规则
void layout_rules() {
// 1. 模拟输入走线必须包地处理(Guard Trace)
// 2. 参考电压(VREF)走线远离数字信号
// 3. 时钟线(如果外部提供)需远离模拟输入
// 4. 去耦电容(100nF + 10uF钽电容)必须紧贴VDD引脚
}
1.2 抗混叠与EMI滤波
虽然Sigma-Delta ADC内置数字滤波器,但前端模拟滤波依然关键。
// 推荐的前端RC滤波器计算
typedef struct {
float R_anti_alias; // 1kOhm - 10kOhm
float C_diff_input; // 10nF - 100nF (差分)
float cutoff_freq_hz;
} InputFilter_t;
// 计算截止频率
void calc_cutoff(InputFilter_t* filter) {
// f_c = 1 / (2 * PI * R * C)
// 目标:低于调制器频率(f_mod)的1/10
filter->cutoff_freq_hz = 1.0f / (2.0f * 3.14159f *
filter->R_anti_alias *
filter->C_diff_input);
}
二、校准算法:消除系统误差
即使PCB完美,Offset(偏移)和Gain(增益)误差依然存在。通过两点校准(Two-Point Calibration),可以在固件中将其消除。
2.1 Offset校准(零点校准)
在输入端短路(Short)或通过继电器接入已知0V信号,测量ADC输出。
// Offset校准结构体
typedef struct {
int32_t offset_code; // 偏移码值
float offset_voltage_uv; // 偏移电压(uV)
} OffsetCal_t;
// 执行Offset校准
OffsetCal_t perform_offset_cal(ADC_Driver* adc) {
OffsetCal_t cal = {0};
// 1. 硬件短接输入(或切换至内部短接)
adc->set_input_mux(SHORTED_INPUT);
// 2. 丢弃前N个采样(等待滤波器稳定)
for(int i=0; i<10; i++) adc->read_raw();
// 3. 采集平均值
int64_t sum = 0;
const int samples = 256;
for(int i=0; i<samples; i++) {
sum += adc->read_raw();
}
cal.offset_code = sum / samples;
// 4. 转换为电压(假设5V参考,24位)
cal.offset_voltage_uv = ((float)cal.offset_code / 16777216.0f) * 5.0f * 1e6f;
return cal;
}
2.2 Gain校准(满量程校准)
接入一个高精度、稳定的参考电压(例如90% Full Scale),计算增益误差。
// Gain校准结构体
typedef struct {
float gain_error; // 增益误差系数
} GainCal_t;
// 执行Gain校准
GainCal_t perform_gain_cal(ADC_Driver* adc, float ref_voltage_v) {
GainCal_t cal = {0};
// 1. 切换至外部高精度参考源
adc->set_input_mux(EXTERNAL_REF_IN);
// 2. 等待稳定并采样
int64_t sum = 0;
const int samples = 256;
for(int i=0; i<samples; i++) {
sum += adc->read_raw();
}
int32_t measured_code = sum / samples;
// 3. 计算理论码值
// 假设双极性:Code = (Vin / Vref) * 2^(N-1)
float ideal_code_f = (ref_voltage_v / 5.0f) * 8388608.0f; // 2^23
int32_t ideal_code = (int32_t)ideal_code_f;
// 4. 计算增益系数
// 校准后的值 = (Raw - Offset) * Gain
cal.gain_error = (float)ideal_code / (float)measured_code;
return cal;
}
2.3 应用校准系数
在最终的读数函数中应用校准参数,这是将“码值”转化为“真实世界值”的关键一步。
// 应用校准后的读数
float read_calibrated_value(ADC_Driver* adc,
OffsetCal_t offset,
GainCal_t gain) {
// 1. 读取原始数据
int32_t raw_code = adc->read_raw();
// 2. 去除偏移量
int32_t corrected_code = raw_code - offset.offset_code;
// 3. 应用增益校正
float final_code_f = (float)corrected_code * gain.gain_error;
// 4. 转换为电压
// 假设双极性,5V参考,24位ADC
float voltage = (final_code_f / 8388608.0f) * 5.0f; // 2^23
return voltage;
}
三、高级技巧:数据抖动与平均
24位ADC的原始数据通常会有Code Flicker(码值跳动)。简单的平均滤波会牺牲实时性。
// 指数加权移动平均(EWMA)- 兼顾响应速度与平滑度
typedef struct {
float alpha; // 平滑因子 (0.01 - 0.3)
float filtered_val; // 上一次的滤波值
} EWMA_Filter_t;
float ewma_update(EWMA_Filter_t* f, float new_sample) {
// y[n] = alpha * x[n] + (1-alpha) * y[n-1]
f->filtered_val = f->alpha * new_sample +
(1.0f - f->alpha) * f->filtered_val;
return f->filtered_val;
}
结语
24位Sigma-Delta ADC的性能发挥,三分靠芯片,七分靠设计。通过严格的PCB布局抑制外部噪声,再通过Offset/Gain两点校准消除系统误差,最后利用EWMA等滤波算法平滑数据抖动,才能在高精度数据采集系统中榨干ADC的每一个有效位。





