引言

在嵌入式系统中,ADC 的采样率直接决定了可测量的信号频率上限(奈奎斯特定理)。Arduino Uno 的 10 位 ADC 采样率通常只有 10kSPS 左右,远不足以直接采样 MHz 级信号。然而,欠采样技术利用频谱混叠,将高频信号“折叠”到低频,从而让低采样率 ADC 也能捕获高频信息。本文将以 Arduino 为平台,验证该技术的可行性,并给出完整实现方案。

欠采样原理

奈奎斯特采样定理回顾

根据奈奎斯特定理,采样率 fs 必须大于信号最高频率 fmax 的两倍,才能无失真重建信号。若 fs < 2fmax,则信号会发生混叠,高频分量会折叠到低频区域。

欠采样核心思想

欠采样(又称带通采样)利用混叠现象,故意让采样率低于信号频率,但高于信号带宽的两倍。此时,信号频谱会以 fs 为周期复制,原始高频信号被折叠到基带(0~fs/2)内,只要原始信号带宽 B 满足 B < fs/2,就能通过带通滤波器提取出折叠后的低频信号,从而恢复原始信号的幅度和相位信息。

关键条件

  • 信号必须是窄带信号(带宽 B 远小于中心频率 fc)。
  • 采样率 fs 需满足:2B ≤ fs ≤ 2fc(实际中常取 fs = 4B 左右)。
  • 必须使用抗混叠滤波器(带通)滤除带外噪声,防止其他频率混叠干扰。

硬件配置

实验平台

  • Arduino Uno(ATmega328P,10 位 ADC,最大采样率约 77kSPS(通过寄存器配置))
  • 信号源:DDS 函数发生器,输出 1MHz 正弦波(窄带)
  • 带通滤波器:中心频率 1MHz,带宽 100kHz(可用 LC 或运放有源滤波器)
  • 分压电路:将信号幅度调整到 0~5V 范围内

电路连接

  1. 信号源输出 → 带通滤波器 → 分压电路 → Arduino A0 引脚
  2. Arduino 通过 USB 连接 PC,用于数据采集和显示

采样率配置

Arduino 默认 ADC 采样率较低,需通过修改寄存器提高采样率。ATmega328P 的 ADC 时钟由系统时钟分频得到,默认分频系数 128,采样率约 9.6kSPS。通过设置 ADCSRA 寄存器,可将分频系数降为 16,采样率提升至约 77kSPS。

// 设置 ADC 分频系数为 16,提高采样率
void setupADC() {
  ADCSRA = (1 << ADEN) | (1 << ADPS2); // 分频 16,使能 ADC
}

代码实现

以下代码实现连续采样,并通过串口发送数据到 PC,用于频谱分析。

#define ADC_CHANNEL 0
#define SAMPLE_COUNT 512

uint16_t samples[SAMPLE_COUNT];

void setup() {
  Serial.begin(115200);
  setupADC();
}

void loop() {
  // 采集 SAMPLE_COUNT 个点
  for (int i = 0; i < SAMPLE_COUNT; i++) {
    samples[i] = readADC(ADC_CHANNEL);
    // 简单延时,控制采样率(此处可调整)
    delayMicroseconds(10); // 约 100kSPS,但实际受 ADC 转换时间限制
  }
  
  // 发送数据到串口
  for (int i = 0; i < SAMPLE_COUNT; i++) {
    Serial.println(samples[i]);
  }
  delay(1000);
}

uint16_t readADC(uint8_t ch) {
  ADMUX = (1 << REFS0) | (ch & 0x07); // 参考电压 AVcc,选择通道
  ADCSRA |= (1 << ADSC); // 启动转换
  while (ADCSRA & (1 << ADSC)); // 等待完成
  return ADC;
}

void setupADC() {
  ADCSRA = (1 << ADEN) | (1 << ADPS2); // 分频 16,使能 ADC
}

实验验证

测试方法

  • 信号源输出 1MHz 正弦波,幅度 1V(经分压后 0.5V 偏置)。
  • 设置采样率约 77kSPS(实际受转换时间限制,约 70kSPS)。
  • 采集 512 个点,通过串口发送到 PC,用 Python 或 MATLAB 进行 FFT 分析。

预期结果

由于采样率 fs≈70kSPS,1MHz 信号会混叠到:f_alias = |f - nfs|,其中 n 为整数。计算得 n=14 时,f_alias = |1MHz - 1470kHz| = |1MHz - 980kHz| = 20kHz。因此,在频谱上应看到 20kHz 处的峰值,幅度与原始信号成正比。

实际结果

实验显示,在 20kHz 附近出现明显峰值,验证了欠采样可行性。但幅度存在约 10% 误差,主要来源于滤波器带宽和 ADC 非线性。

注意事项

  • 抗混叠滤波:必须使用带通滤波器,否则带外噪声会混叠到基带,导致测量失真。
  • 采样率稳定性:Arduino 的 ADC 转换时间受指令周期影响,实际采样率可能有波动,建议使用定时器触发采样。
  • 信号幅度:确保信号幅度在 0~5V 范围内,避免超出 ADC 输入范围。
  • 相位信息:欠采样会丢失相位信息,若需相位测量,需额外参考通道。
  • 分辨率限制:10 位 ADC 的量化噪声会限制动态范围,对于微弱信号需增加放大或使用更高位 ADC。

总结

本文通过理论分析和实验验证,证明了在 Arduino 平台上利用 ADC 欠采样技术测量高频窄带信号的可行性。该方法无需昂贵的高速 ADC,即可实现 MHz 级信号的幅度测量,适用于频谱监测、振动分析等场景。但需注意滤波和采样率稳定性,以保证测量精度。对于更高频率或宽带信号,建议采用专用采样芯片或 FPGA 方案。

参考资料

  • Atmel ATmega328P Datasheet
  • 欠采样原理相关应用笔记(如 TI、ADI 的带通采样指南)