- Vì các phép đo vị trí và vận tốc trong thực tế luôn dao động, có thể hiểu bộ lọc Kalman là cách kết hợp nhiều nguồn thông tin không hoàn hảo để tạo ra ước lượng trạng thái đáng tin cậy hơn
- Trong ví dụ về vị trí của con tàu, mô hình tốc độ động cơ 10m/s sẽ bị lệch do gió và sóng, còn cảm biến như GPS cũng không phải lúc nào cũng chính xác do nhiễu hoặc sự cố
- Mã ví dụ cho 1.000 hành khách, mỗi người tạo một ước lượng dựa trên vận tốc và một phép đo cảm biến, rồi kết hợp hai giá trị bằng trung bình có trọng số để minh họa trực giác của bộ lọc Kalman
- Độ tin cậy của các nguồn thông tin được tính bằng phương sai của các giá trị đo; dùng
1/variance để ít tin hơn vào phía dao động lớn và phản ánh mạnh hơn phía nhất quán
- Khi cảm biến hoạt động bình thường thì hệ sẽ theo giá trị cảm biến nhiều hơn, còn ở các đoạn dao động như
t=3 và t=6 thì ảnh hưởng của cảm biến tự động giảm xuống, duy trì ước lượng ổn định hơn
Khi nào cần bộ lọc Kalman
- Có thể xem bộ lọc Kalman như một cái phễu nén nhiều nguồn thông tin có nhiễu thành một giá trị thống kê chính xác hơn
- Về mặt toán học, nó liên quan đến đại số tuyến tính, lý thuyết xác suất và giải tích, nhưng ở đây tập trung vào trực giác hơn là lý thuyết đầy đủ
- Giả sử một con tàu xuất phát từ cảng tại
x=0, di chuyển một chiều, và động cơ cung cấp vận tốc không đổi 10m/s
- Trong thế giới lý tưởng, vị trí sau 2 giây sẽ là
2 * 10 = 20m, nhưng trong thế giới thực, vận tốc và vị trí không được giữ chính xác do động cơ, gió và sóng
- Vì vậy, chỉ dựa vào công thức vị trí thì khó có thể chắc chắn về vị trí thực tế của con tàu
Cảm biến cũng không hoàn hảo
- Nếu có cảm biến như GPS, ta có thể đo trực tiếp vị trí tại một thời điểm cụ thể, nhưng giá trị đo của cảm biến cũng không phải lúc nào cũng chính xác
- GPS có thể trả về giá trị gần với vị trí thực như 29.998m hoặc 30.002m tại thời điểm 3 giây, và rất hiếm khi có thể lệch mạnh như 100m
- Ở những khu vực không có vùng phủ vệ tinh, cảm biến GPS trên thực tế có thể không hoạt động
- Nếu cảm biến không bao giờ offline và có thể đo giá trị mong muốn với độ chính xác tùy ý, ta sẽ không cần bộ lọc Kalman
- Bộ lọc Kalman có thể kết hợp nhiều nguồn thông tin như ước lượng vị trí dựa trên vận tốc, ước lượng GPS, radar, sonar để ước lượng vị trí chính xác hơn
Ước lượng vị trí qua mã nguồn
- Ví dụ giả định trên tàu có 1.000 hành khách, mỗi người có thiết bị GPS riêng
- Trước hết, mỗi hành khách ước lượng vị trí mới bằng cách cộng vận tốc và biến động của các yếu tố bên ngoài vào vị trí trước đó
from random import gauss
def new_position(last):
velocity = 10
wind = gauss(0, 2)
wave = gauss(0, 0.1)
return last + velocity + wind + wave
gauss tạo ra giá trị ngẫu nhiên dương hoặc âm, và tham số thứ hai biểu thị độ lớn của biến động
- Vì không thể đo trực tiếp tác động của gió và sóng, ví dụ mô hình hóa nhiễu bằng số ngẫu nhiên có trung bình 0 và độ lệch chuẩn
2, 0.1
- Ở bước thứ hai, cảm biến trả về giá trị đo bằng cách cộng nhiễu cảm biến vào vị trí thực
def sensor(t):
if t == 3:
# oops, passing through a thunderstorm. GPS fluctuating!
sensor_noise = gauss(5, 10)
elif t == 6:
# uh-oh, satellite unavailable!
sensor_noise = gauss(-5, 10)
else:
sensor_noise = gauss(0, 1)
return true_position[t] + sensor_noise
- Tại
t=3, mô hình hóa tình huống GPS dao động do giông bão; tại t=6, mô hình hóa tình huống không dùng được vệ tinh
- Ngay cả ở cùng một thời điểm, giá trị đo cảm biến cũng khác nhau giữa các hành khách
Quỹ đạo thực tế và trung bình đơn giản
- Vị trí thực tế của con tàu được cho bởi danh sách sau
true_position = [0, 9, 19.2, 28, 38.1, 48.5, 57.2, 66.2, 77.5, 85, 95.2]
- Con tàu xuất phát từ cảng tại
x=0, đi được 9m sau 1 giây, 19.2m sau 2 giây, rồi di chuyển theo các giá trị trong danh sách
- Mục tiêu của hành khách là dự đoán vị trí ở từng giây chính xác nhất có thể từ các phép đo có nhiễu và không đáng tin cậy
- Nếu ở
t=1, ước lượng dựa trên vận tốc của một hành khách là 9.37, còn phép đo cảm biến là 8.98, thì trung bình đơn giản là 9.17
- Khi vị trí thực là 9m, trung bình đơn giản này có sai số nhỏ hơn so với ước lượng vận tốc, nhưng tệ hơn phép đo cảm biến trong ví dụ đó
Trung bình có trọng số và độ tin cậy
- Một phương pháp tốt hơn trung bình đơn giản là dùng trung bình có trọng số
def combine(A, B, trustA, trustB):
total_trust = trustA + trustB
return (A * trustA + B * trustB) / total_trust
combine(9.37, 8.98, 10, 1) tin vào ước lượng vận tốc nhiều hơn, nên kết quả là 9.33, gần với 9.37
combine(9.37, 8.98, 1, 10) tin vào phép đo cảm biến nhiều hơn, nên kết quả là 9.01, gần với 8.98
- Trung bình có trọng số dựa trên độ tin cậy này là trực giác cốt lõi của bộ lọc Kalman, và là trọng tâm của việc kết hợp dữ liệu
- Việc nên tin nguồn thông tin nào hơn được quyết định bằng phương sai
- Nguồn thông tin có kết luận dao động mạnh thì được tin ít hơn
- Nguồn thông tin có kết luận nhất quán thì được tin nhiều hơn
- Nếu trong 10 đài phát thanh có 4 đài nói trời mưa, 6 đài nói trời nắng, còn trong 10 website có 9 website nói trời mưa, thì phía website có phương sai thấp hơn nên đáng tin hơn
Bước cập nhật
- Toàn bộ quá trình cập nhật tạo các ước lượng dựa trên vận tốc và các phép đo cảm biến cho từng hành khách, rồi tính độ tin cậy bằng phương sai của hai nhóm phép đo
from statistics import variance
def update(t, last):
velocity_updates = []
sensor_updates = []
for p in range(1000):
velocity_updates.append(new_position(last[p]))
sensor_updates.append(sensor(t))
fluctuation_velocity = variance(velocity_updates)
fluctuation_sensor = variance(sensor_updates)
trust_velocity = 1 / fluctuation_velocity
trust_sensor = 1 / fluctuation_sensor
combined = []
for p in range(1000):
combined.append(combine(
A=velocity_updates[p],
B=sensor_updates[p],
trustA=trust_velocity,
trustB=trust_sensor
))
return sensor_updates, velocity_updates, combined
- Vì phương sai càng lớn thì độ tin cậy càng thấp, nên dùng
1/variance
- Mỗi hành khách cập nhật vị trí của mình một cách riêng biệt
- Sau khi cập nhật vị trí của tất cả hành khách, có thể suy ra ước lượng vị trí thực tế của con tàu bằng trung bình các vị trí của hành khách
Cách đọc kết quả
- Hàm
update_plot lưu vị trí thực, ước lượng cảm biến, ước lượng vận tốc và ước lượng kết hợp tại từng thời điểm để tạo biểu đồ
- Vòng lặp chính tiếp tục cập nhật ước lượng vị trí ở mỗi thời điểm bằng cách dùng ước lượng tốt nhất hiện tại mà các hành khách đang có
- Trên biểu đồ, envelope quanh đường biểu thị độ bất định; bề rộng càng lớn thì độ bất định đối với giá trị đó càng cao
- Trong khoảng từ
t=0.75 đến t=1, khi cảm biến hoạt động bình thường, ước lượng vị trí kết hợp tốt hơn so với chỉ dùng ước lượng vận tốc, nhưng có thể kém hơn so với chỉ dùng phép đo cảm biến
- Trong khoảng từ
t=2 đến t=4, khi cảm biến bị lỗi, ước lượng kết hợp cho kết quả tốt hơn so với chỉ dùng phép đo cảm biến bị lỗi
- Trong khoảng từ
t=4 đến t=5, khi cảm biến hồi phục, bộ lọc Kalman bắt đầu ưu tiên cảm biến nhiều hơn trở lại
Phụ lục: gauss và phương sai
gauss(0, 0.1) và gauss(0, 2), là normal distribution function, chủ yếu tạo ra các giá trị ngẫu nhiên quanh 0
- Tham số thứ hai, độ lệch chuẩn, kiểm soát mức độ dao động của các giá trị đo
gauss(0, 0.1) có khả năng cao tạo ra các giá trị nhỏ quanh 0 như 0.06, -0.07, 0.02
gauss(0, 2) có khả năng cao tạo ra các giá trị phân tán rộng hơn như 1.05, -1.06, 1.29, -1.72
- Trong mã ví dụ, giả định gió biến thiên mạnh hơn, còn sóng nước biến thiên nhỏ hơn
- Phương sai là thước đo tính nhất quán; tính nhất quán cao thì phương sai thấp, tính nhất quán thấp thì phương sai cao
- Phân phối có độ lệch chuẩn 2 thì phương sai là 4, còn phân phối có độ lệch chuẩn 0.1 thì phương sai là 0.01
1 bình luận
Ý kiến trên Hacker News
Bài viết đọc khá thú vị, nhưng phần triển khai bị sai. Lỗi lớn nhất là không lan truyền độ bất định theo trục thời gian, nên đánh giá thấp sai số
Điều này cũng thể hiện trên đồ thị: khoảng sai số lẽ ra phải bao gồm trạng thái thực trong phần lớn thời gian, nhưng kết quả lại không như vậy
Không phải hành khách thêm nhiễu vào giá trị ước lượng; từ góc nhìn của hành khách, khi đã biết trạng thái tại thời điểm k, kỳ vọng của trạng thái tại thời điểm k+1 đơn giản là
position_k+1 = position_k + velocity * Delta_t. Động lực học thực tế có nhiễu, và trong bộ lọc, điều đó được phản ánh bằng cách cộng vào hiệp phương sai ước lượngLý do code không hỏng ngay là vì với 1000 hành khách, nó lấy rất nhiều mẫu động lực học rồi tính phương sai của kết quả bằng số, nhưng cách này khá khác với cách thường làm trong thực tế
Ngoài ra, GPS bị ảnh hưởng bởi thời tiết là một hiểu lầm phổ biến, thực tế không phải vậy. Và định nghĩa về tính nhất quán dùng trong bài cũng không chuẩn. Trong lý thuyết ước lượng, nói một bộ ước lượng nhất quán nghĩa là khi dữ liệu tăng lên, giá trị ước lượng hội tụ về giá trị thật
Việc diễn giải dễ hiểu cho độc giả phổ thông là tốt, nhưng có vẻ một vài hiểu lầm đang gây ra vấn đề. Tôi là nghiên cứu sinh về lý thuyết ước lượng, nên nếu trao đổi thêm thì có thể giúp được
Nó khiến tôi tự hỏi tại sao trong các môn xử lý tín hiệu ở đại học, người ta không dạy Kalman Filter đơn giản như thế này. Khái niệm toán học thì đúng là nên dạy bằng toán, nhưng với người thiếu kiến thức nền, sẽ có mất mát thông tin
Trước đây tôi từng dạy biến đổi cosin rời rạc và biến đổi wavelet theo hướng lấy hình ảnh làm trung tâm; cách cho trực giác trước rồi mới đến sự chặt chẽ luôn hiệu quả hơn thứ tự ngược lại
Có thể có vài lý do khiến các giáo sư không đưa trực giác trước. Có người bản thân có chuyên môn sâu hơn về con số và thao tác phương trình hơn là trực giác; có người vì năng lực giảng dạy không được tưởng thưởng nên dành thời gian cần để diễn giải trực quan cho việc viết đề xuất xin tài trợ nghiên cứu hoặc quản lý nghiên cứu sinh; và cũng có trường hợp sau khi đã hiểu toán, lời giải thích trực quan lại trông như “con đường khó”, khiến bộ não không muốn quay lại
Tôi nghĩ lý do thứ ba là lớn nhất. Đây cũng là sự khác biệt giữa chuyên môn và năng lực giảng dạy, vượt ra ngoài giáo dục toán học. Nếu muốn học đánh driver trong golf, có khi học từ người bắt đầu ở 100 yard rồi dần đánh ổn định 300 yard sẽ tốt hơn học từ người đánh xa nhất
Một cảnh báo chung cho những ai muốn triển khai Kalman Filter: để xử lý bất ổn định số học, nên đọc vài trang đầu của https://www.stat.berkeley.edu/~brill/Stat248/kalmanfiltering...
Trong thực tế, làm như vậy tôi hiếm khi thấy artifact số học đáng chú ý, nhưng đây là một giải pháp khá hấp dẫn
Bổ sung cho bài này, nếu muốn nhập môn họ Kalman Filter một cách kỹ lưỡng và có tính toán học hơn, tôi rất khuyến nghị cuốn sách này: https://github.com/rlabbe/Kalman-and-Bayesian-Filters-in-Pyt...
Đây là sách do một software engineer từng phải triển khai Kalman Filter trong công việc viết, nên cách tạo động lực và truyền đạt khái niệm có thể rất phù hợp với nhóm độc giả này. Sách được viết dưới dạng Jupyter notebook tương tác, có thể clone kho lưu trữ rồi tự chạy để theo dõi
Nó bắt đầu từ một bộ lọc đơn giản, rồi dần cải thiện bằng cách đưa quy tắc Bayes vào và mở rộng sang phân phối xác suất, nhờ đó tạo một lối vào nhẹ nhàng để tiếp cận Kalman Filter
Có một khía cạnh bị bỏ sót. Khi lấy trung bình có trọng số giữa giá trị dự đoán và giá trị đo, trọng số của Kalman Filter có thể thay đổi theo thời gian. Nếu không thì có lẽ nó sẽ được gọi bằng tên khác
Ví dụ đo một giá trị thay đổi chậm bằng một cảm biến đơn lẻ là rất hay. Chẳng hạn với đồng hồ nhiên liệu, theo đơn vị giây thì tốt nhất nên giả định nó không thay đổi, nhưng giá trị đo có thể có nhiễu như nhiên liệu dao động trong bình
Trong trường hợp này, Kalman Filter trông giống như bộ lọc thông thấp bậc một có độ lợi suy giảm theo hàm mũ. Tần số cắt thay đổi, nên nó nhanh chóng tìm được mức ban đầu trong vài giây, rồi sau đó có thể bỏ qua nhiễu với tần số cắt rất thấp như 0,01Hz
Đây là một bài viết hay về một công cụ quan trọng
Theo cách tôi hiểu, Kalman Filter tuyến tính là lời giải tối ưu cho các bài toán tuyến tính, và tương đối dễ hiểu cũng như dễ triển khai. Nhưng hầu hết các ứng dụng tôi từng thấy đều là phi tuyến
Extended Kalman Filter và Unscented Kalman Filter khó hiểu và khó triển khai hơn nhiều, tài liệu cũng như thư viện thì ít hơn và kém hữu dụng hơn
Ví dụ, khi làm việc với thiết bị AHRS/GNSS CAN cho UAV cỡ nhỏ, Extended Kalman Filter mà tôi thấy trong PX4 hay Ardupilot rất phức tạp và có rất nhiều tham số. Vì vậy, cách bắt đầu từ nguyên lý cơ bản của quaternion rồi từng chút một hiệu chỉnh nghiệm gyro về phía “hướng lên” của gia tốc kế và về phía vector độ nghiêng của từ kế thì đơn giản hơn
Nếu độ lớn gia tốc khác 1G quá nhiều, hoặc vector từ trường khác nhiều so với cường độ từ trường Trái Đất tại khu vực đó, thì giảm trọng số hoặc bỏ qua cập nhật của cảm biến tương ứng, để gyro tiếp tục chạy như cũ. Có lẽ EKF nhiều khả năng là đáp án đúng, nhưng tôi đã bỏ cuộc trong việc đưa nó về một dạng dễ hiểu, dễ xây dựng, dễ tinh chỉnh và chẩn đoán
Tuy nhiên với quadrotor, điểm khó lớn là phép quay. Mô hình tuyến tính của Kalman Filter giả định mọi thứ nằm trong không gian Euclid, nhưng phép quay lại nằm trên một đa tạp. Với quaternion, đa tạp này là tập các quaternion đơn vị
Nếu áp dụng EKF một cách ngây thơ để ước lượng quaternion, nó sẽ không còn là quaternion đơn vị nữa và giá trị ước lượng sẽ bị hỏng. Có những phương pháp đã biết để xử lý ràng buộc đa tạp này, nhưng trong số các phương trình tôi từng chuyển thành code, chúng thuộc loại khó coi nhất
Một ví dụ đơn giản là có thể xét trạng thái
(x, y)mà do các định luật vật lý nên luôn phải nằm trên đường tròn đơn vị. Động lực học thực tếf(x, y)cho ra một điểm mới trên đường tròn, nhưng động lực học xấp xỉ sau khi tuyến tính hóa không có gì đảm bảo vẫn nằm trên đường tròn đơn vị, nên có thể dẫn đến trạng thái phi vật lý hoặc ước lượng trạng thái EKF phi vật lýMột số lựa chọn đáng xem qua là ForneyLab.jl, Infer.net, Gen.jl, Pyro
Nhưng có nhiều cách sử dụng Kalman Filter, và tùy bạn bắt đầu từ đâu, việc xử lý đúng các biến đổi phi tuyến có thể trở nên cực kỳ phiền phức
Tôi bị cận thị và loạn thị, và khi nhắm một mắt để nhìn thứ gì đó như đồng hồ treo tường, tôi nhận ra mỗi mắt tạo ra một hình ảnh bị méo khác nhau. Hai mắt hơi khác nhau
Nhưng khi nhìn đồng hồ bằng cả hai mắt, hình ảnh rõ hơn nhiều, tốt hơn so với nhìn bằng bất kỳ một mắt nào. Kịch bản trong bài về 1000 hành khách trên tàu báo cáo tọa độ GPS của từng người khiến tôi nhớ đến hiện tượng này
Có lẽ não cũng sử dụng rộng rãi những thuật toán thông minh kiểu Kalman Filter
Hiểu Kalman Filter là thứ giúp ước lượng giá trị tốt hơn trung bình đơn giản từ các quan sát có nhiễu thì có đúng không?
Ví dụ, nếu đo một thứ 3 lần được 7, 8, 9 thì ta sẽ đoán giá trị thực là 8; Kalman Filter có đưa ra một ước lượng khác không?
Theo truyền thống, Kalman Filter được dùng để ước lượng những thứ chuyển động theo thời gian. Hãy nghĩ đến một người trong video, hoặc một dạng bước đi ngẫu nhiên nào đó
Nếu giả định giữa hai thời điểm hoặc hai phép đo liên tiếp có quan hệ như vận tốc và hướng hiện tại, ta có thể trộn thông tin từ mô hình chuyển động với thông tin từ mô hình đo có nhiễu để ước lượng tốt hơn vị trí, giá trị, hoặc toàn bộ lịch sử di chuyển
Nếu mô hình chuyển động sai một cách có ý nghĩa, ước lượng sẽ không được cải thiện. Nhiều phương pháp mở rộng về sau tập trung vào việc đưa vào các mô hình chuyển động tinh vi hơn, như trượt bánh trong robot học
Ví dụ, khi đo một hằng số, ta có thể đặt mô hình cơ bản là một hằng số có độ bất định ban đầu, chẳng hạn một phân phối Gaussian có độ lệch chuẩn, cùng với các phép đo cũng có nhiễu Gaussian và độ lệch chuẩn. Có thể điều chỉnh độ bất định ban đầu quanh hằng số cần ước lượng và độ bất định của phép đo
Trong ví dụ này, Kalman Filter không hành xử như phép trung bình. Nếu phép đo tốt, tức độ bất định thấp, nó sẽ hội tụ nhanh; nếu phép đo tệ, giá trị ước lượng sẽ dao động và mất nhiều thời gian hơn để hội tụ
Và nói Kalman Filter chỉ dùng cho những thứ chuyển động là không đúng. Nó cũng luôn được dùng cho ước lượng hằng số, chỉ là nổi tiếng hơn trong trường hợp các đối tượng chuyển động
Kalman Filter xử lý trường hợp các mẫu có tương quan do một động lực học tuyến tính nào đó. Giá trị đo cũng không nhất thiết phải là chính đối tượng quan tâm; nó có thể là một hàm tuyến tính của đối tượng đó cộng thêm nhiễu Gaussian
Vì vậy, việc biết rằng ở phép đo đầu tiên ta thấy 7 sẽ làm thay đổi xác suất thấy 8 ở phép đo thứ hai. Nếu chỉ lấy trung bình mẫu như trên thì nói chung sẽ không hội tụ về giá trị trung bình thực
Trong ví dụ, nó sẽ đưa ra gì phụ thuộc vào mô hình chính xác. Ngay cả trong kịch bản đơn giản nhất có thể tưởng tượng, cũng như trong Bayes, bạn phải chỉ định sẽ bắt đầu từ kỳ vọng nào
Nếu mã hóa cách diễn đạt đó thành mô hình Gaussian tuyến tính, ta sẽ có Kalman Filter
Một bài viết ngắn khác giúp hiểu thêm về Kalman Filter và đem lại một nhận ra nữa là ghi chú của John D. Cook: https://www.johndcook.com/blog/applied-kalman-filtering/
Trong khi mô hình hóa hệ thống truyền thống dựa trên giải tích và phương trình vi phân cho rằng dữ liệu không có bất định và mọi thứ đều được chứa trong mô hình hệ thống, thì bộ ước lượng dựa trên dữ liệu lại cho rằng “mọi thứ đều nằm trong dữ liệu” và hoàn toàn bỏ qua mô hình của quá trình vật lý tạo ra dữ liệu
Vẻ đẹp của Kalman Filter nằm ở việc nó kết hợp hai cách tiếp cận này
Cũng có một bài viết khác với phần trực quan hóa rất tốt: https://www.bzarg.com/p/how-a-kalman-filter-works-in-picture...
Đây là bài đã từng được đăng lên HN ba lần