Aliasing là gì: chồng phổ khi lấy mẫu và bộ lọc chống chồng phổ RC trước ADC

Aliasing (chồng phổ) là gì, vì sao nhiễu cao tần hiện ra thành tần số thấp giả khi lấy mẫu, cách tính, bộ lọc chống chồng phổ RC trước ADC kèm script Python tính, và kỹ thuật lấy mẫu dư rồi lọc số.

Aliasing (chồng phổ) là hiện tượng một thành phần tần số cao, sau khi bị lấy mẫu quá thưa, hiện ra như một tần số thấp không có thật. Nó là lý do số đo ADC đôi khi dao động đều đặn dù tín hiệu đứng yên, hoặc phổ FFT có một vạch lạ. Bài này giải thích aliasing là gì bằng ví dụ cụ thể, cách tính tần số "giả" mà nhiễu tạo ra, bộ lọc chống chồng phổ (anti-aliasing filter) bằng RC trước ADC, cách tính bằng script Python, và kỹ thuật lấy mẫu dư rồi lọc số.

1. Aliasing là gì

Theo định lý Nyquist, lấy mẫu ở tần số fs chỉ ghi đúng các thành phần dưới fs/2. Thành phần nào cao hơn không biến mất mà bị "gấp" xuống dải 0 đến fs/2: tần số hiện ra bằng tần số thật trừ bội số gần nhất của fs, lấy trị tuyệt đối. Phần giải thích định lý và thí nghiệm trên ESP32 có ở bài định lý lấy mẫu Nyquist cùng cụm chủ đề.

Trục tần số 0 đến 1000 Hz, vùng xanh từ 0 tới 500 Hz là dải ghi đúng; tín hiệu 30 Hz nằm trong dải; nhiễu 950 Hz bị gấp, hiện ra ở 50 Hz bằng nét đứt đỏ
Lấy mẫu 1000 Hz, nhiễu 950 Hz hiện ra như sóng 50 Hz (hình minh họa).

Ví dụ: cảm biến đo rung 30 Hz, ADC lấy mẫu 1000 Hz. Trên dây tín hiệu có nhiễu 950 Hz từ bộ nguồn xung. Sau khi lấy mẫu, nhiễu này hiện ra đúng như một dao động 50 Hz, nằm ngay cạnh tín hiệu thật và không lọc ra được bằng phần mềm nữa, vì dãy mẫu của nó giống hệt dãy mẫu của sóng 50 Hz thật. Tệ hơn, một nhiễu 4970 Hz sẽ hiện ra đúng ở 30 Hz, chồng lên tín hiệu cần đo.

Nguồn nhiễu cao tần hay gặp: nguồn xung (vài chục đến vài trăm kHz), PWM điều khiển động cơ, LED, bộ phát Wi-Fi, nhiễu điện lưới và các hài của nó.

2. Bộ lọc chống chồng phổ

Cách duy nhất ngăn aliasing là loại bỏ thành phần trên fs/2 trước khi ADC lấy mẫu, bằng mạch lọc thông thấp tương tự. Mạch đơn giản nhất là một điện trở nối tiếp và một tụ xuống GND:

Mạch lọc RC: điện trở 10 kΩ nối tiếp, tụ 100 nF xuống GND, điểm giữa vào ADC, tần số cắt 159,2 Hz; đồ thị suy giảm theo tần số thang log cho 1 tầng và 2 tầng RC với vạch fs/2 bằng 500 Hz
Bộ lọc RC và độ suy giảm theo tần số.

Tần số cắt fc = 1 / (2π × R × C). Trên fc, mỗi lần tần số tăng gấp 10, một tầng RC giảm biên độ thêm khoảng 10 lần (20 dB). Như hình, một tầng RC với fc 159 Hz chỉ giảm nhiễu ở 500 Hz khoảng 10 dB, tức còn 30 % biên độ: bộ lọc bậc 1 dốc chậm, chỉ đủ khi nhiễu ở xa trên fs/2 hoặc yêu cầu không cao. Hai tầng RC (có tầng đệm op-amp giữa hai tầng, hoặc chọn tầng sau có trở kháng cao hơn nhiều) giảm gấp đôi số dB.

Bảng suy giảm của lọc RC 10 kΩ 100 nF ở 50, 159, 500, 950, 1950, 4970 Hz cho 1 tầng và 2 tầng, kèm tần số hiện ra sau khi lấy mẫu 1 kHz
Lọc RC 10 kΩ, 100 nF giảm nhiễu bao nhiêu.

Script dưới đây tính tần số cắt, độ suy giảm ở fs/2 và ở tần số nhiễu bất kỳ, cùng tần số mà nhiễu đó hiện ra sau khi lấy mẫu:

# PYWORLD.VN - Tính bộ lọc RC chống chồng phổ đặt trước ADC: tần số cắt, độ suy giảm ở fs/2, tần số chồng phổ của nhiễu
# PYWORLD.VN - Chạy: python tinh_loc_rc.py --r 10000 --c 100e-9 --fs 1000 --nhieu 950
# PYWORLD.VN - n tầng RC giống nhau nối tiếp (có đệm giữa các tầng) thì độ suy giảm nhân lên n lần (tính bằng dB)

import argparse
import math


def tan_so_cat(r: float, c: float) -> float:
    return 1 / (2 * math.pi * r * c)


def suy_giam_db(f: float, fc: float, so_tang: int = 1) -> float:
    return so_tang * 10 * math.log10(1 + (f / fc) ** 2)


def chong_pho(f: float, fs: float) -> float:
    return abs(f - round(f / fs) * fs)


def main() -> None:
    p = argparse.ArgumentParser(description="Bộ lọc RC chống chồng phổ")
    p.add_argument("--r", type=float, default=10000, help="điện trở (Ω)")
    p.add_argument("--c", type=float, default=100e-9, help="tụ (F)")
    p.add_argument("--fs", type=float, default=1000, help="tần số lấy mẫu (Hz)")
    p.add_argument("--nhieu", type=float, default=950, help="tần số nhiễu cần xét (Hz)")
    p.add_argument("--tang", type=int, default=1, help="số tầng RC")
    a = p.parse_args()
    fc = tan_so_cat(a.r, a.c)
    print(f"Tan so cat fc = {fc:.1f} Hz (R = {a.r:g} ohm, C = {a.c:g} F, {a.tang} tang)")
    print(f"Tan so Nyquist fs/2 = {a.fs / 2:g} Hz: suy giam {suy_giam_db(a.fs / 2, fc, a.tang):.1f} dB")
    sg = suy_giam_db(a.nhieu, fc, a.tang)
    print(f"Nhieu {a.nhieu:g} Hz: con {100 / 10 ** (sg / 20):.1f} % bien do (suy giam {sg:.1f} dB), "
          f"sau lay mau hien ra o {chong_pho(a.nhieu, a.fs):g} Hz")


if __name__ == "__main__":
    main()

Ví dụ: python tinh_loc_rc.py --r 10000 --c 100e-9 --fs 1000 --nhieu 950 cho biết nhiễu 950 Hz còn khoảng 16 % biên độ và hiện ra ở 50 Hz. Thêm --tang 2 thì còn khoảng 3 %.

3. Chọn R, C cho bộ lọc trước ADC của vi điều khiển

  • Đặt fc trên tần số cao nhất của tín hiệu một ít, để tín hiệu không bị giảm (ở fc biên độ đã giảm còn 71 %).
  • Đặt fs đủ cao để fs/2 nằm xa trên fc; đây là lý do thực tế lấy mẫu 5–10 lần tần số tín hiệu.
  • R không quá lớn: ADC của ESP32, STM32 nạp tụ lấy mẫu bên trong mỗi lần đọc; R vài chục kΩ trở lên làm số đọc thấp hơn thật. Tụ C ở chân ADC (vài chục nF trở lên) cũng giúp cấp điện tích cho tụ lấy mẫu, nên mạch RC trước ADC có lợi cả hai mặt.
  • Tụ gốm C0G/NP0 hoặc tụ phim cho bộ lọc chính xác; tụ gốm X7R thay đổi điện dung theo điện áp, nhiệt độ.

4. Lấy mẫu dư rồi lọc số

Chuỗi khối: lọc RC đơn giản fc vài kHz, ADC lấy mẫu dư 10 kHz, lọc số trung bình 10 mẫu, giảm tốc độ còn 1 kHz
Lấy mẫu nhanh, lọc số, rồi giảm tốc độ (hình minh họa).

Khi bộ lọc tương tự bậc cao khó làm, có thể lấy mẫu nhanh hơn nhiều lần tốc độ cần (lấy mẫu dư), lọc bằng phần mềm rồi chỉ giữ lại một phần mẫu (giảm tốc độ, decimation). Bộ lọc RC lúc này chỉ cần chặn nhiễu trên nửa tốc độ lấy mẫu dư (5 kHz trong ví dụ), dễ hơn nhiều. Lọc trung bình khối 10 mẫu là cách đơn giản nhất; bộ lọc số tốt hơn (FIR, CIC) cho dải tín hiệu phẳng hơn. Nguyên tắc vẫn giữ: lọc số phải làm trước khi giảm tốc độ, nếu không chính bước giảm tốc độ lại gây aliasing.

5. Nhận biết aliasing trong số đo

  • Số đo dao động đều đặn ở tần số thấp mà tín hiệu thật không có (nhìn trên đồ thị theo thời gian).
  • Đổi tần số lấy mẫu một chút (ví dụ 1000 Hz thành 1100 Hz) mà tần số dao động lạ thay đổi theo: chắc chắn là aliasing, vì tín hiệu thật không đổi theo tốc độ lấy mẫu.
  • Tắt nguồn nhiễu nghi ngờ (động cơ, nguồn xung, Wi-Fi) thì dao động biến mất.

6. Xem thêm


Tin tức liên quan

Transistor BJT: NPN, PNP, cách xác định chân và hệ số khuếch đại
Transistor BJT: NPN, PNP, cách xác định chân và hệ số khuếch đại

Transistor BJT là gì: cấu tạo NPN, PNP, ký hiệu và chiều dòng, hệ số khuếch đại β, ba vùng tắt, khuếch đại, bão hòa, thông số BC547, 2N2222A, S8050, cách xác định chân và đo transistor.

Jack Type-C tích hợp mạch sạc pin 1S: cấu tạo, thông số và khi nào nên dùng
Jack Type-C tích hợp mạch sạc pin 1S: cấu tạo, thông số và khi nào nên dùng

Jack Type-C tích hợp mạch sạc pin 1S nhận 5 V, sạc pin Li-ion hoặc Li-po một cell đến 4,2 V ở dòng 1 A, có đèn báo đỏ và xanh. Bài nêu cấu tạo, thông số, điểm khác với jack Type-C thường và các trường hợp nên dùng.

Cách chọn vali chống sốc đựng thiết bị: 7 điều cần xem trước khi mua
Cách chọn vali chống sốc đựng thiết bị: 7 điều cần xem trước khi mua

Bảy điều cần xem khi chọn vali chống sốc đựng thiết bị: kích thước lọt lòng, độ sâu nắp và đáy, vật liệu vỏ, chống nước, khóa, xốp, khối lượng; kèm danh sách kiểm tra trước khi mua.

Chọn mỏ hàn, đầu mỏ, thiếc hàn và nhựa thông cho điện tử: nhiệt độ, cách giữ đầu mỏ, mối hàn tốt
Chọn mỏ hàn, đầu mỏ, thiếc hàn và nhựa thông cho điện tử: nhiệt độ, cách giữ đầu mỏ, mối hàn tốt

Chọn mỏ hàn chỉnh nhiệt, đầu mỏ dẹt hay nhọn, thiếc có chì hay không chì, nhựa thông và flux cho điện tử; nhiệt độ đặt mỏ, láng thiếc đầu mỏ, mối hàn tốt và an toàn khi hàn.

Từ Scratch sang Python cho trẻ: khi nào chuyển, khối nào ứng với lệnh nào
Từ Scratch sang Python cho trẻ: khi nào chuyển, khối nào ứng với lệnh nào

Hướng dẫn học sinh chuyển từ Scratch sang Python: dấu hiệu sẵn sàng, cài Thonny, bảng khối Scratch ứng với lệnh Python, hai dự án đố vui phép nhân và con rùa vẽ đa giác.

Watchdog trên ESP32: vì sao mạch tự khởi động lại, đọc lý do reset và tự cứu khi chương trình treo
Watchdog trên ESP32: vì sao mạch tự khởi động lại, đọc lý do reset và tự cứu khi chương trình treo

Watchdog là gì, task watchdog, interrupt watchdog, panic và brownout trên ESP32, in lý do khởi động lại bằng esp_reset_reason, đếm số lần khởi động, cho task tự đăng ký watchdog.

Máy CNC là gì: nguyên lý, các loại máy CNC mini và lộ trình tự làm CNC, laser
Máy CNC là gì: nguyên lý, các loại máy CNC mini và lộ trình tự làm CNC, laser

Máy CNC là gì, hoạt động thế nào từ bản vẽ tới đường cắt, ba trục X Y Z, các loại máy CNC mini, laser, máy vẽ cho người tự làm, nên bắt đầu từ đâu và lộ trình 20 bài.

Đo biến dạng bằng cảm biến strain gauge
Đo biến dạng bằng cảm biến strain gauge

Giải thích strain, hệ số gauge, cầu Wheatstone, cấu hình quarter/half/full bridge và các bước thiết lập phép đo biến dạng tin cậy.


Bình luận
Đã thêm vào giỏ hàng