Bộ Lọc Kalman – Giải Pháp Chống Nhiễu Tuyệt Vời Cho Mọi Dự án Sử ...

Phương pháp này được đề suất năm 1960 bởi nhà khoa học có tên Kalman.

Để chứng minh hiệu quả của phương pháp này chúng ta sẽ có một phép thử mô phỏng như sau.

float u0 = 100.0; // giá trị thực (không đổi) float e; // nhiễu float u; // giá trị đo được (có thêm nhiễu) void setup() { Serial.begin(9600); } void loop() { randomSeed(millis()); e = (float)random(-100, 100); u = u0 + e; Serial.println(u); }

Nạp code cho arduino rồi sau đó mở cổng Serial plotter để xem dưới dạng đồ thị:

Kết quả hiển thị trên Serial plotter:

Xem lại code bên trên ta thấy có vài điều như sau:

Gọi u0=100.0 là giá trị thực tế của vật thể, cũng là giá trị mà ta mong muốn thu được, vì u0 là hằng số, (nếu như không có nhiễu). Lý tưởng thì trên đồ thị ta sẽ thu được một đường thẳng song song với trục thời gian t.

Thường thì nhiễu chỉ dao động trong khoảng e=±10% giá trị thực đã được coi là rất ồn rồi (noise).

Để tăng độ khó, mình đã cố ý cho e=±100% u0 bằng hàm Random khiến cho giá trị đo bị nhiễu hoàn toàn và gần như rất khó để thu thập lẫn tính toán sau này.

Sử dụng bộ lọc Kalman

Như đã thống nhất, trong thực tế u0 là giá trị chúng ta không biết, việc sử dụng bộ lọc sẽ phải giúp ta loại bỏ các nhiễu, khi đó giá trị đo được phải gần đường u0=100 hơn .

Vì đây là mô phỏng nên giá trị u0cần được cho trước (chỉ mình và bạn biết) để có thể kiểm chứng tính đúng đắn của kết quả trước và sau khi lọc. (bằng cách trộn u0 với nhiễu rồi cho arduino lọc)

So với code bên trên ,phần code này chỉ cần thêm một dòng lệnh duy nhất:

Gọi u_kalman  là giá trị đo đã qua bộ lọc Kalman:

u_kalman=bo_loc.updateEstimate(u);

Code

#include <SimpleKalmanFilter.h> SimpleKalmanFilter bo_loc(2, 2, 0.001); float u0 = 100.0; // giá trị thực (không đổi) float e; // nhiễu float u; // giá trị đo được (có thêm nhiễu) float u_kalman; // giá được lọc nhiễu void setup() { Serial.begin(9600); } void loop() { randomSeed(millis()); e = (float)random(-100, 100); u = u0 + e; Serial.print(u); Serial.print(","); u_kalman = bo_loc.updateEstimate(u); Serial.print(u_kalman); Serial.println(); }

Và đây là kết quả khi sử dụng thêm bộ lọc:

Đường màu xanh: u.

Đường màu vàng: u_kalman.

Dừng lại một chút để quan sát đồ thị, hẳn bạn cũng đồng ý với mình thuật toán lọc Kalman tỏ ra rất hiệu quả, có những lúc nhiễu dồn ra biên cực đại (±100%u0). nhưng giá trị vẫn khá sát đường u0.

Ghép tầng các bộ lọc ta thu được kết quả chính xác hơn, tất nhiên nó sẽ đáp ứng trễ hơn 1 tầng

#include <SimpleKalmanFilter.h> SimpleKalmanFilter bo_loc(2, 2, 0.001); float u0 = 100.0; // giá trị thực (không đổi) float e; // nhiễu float u; // giá trị đo được (có thêm nhiễu) float u_kalman; // giá được lọc nhiễu void setup() { Serial.begin(9600); } void loop() { randomSeed(millis()); e = (float)random(-100, 100); u = u0 + e; Serial.print(u); Serial.print(","); u_kalman = bo_loc.updateEstimate(u); // tầng 1 u_kalman = bo_loc.updateEstimate(u_kalman); // tầng 2 u_kalman = bo_loc.updateEstimate(u_kalman); // tầng 3 u_kalman = bo_loc.updateEstimate(u_kalman); // tầng 4 Serial.print(u_kalman); Serial.println(); }

Kết quả cho 4 tầng lọc

Bạn nào còn nghi ngờ kết quả giống mình thì copy code rồi test lại dùm mình nhé, thật khó tin phải không ! ^^ devil

Từ khóa » Chống Nhiễu Cho Vi điều Khiển Arduino