DMDT
  • Danh Mục
    • Vi Điều Khiển
      • 8051
      • Arduino
      • AVR
      • IC Chức Năng
      • PIC
    • Module
      • MD Chuyển Đổi
      • MD GSM,GPS,3G
      • MD LCD
      • MD Nguồn
      • MD Wifi
    • Điện Tử Cơ Bản
      • ADC/DAC
      • Bộ Nhớ Bán Dẫn
      • Các Họ IC Số
      • Họ OPAM
      • Mạch Tổ Hợp
      • Mạch Tuần Tự
      • Linh Kiện Cơ Bản
    • Mạch Điện Vui
      • DIY – Tự Ráp Mạch
      • Hướng Dẫn Thiết Kế Mạch
      • Sản Phẩm Sáng Tạo
      • Tự Làm Mạch In
    • Cảm Biến
      • Analog (Tín hiệu điện áp)
      • Digital (Tín hiệu số)
  • Phần Mềm
  • Đồ Án
No Result
View All Result
DMDT
  • Danh Mục
    • Vi Điều Khiển
      • 8051
      • Arduino
      • AVR
      • IC Chức Năng
      • PIC
    • Module
      • MD Chuyển Đổi
      • MD GSM,GPS,3G
      • MD LCD
      • MD Nguồn
      • MD Wifi
    • Điện Tử Cơ Bản
      • ADC/DAC
      • Bộ Nhớ Bán Dẫn
      • Các Họ IC Số
      • Họ OPAM
      • Mạch Tổ Hợp
      • Mạch Tuần Tự
      • Linh Kiện Cơ Bản
    • Mạch Điện Vui
      • DIY – Tự Ráp Mạch
      • Hướng Dẫn Thiết Kế Mạch
      • Sản Phẩm Sáng Tạo
      • Tự Làm Mạch In
    • Cảm Biến
      • Analog (Tín hiệu điện áp)
      • Digital (Tín hiệu số)
  • Phần Mềm
  • Đồ Án
No Result
View All Result
DMDT
No Result
View All Result
Home Vi Điều Khiển Arduino

Bộ lọc Kalman chống nhiễu tuyệt vời cho các dự án sử dụng cảm biến

20 Tháng Sáu, 2022
in Arduino, Vi Điều Khiển
688 7

  Khi ta sử dụng cảm biến, giá trị trả về từ chúng luôn thay đổi quanh vị trí cân bằng dù là rất nhỏ, và bạn biết nguyên nhân của hiện tượng này  là do nhiễu, bạn luôn muốn loại bỏ nhiễu nhưng việc đó dường như ngoài tầm với của bạn.  Đừng lo, chúng ta đã có giải pháp, Bạn chỉ cần đọc bài viết này !

I.Nhiễu

 Trong đo lường, do các yếu tố cả chủ quan lẫn khách quan mà kết quả đo đạc luôn chỉ được coi là tương đối so với giá trị thực cần đo. Độ chênh lệch giữa giá trị đo được với giá trị thực được gọi là Sai số.

Sai số gây ra bởi nhiễu, chúng được phân làm 2 loại chính: sai số hệ thống hoặc sai số ngẫu nhiên.

Đọc thêm tại:  https://vi.wikipedia.org/wiki/Sai_s%…

Giả sử ta tiến hành đo giá trị điện áp của một cục pin năng lượng mặt trời, kết quả thu được trên đồ thị như sau :

 

Giả sử giá trị điện áp thực của pin mặt trời là u0=1.9545 vol.

Do ảnh hưởng bởi nhiều yếu tố trong quá trình đo đạc, sai số xuất hiện là điều rất khó tránh khỏi, kết quả là ta chỉ có thể đo giá trị điện áp bằng cách lấy tương đối kết quả trung bình các phép đo .

  • Tức u0=u ± ∆ e =1.95 ± 1%,  (với ∆ e là sai số)

II.Loại bỏ nhiễu bằng thuật toán lọc Kalman

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.

2.1.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ị u0 cầ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.

2.2.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

III.Ma thuật hay trí tuệ nhân tạo

Đây là thành quả nghiên cứu có từ 56 năm trước, chủ nhân của thuật toán là ông Rudolf (Rudy) E. Kálmán  

Bộ lọc này được sử dụng rộng rãi trong các máy tính kỹ thuật số của các hệ thống điều khiển, Hệ thống định vị, Hệ thống điện tử, RADA, vệ tinh dẫn đường để lọc nhiễu.

Bộ lọc hoạt động ổn định đến mức, nó đã được sử dụng trong chương trình Apollo, tàu con thoi của NASA, tàu ngầm Hải quân và xe tự hành không gian không người lái và vũ khí, tên lửa hành trình.

Với thành công đó, ông cũng đã nhận được rất nhiều giải thưởng lớn khác nhau.

https://vi.wikipedia.org/wiki/Rudolf…

IV.Thuật toán Kalman trong C

Đây là thuật toán đơn giản mình tìm được, hãy vào địa chỉ bên dưới để hiểu được ý nghĩa của các tham số K (Kalman Gian) ,P,Q,R….

https://malcolmmielle.wordpress.com/…

/*
* Need to tweak value of sensor and process noise
* arguments :
* process noise covariance
* measurement noise covariance
* estimation error covariance */
 
class Kalman_Filter_Distance {
protected:
    double _q; //process noise covariance
    double _q_init;
    double _r; //measurement noise covariance
    double _r_init;
    double _x; //value
    double _p; //estimation error covariance
    double _p_init;
    double _k; //kalman gain
 
public:
    /*
* Need to tweak value of sensor and process noise
* arguments :
* process noise covariance
* measurement noise covariance
* estimation error covariance */
    Kalman_Filter_Distance(double q, double r, double p)
        : _q(q)
        , _q_init(q)
        , _r(r)
        , _r_init(0)
        , _x(0)
        , _p(p)
        , _p_init(p)
        , _k(_p / (_p + _r)){};
    virtual void init(double x) { _x = x; }
    virtual void setProcessNoiseCovariance(double i)
    {
        _q = i;
        _q_init = i;
    }
    virtual void setMeasurementNoiseCovariance(double i)
    {
        _r = i;
        _r_init = i;
    }
    virtual void setEstimatiomErrorCovariance(double i)
    {
        _p = i;
        _p_init = i;
    }
    virtual double kalmanUpdate(double measurement);
    virtual void reset()
    {
        _q = _q_init;
        _r = _r_init;
        _p = _p_init;
    };
};
 
double Kalman_Filter_Distance::kalmanUpdate(double measurement)
{
    //prediction update
    //omit _x = _x
    _p = _p + _q;
 
    //measurement update
    _k = _p / (_p + _r);
    _x = _x + _k * (measurement - _x);
    _p = (1 - _k) * _p;
 
    return _x;
}

 

Các thư viện với các cảm biến bạn có thể đọc thêm Tại đây:

Tags: arduinoKalmanlập trình arduino
Share516Tweet323

Related Posts

Mạch điều khiển thiết bị và giám sát nhiệt độ qua Internet dùng App Blynk
Arduino

Mạch điều khiển thiết bị và giám sát nhiệt độ qua Internet dùng App Blynk

26 Tháng Sáu, 2022
Lập Trình Arduino – Chia Sẻ Mạch Quản lý Bãi Đỗ Xe Bằng Thẻ RFID
Arduino

Lập Trình Arduino – Chia Sẻ Mạch Quản lý Bãi Đỗ Xe Bằng Thẻ RFID

26 Tháng Sáu, 2022
Lập trình Arduino – Lập trình Kết nối với module bàn phím 4×4
Arduino

Lập trình Arduino – Lập trình Kết nối với module bàn phím 4×4

26 Tháng Sáu, 2022
Next Post
Chia sẻ Thư viện truyền dữ liệu theo gói tin trên Arduino

Chia sẻ Thư viện truyền dữ liệu theo gói tin trên Arduino

Xung PPM

Xung PPM

0 0 đánh giá
Đánh giá bài viết
Theo dõi
Đăng nhập
Thông báo của
guest
guest
0 Góp ý
Phản hồi nội tuyến
Xem tất cả bình luận

No Result
View All Result
  • Danh Mục
    • Vi Điều Khiển
      • 8051
      • Arduino
      • AVR
      • IC Chức Năng
      • PIC
    • Module
      • MD Chuyển Đổi
      • MD GSM,GPS,3G
      • MD LCD
      • MD Nguồn
      • MD Wifi
    • Điện Tử Cơ Bản
      • ADC/DAC
      • Bộ Nhớ Bán Dẫn
      • Các Họ IC Số
      • Họ OPAM
      • Mạch Tổ Hợp
      • Mạch Tuần Tự
      • Linh Kiện Cơ Bản
    • Mạch Điện Vui
      • DIY – Tự Ráp Mạch
      • Hướng Dẫn Thiết Kế Mạch
      • Sản Phẩm Sáng Tạo
      • Tự Làm Mạch In
    • Cảm Biến
      • Analog (Tín hiệu điện áp)
      • Digital (Tín hiệu số)
  • Phần Mềm
  • Đồ Án

Welcome Back!

Login to your account below

Forgotten Password?

Retrieve your password

Please enter your username or email address to reset your password.

Log In
wpDiscuz