Mở đầu: một tone sạch, một phổ "bẩn"
Cho một sine đơn tần thật sạch vào dft()/fft() đã verify ở 2 bài trước — kỳ vọng
thấy đúng MỘT vạch nhọn tại đúng tần số đó. Nhưng nếu tần số sine không rơi đúng vào một bin (ví dụ hoàn
thành đúng 10,5 chu kỳ trong cả khung, thay vì một số nguyên chu kỳ), phổ không còn sạch nữa — năng lượng
"loang" ra khắp mọi bin xung quanh, có khi che mất hẳn một tín hiệu yếu hơn ở gần đó.
Bài này truy nguyên hiện tượng đó tận gốc — gọi là rò rỉ phổ (spectral leakage) — bằng đúng một hình ảnh toán học, rồi giới thiệu bộ công cụ khắc phục: các hàm cửa sổ (rect/Hann/Hamming/Blackman), mỗi loại đánh đổi độ phân giải lấy dải động theo cách khác nhau.
1. Hiện tượng lạ: một sine, cả phổ "sáng"
Truy nguyên gốc rễ: dft() ngầm giả định khung tín hiệu đang phân tích LẶP LẠI vô hạn — nối
đuôi khung này với chính nó tạo thành một tín hiệu tuần hoàn tưởng tượng. Nếu sine hoàn thành đúng MỘT SỐ
NGUYÊN chu kỳ trong khung, mép nối liền mạch — không có vấn đề gì. Nhưng nếu không (ví dụ 10,5 chu kỳ),
mép nối bị GÃY — tạo ra một bước nhảy giả tạo không hề có trong tín hiệu gốc. Bước nhảy giả đó chính là
nguồn năng lượng "rò rỉ" lan ra khắp phổ.
2. Nhìn qua lăng kính toán: cửa sổ = chập với sinc
Cắt một khung hữu hạn từ tín hiệu vô hạn, về bản chất toán học, là NHÂN tín hiệu đó với một cửa sổ chữ nhật (1 bên trong khung, 0 bên ngoài). Theo định lý nhân-chập của biến đổi Fourier, nhân trong miền thời gian tương đương với chập trong miền tần số — phổ của tín hiệu gốc bị chập với phổ của chính cửa sổ chữ nhật, vốn có dạng hàm sinc ($\text{sinc}(x) = \sin(\pi x)/(\pi x)$): một thuỳ chính (main lobe) hẹp ở giữa, và vô số thuỳ phụ (side lobes) nhỏ dần lan ra hai bên. Đây là lời giải thích TRỌN VẸN cho hiện tượng leakage — không có gì bí ẩn, chỉ là hệ quả của việc cắt khung hữu hạn KHÔNG THỂ tránh khỏi khi xử lý số.
3. Bộ sưu tập cửa sổ: đánh đổi thuỳ chính ↔ thuỳ phụ
Nếu cửa sổ chữ nhật là "cắt cứng" (0/1 đột ngột ở biên), các cửa sổ khác làm biên độ GIẢM DẦN MƯỢT về 0 ở
hai đầu khung — đổi lấy thuỳ chính rộng hơn (phân giải tần số kém hơn) nhưng thuỳ phụ thấp hơn NHIỀU (ít
rò rỉ hơn hẳn). Số đo thật từ self-test (node dsp-core.js, $N=1024$):
| Cửa sổ | Mức thuỳ phụ (side lobe) | Coherent gain | Khi nào dùng |
|---|---|---|---|
| Rect (chữ nhật) | ≈ −13,5dB (rất cao — rò rỉ nhiều) | 1,00 | Chỉ khi tần số RƠI ĐÚNG bin (hiếm khi thực tế) |
| Hann | ≈ −32,2dB | 0,50 | Đa dụng hằng ngày — cân bằng tốt độ phân giải/dải động |
| Hamming | ≈ −42,7dB | 0,54 | Tách 2 tone GẦN nhau (thuỳ chính hẹp hơn Hann) |
| Blackman | ≈ −58,3dB (thấp NHẤT) | 0,42 | Tìm tone YẾU cạnh tone MẠNH (side lobe thấp nhất) |
Đúng thứ tự kinh điển verified bằng self-test: rect > Hann > Hamming > Blackman (số càng âm, càng ít rò rỉ). Không có cửa sổ nào "tốt nhất tuyệt đối" — Hamming thắng khi cần TÁCH 2 tần số gần nhau, Blackman thắng khi cần THẤY một tín hiệu yếu bên cạnh một tín hiệu mạnh, Hann là lựa chọn cân bằng mặc định khi không chắc cần gì.
Số đo thật minh hoạ trực tiếp mức độ khác biệt: với một sine hoàn thành 10,5 chu kỳ trong khung 256 mẫu, đo năng lượng "rò rỉ" tại một bin XA (bin 40, cách xa vị trí tín hiệu thật ở bin ~10-11) — cửa sổ rect cho ra biên độ rò rỉ 0,62, trong khi Hann chỉ còn 0,0006 — chênh nhau hơn 1000 lần.
4. Pitfall đo lường: cửa sổ "ăn" mất năng lượng
Mọi cửa sổ (trừ rect) đều làm GIẢM biên độ trung bình của tín hiệu — vì phần lớn cửa sổ có giá trị nhỏ hơn 1 (đặc biệt gần 2 đầu khung). Đại lượng đo mức giảm này gọi là coherent gain — chính là giá trị TRUNG BÌNH của cửa sổ (bảng Mục 3: Hann≈0,50, Hamming≈0,54, Blackman≈0,42).
function coherentGain(window) {
return window.reduce((sum, w) => sum + w, 0) / window.length;
}
// Bu lai bien do da bi cua so lam "tut" - QUEN buoc nay la sai he thong
function compensatedMagnitude(magnitude, window) {
const cg = coherentGain(window);
return magnitude.map((m) => m / cg);
}
5. Thực hành: hai tone chênh 40dB — hiện rồi lặn
Demo dưới đây dựng 2 tone: một tone MẠNH tại 1004Hz (cố tình KHÔNG rơi đúng bin để có leakage thật) và một tone YẾU HƠN 40dB (biên độ chỉ bằng 1%) tại 1031,25Hz (cách main tone vài bin). Đổi cửa sổ để xem tone yếu bị leakage của tone mạnh CHE MẤT hay HIỆN RA rõ:
Trục ngang: bin tần số quanh 2 tone. Cột xanh = tone mạnh (1004Hz), cột cam = tone yếu -40dB (1031,25Hz). Với Rect, "sàn rò rỉ" của tone mạnh cao hơn hẳn tone yếu — tone yếu gần như biến mất. Đổi sang Hann/Hamming/Blackman xem sàn rò rỉ hạ xuống, tone yếu dần lộ rõ.
import { rectWindow, hannWindow, hammingWindow, blackmanWindow, applyWindow, fft, dftMagnitude } from './dsp-core.js';
const fs = 8000, N = 1024;
const strongFreq = 1004, weakFreq = 1031.25, weakAmp = Math.pow(10, -40 / 20); // -40dB
const signal = Array.from({ length: N }, (_, n) =>
Math.sin((2 * Math.PI * strongFreq * n) / fs) + weakAmp * Math.sin((2 * Math.PI * weakFreq * n) / fs)
);
const windows = { rect: rectWindow(N), hann: hannWindow(N), hamming: hammingWindow(N), blackman: blackmanWindow(N) };
const spectrum = dftMagnitude(fft(applyWindow(signal, windows[selectedWindow])));
// bin ~128 = tone manh, bin ~132 = tone yeu - xem spectrum[132] doi the nao theo tung cua so
Tóm lược
- ✅ Leakage: DFT ngầm coi khung là tuần hoàn — nếu tần số không hoàn thành số nguyên chu kỳ, mép nối "gãy" tạo năng lượng giả lan khắp phổ.
- ✅ Toán học trọn vẹn: cắt khung = nhân với cửa sổ chữ nhật = chập phổ với sinc (main lobe + side lobes).
- ✅ Verified ($N=1024$): side lobe rect≈−13,5dB, Hann≈−32,2dB, Hamming≈−42,7dB, Blackman≈−58,3dB — đúng thứ tự kinh điển.
- ✅ Verified: sine không-nguyên-chu-kỳ rò rỉ tới 1 bin xa — biên độ 0,62 (rect) so 0,0006 (Hann), chênh >1000 lần.
- ✅ Coherent gain (rect=1,0 / Hann≈0,50 / Hamming≈0,54 / Blackman≈0,42): cửa sổ "ăn" năng lượng — quên bù là sai biên độ có hệ thống.
- ✅ Không cửa sổ nào thắng tuyệt đối: Hamming tách 2 tone gần, Blackman tìm tone yếu cạnh tone mạnh, Hann là lựa chọn cân bằng mặc định.
Trắc nghiệm ôn tập
Câu 1
Nguyên nhân gốc rễ của hiện tượng rò rỉ phổ (spectral leakage) là gì?
Câu 2
Về mặt toán học, việc cắt một khung tín hiệu hữu hạn tương đương với phép toán nào?
Câu 3
Verified: Blackman có side lobe thấp nhất (≈−58dB) nhưng main lobe RỘNG nhất trong 4 loại cửa sổ. Khi nào nên chọn Blackman?
Câu 4
Quên bù coherent gain khi đo biên độ qua cửa sổ Hann (coherent gain≈0,50) gây ra hậu quả gì?
Tải file code thực hành minh họa bài học
File JavaScript DSPJS (dsp-core.js) — thư viện DSP tự viết dùng xuyên suốt cả
15 bài, Bài 7 vừa thêm 4 hàm cửa sổ (rect/Hann/Hamming/Blackman) + coherent gain + đo side lobe, kèm
self-test đối chiếu đúng mọi hành vi trong bài (chạy node dsp-core.js, không cần cài thêm
gì):
Bình luận