Đây là bài tập lớn môn Kiến trúc Máy tính (CO2008) - Trường Đại học Bách Khoa TP.HCM.
Dự án này triển khai Bộ lọc Wiener bằng assembly MIPS để lọc và dự đoán tín hiệu. Bộ lọc Wiener là một kỹ thuật lọc thích nghi cổ điển được sử dụng trong xử lý tín hiệu để ước lượng tín hiệu mong muốn từ một quan sát bị nhiễu, nhằm tối thiểu hóa sai số bình phương trung bình (Mean Square Error - MSE).
wiener_filter.asm- Chương trình MIPS assembly chính thực hiện bộ lọc Wienergenerate_testdata.py- Script Python để tạo dữ liệu test (tín hiệu gốc + nhiễu)wiener_filter_verify.py- Script Python để xác minh kết quả và tính toán đầu ra mong đợi
testcases/- Chứa các trường hợp kiểm thửtest1_white/- Test case với nhiễu trắng (White Gaussian Noise)test2_pink/- Test case với nhiễu hồng (Pink Noise / 1/f noise)
Mỗi test case bao gồm 3 tập tin:
desired.txt- Tín hiệu mong muốn gốc (500 giá trị)noise.txt- Nhiễu (500 giá trị)input.txt- Tín hiệu đầu vào = desired + noise (500 giá trị)
Tất cả giá trị là số thực dấu phẩy động, được làm tròn đến 1 chữ số thập phân.
output.txt - Chứa:
- Dòng đầu:
MMSE: <giá trị>- Giá trị sai số bình phương trung bình tối thiểu - Dòng trống
- 500 dòng tiếp theo: Tín hiệu đầu ra đã được lọc (mỗi giá trị 1 dòng, 1 chữ số thập phân)
Đầu ra của bộ lọc FIR tuyến tính:
y(n) = Σ(k=0 to M-1) h_k * x(n-k)
Phương trình Wiener-Hopf (dạng ma trận):
R_M * h = γ_d
Trong đó:
R_M- Ma trận tự tương quan (autocorrelation) của tín hiệu đầu vào (M×M)h- Vector hệ số bộ lọc tối ưu (M×1)γ_d- Vector tương quan chéo (cross-correlation) giữa tín hiệu mong muốn và đầu vào (M×1)
Hệ số tối ưu:
h_opt = R_M^(-1) * γ_d
MMSE (Minimum Mean Square Error):
MMSE = σ²_d - γ_d^T * R_M^(-1) * γ_d
hoặc tính trực tiếp:
MMSE = (1/N) * Σ(n=0 to N-1) [d(n) - y(n)]²
Theo yêu cầu đề bài, các biến sau phải được định nghĩa trong phần .data:
desired_signal: .space 2000 # Tín hiệu mong muốn (500 floats)
noise: .space 2000 # Nhiễu (500 floats)
input_signal: .space 2000 # Tín hiệu đầu vào (500 floats)
optimize_coefficient: .space 80 # Hệ số bộ lọc tối ưu (20 floats)
MMSE: .float 0.0 # Giá trị MMSE
out: .space 2000 # Tín hiệu đầu ra (500 floats)
- Đọc
desired.txtvào mảngdesired_signal - Đọc
input.txtvào mảnginput_signal - Kiểm tra kích thước 2 file có khớp nhau không
Với mỗi cặp (i, j) từ 0 đến M-1:
R[i][j] = (1/N) * Σ(n=0 to N-|i-j|-1) x[n] * x[n + |i-j|]
Với mỗi i từ 0 đến M-1:
γ_d[i] = (1/N) * Σ(k=0 to N-i-1) d[i+k] * x[k]
Giải R * h = γ_d để tìm hệ số tối ưu h
Lưu ý: Trong code MIPS, sử dụng phương pháp đơn giản hóa (diagonal approximation) do hạn chế của assembly. Trong thực tế nên dùng Gaussian elimination hoặc Cholesky decomposition.
Với mỗi n từ 0 đến N-1:
y[n] = Σ(k=0 to M-1) h[k] * x[n-k] (nếu n-k >= 0)
MMSE = (1/N) * Σ(n=0 to N-1) [d[n] - y[n]]²
Ghi MMSE và mảng đầu ra vào output.txt
- MARS MIPS Simulator - Để chạy code assembly
- Python 3.x với NumPy - Để tạo test data và verify
# Tạo virtual environment (nếu cần)
python3 -m venv venv
source venv/bin/activate # macOS/Linux
# hoặc: venv\Scripts\activate # Windows
# Cài đặt numpy
pip install numpy
# Tạo test data
python3 generate_testdata.pyScript sẽ tạo 2 test cases:
test1_white- Với nhiễu trắng (White Gaussian Noise)test2_pink- Với nhiễu hồng (Pink/1f Noise)
python3 wiener_filter_verify.pyScript này sẽ:
- Tính toán kết quả mong đợi bằng Python
- Tạo file
output.txttrong mỗi test case - Hiển thị thống kê (MMSE, improvement, v.v.)
- Mở MARS MIPS Simulator
- Load file
wiener_filter.asm - Copy các file test vào thư mục làm việc:
testcases/test1_white/desired.txt -> desired.txt testcases/test1_white/input.txt -> input.txt - Assemble và run chương trình
- Kiểm tra file
output.txtđược tạo ra - So sánh với kết quả từ Python script
So sánh file output.txt từ MIPS với file từ Python:
# Ví dụ cho test case 1
diff output.txt testcases/test1_white/output.txt- Filter order: 20
- MMSE: ~0.69
- Input MSE: ~3.84
- Output MSE: ~0.69
- Improvement: ~82%
- Filter order: 20
- MMSE: ~0.97
- Input MSE: ~4.01
- Output MSE: ~0.97
- Improvement: ~76%
main- Hàm chính, điều khiển luồng chương trìnhread_signal_file- Đọc tín hiệu từ fileparse_float- Parse chuỗi thành số floatapply_wiener_filter- Áp dụng bộ lọc Wienercompute_autocorrelation_matrix- Tính ma trận R_Mcompute_autocorrelation- Tính tự tương quan cho 1 lagcompute_cross_correlation- Tính vector γ_dsolve_linear_system- Giải hệ phương trình tuyến tínhapply_fir_filter- Áp dụng bộ lọc FIRcompute_mse- Tính Mean Square Errorwrite_output_file- Ghi kết quả ra filefloat_to_string- Chuyển float thành chuỗiint_to_string- Chuyển integer thành chuỗi
.data segment:
- Signal arrays (500 elements × 4 bytes = 2000 bytes each)
- Autocorrelation matrix (20×20 × 4 bytes = 1600 bytes)
- Cross-correlation vector (20 × 4 bytes = 80 bytes)
- Filter coefficients (20 × 4 bytes = 80 bytes)
- Buffers and constants
-
Giải hệ phương trình: Do độ phức tạp, code MIPS sử dụng phương pháp đơn giản hóa (diagonal approximation) thay vì Gaussian elimination đầy đủ. Điều này có thể làm giảm độ chính xác.
-
File I/O: MARS MIPS có hạn chế về file I/O. Đảm bảo các file input nằm đúng thư mục làm việc.
-
Floating-point precision: MIPS single-precision float có thể có sai số làm tròn nhỏ so với Python double-precision.
-
Memory limits: MARS có giới hạn bộ nhớ. Code này đã được tối ưu cho tín hiệu 500 mẫu và filter order 20.
- Đảm bảo file
input.txtvàdesired.txtcó cùng số dòng - Mỗi dòng trong file chỉ chứa 1 số với 1 chữ số thập phân
- Không có dòng trống hoặc ký tự lạ trong file input
- File paths phải chính xác (tương đối với working directory của MARS)
- Digital Signal Processing - Proakis & Manolakis
- Adaptive Filter Theory - Simon Haykin
- Course materials: Computer Architecture Lab (CO2008)
Bài tập được thực hiện cho môn Kiến trúc Máy tính (CO2008)
Khoa Khoa học và Kỹ thuật Máy tính
Trường Đại học Bách Khoa TP.HCM
Năm học 2025-2026
Dự án này được tạo ra cho mục đích học tập.
Nguyên nhân: File desired.txt và input.txt có số dòng khác nhau.
Giải pháp: Kiểm tra lại 2 file, đảm bảo cùng có 500 dòng.
Nguyên nhân: MARS không tìm thấy file input.
Giải pháp:
- Copy file vào thư mục làm việc của MARS
- Hoặc đổi đường dẫn trong code assembly
Nguyên nhân:
- Sai số làm tròn floating-point
- Phương pháp giải hệ phương trình đơn giản hóa
Giải pháp:
- Chấp nhận sai số nhỏ (< 5%)
- Để có kết quả chính xác hơn, cần implement Gaussian elimination đầy đủ
Nguyên nhân: Thuật toán có độ phức tạp O(N²M²) với N=500, M=20.
Giải pháp:
- Giảm filter order M (ví dụ: M=10)
- Giảm số lượng sample N
- Chạy trên máy tính mạnh hơn
- Sử dụng SPIM thay vì MARS (nhanh hơn nhưng ít UI hơn)
Chúc các bạn làm bài tốt! 🎓