Như những người khác đã đề cập, bạn nên xem xét bộ lọc IIR (phản hồi xung vô hạn) thay vì bộ lọc FIR (phản hồi xung hữu hạn) mà bạn hiện đang sử dụng. Có nhiều hơn thế, nhưng thoạt nhìn, các bộ lọc FIR được triển khai dưới dạng kết hợp rõ ràng và bộ lọc IIR với các phương trình.
Bộ lọc IIR cụ thể tôi sử dụng rất nhiều trong vi điều khiển là bộ lọc thông thấp cực đơn. Đây là tương đương kỹ thuật số của một bộ lọc tương tự RC đơn giản. Đối với hầu hết các ứng dụng, chúng sẽ có các đặc tính tốt hơn bộ lọc hộp mà bạn đang sử dụng. Hầu hết việc sử dụng bộ lọc hộp mà tôi gặp phải là kết quả của việc ai đó không chú ý đến lớp xử lý tín hiệu số, không phải do cần các đặc điểm cụ thể của chúng. Nếu bạn chỉ muốn giảm tần số cao mà bạn biết là nhiễu, bộ lọc thông thấp cực đơn sẽ tốt hơn. Cách tốt nhất để thực hiện một kỹ thuật số trong vi điều khiển thường là:
PHIM <- PHIM + FF (MỚI - PHIM)
LỌC là một phần của trạng thái bền bỉ. Đây là biến duy nhất liên tục bạn cần để tính toán bộ lọc này. MỚI là giá trị mới mà bộ lọc đang được cập nhật với lần lặp này. FF là phần lọc , điều chỉnh "độ nặng" của bộ lọc. Nhìn vào thuật toán này và thấy rằng với FF = 0, bộ lọc cực kỳ nặng vì đầu ra không bao giờ thay đổi. Với FF = 1, thực sự không có bộ lọc nào vì đầu ra chỉ theo đầu vào. Các giá trị hữu ích nằm ở giữa. Trên các hệ thống nhỏ, bạn chọn FF là 1/2 Nsao cho nhân với FF có thể được thực hiện như một sự dịch chuyển đúng bởi N bit. Ví dụ, FF có thể là 1/16 và nhân với FF do đó dịch chuyển đúng 4 bit. Mặt khác, bộ lọc này chỉ cần một phép trừ và một phép cộng, mặc dù các số thường cần rộng hơn giá trị đầu vào (nhiều hơn về độ chính xác số trong một phần riêng biệt bên dưới).
Tôi thường thực hiện các bài đọc A / D nhanh hơn đáng kể so với mức cần thiết và áp dụng hai trong số các bộ lọc này xếp tầng. Đây là tương đương kỹ thuật số của hai bộ lọc RC nối tiếp và suy giảm 12 dB / quãng tám trên tần số rolloff. Tuy nhiên, đối với các lần đọc A / D, thường phải xem xét bộ lọc trong miền thời gian bằng cách xem xét phản hồi bước của nó. Điều này cho bạn biết hệ thống của bạn sẽ thấy sự thay đổi nhanh như thế nào khi thứ bạn đang đo thay đổi.
Để thuận tiện cho việc thiết kế các bộ lọc này (điều này chỉ có nghĩa là chọn FF và quyết định số lượng chúng trong số các tầng đó), tôi sử dụng chương trình FILTBITS của chương trình. Bạn chỉ định số lượng bit thay đổi cho mỗi FF trong chuỗi bộ lọc xếp tầng và nó tính toán phản hồi bước và các giá trị khác. Trên thực tế, tôi thường chạy nó thông qua kịch bản trình bao bọc PLOTFILT. Điều này chạy FILTBITS, tạo một tệp CSV, sau đó vẽ tệp CSV. Ví dụ: đây là kết quả của "PLOTFILT 4 4":
Hai tham số cho PLOTFILT có nghĩa là sẽ có hai bộ lọc xếp tầng được mô tả ở trên. Các giá trị của 4 chỉ ra số bit dịch chuyển để nhận ra bội số của FF. Do đó, hai giá trị FF là 1/16 trong trường hợp này.
Dấu vết màu đỏ là phản ứng bước đơn vị, và là điều chính để xem xét. Ví dụ, điều này cho bạn biết rằng nếu đầu vào thay đổi tức thời, đầu ra của bộ lọc kết hợp sẽ giải quyết đến 90% giá trị mới trong 60 lần lặp. Nếu bạn quan tâm đến thời gian giải quyết 95% thì bạn phải chờ khoảng 73 lần lặp và trong 50% thời gian giải quyết chỉ có 26 lần lặp.
Dấu vết màu xanh lá cây cho bạn thấy đầu ra từ một đột biến biên độ đầy đủ duy nhất. Điều này cung cấp cho bạn một số ý tưởng về việc khử nhiễu ngẫu nhiên. Có vẻ như không có mẫu đơn nào sẽ gây ra thay đổi nhiều hơn 2,5% trong đầu ra.
Dấu vết màu xanh là mang lại cảm giác chủ quan về những gì bộ lọc này làm với nhiễu trắng. Đây không phải là một bài kiểm tra nghiêm ngặt vì không có gì đảm bảo chính xác nội dung của các số ngẫu nhiên được chọn làm đầu vào tiếng ồn trắng cho lần chạy PLOTFILT này. Nó chỉ mang đến cho bạn cảm giác thô ráp về việc nó sẽ bị nghiền nát và mịn như thế nào.
PLOTFILT, có thể là PHIM, và nhiều nội dung hữu ích khác, đặc biệt là để phát triển phần mềm PIC có sẵn trong bản phát hành phần mềm PIC Development Tools tại trang tải xuống Phần mềm của tôi .
Đã thêm về độ chính xác số
Tôi thấy từ các ý kiến và bây giờ một câu trả lời mới rằng có sự quan tâm trong việc thảo luận về số lượng bit cần thiết để thực hiện bộ lọc này. Lưu ý rằng nhân với FF sẽ tạo ra các bit mới Log 2 (FF) bên dưới điểm nhị phân. Trên các hệ thống nhỏ, FF thường được chọn là 1/2 N để số nhân này thực sự được nhận ra bằng một sự dịch chuyển phải của N bit.
Do đó, FILT thường là một số nguyên điểm cố định. Lưu ý rằng điều này không thay đổi bất kỳ phép toán nào theo quan điểm của bộ xử lý. Ví dụ: nếu bạn đang lọc các số đọc A / D 10 bit và N = 4 (FF = 1/16), thì bạn cần 4 bit phân số dưới số đọc A / D số nguyên 10 bit. Hầu hết các bộ xử lý, bạn sẽ thực hiện các hoạt động số nguyên 16 bit do các lần đọc A / D 10 bit. Trong trường hợp này, bạn vẫn có thể thực hiện chính xác các phép toán số nguyên 16 bit giống nhau, nhưng bắt đầu với số đọc A / D được dịch chuyển trái 4 bit. Bộ xử lý không biết sự khác biệt và không cần. Làm toán trên toàn bộ số nguyên 16 bit hoạt động cho dù bạn coi chúng là 12,4 điểm cố định hay số nguyên 16 bit thực (điểm cố định 16,0).
Nói chung, bạn cần thêm N bit cho mỗi cực của bộ lọc nếu bạn không muốn thêm nhiễu do biểu diễn bằng số. Trong ví dụ trên, bộ lọc thứ hai của hai sẽ phải có 10 + 4 + 4 = 18 bit để không bị mất thông tin. Trong thực tế trên máy 8 bit có nghĩa là bạn sử dụng các giá trị 24 bit. Về mặt kỹ thuật, chỉ có cực thứ hai của hai sẽ cần giá trị rộng hơn, nhưng để đơn giản phần sụn, tôi thường sử dụng cùng một biểu diễn, và do đó cùng một mã, cho tất cả các cực của bộ lọc.
Thông thường tôi viết một chương trình con hoặc macro để thực hiện một thao tác cực bộ lọc, sau đó áp dụng điều đó cho mỗi cực. Việc một chương trình con hay macro phụ thuộc vào việc chu kỳ hoặc bộ nhớ chương trình là quan trọng hơn trong dự án cụ thể đó. Dù bằng cách nào, tôi sử dụng một số trạng thái cào để chuyển MỚI vào chương trình con / macro, cập nhật FILT, nhưng cũng tải trạng thái đó vào cùng trạng thái cào MỚI. Điều này giúp dễ dàng áp dụng nhiều cực kể từ khi PHẢI cập nhật một cực MỚI của cái tiếp theo. Khi một chương trình con, thật hữu ích khi có một con trỏ trỏ tới LỌC trên đường vào, được cập nhật ngay sau khi LỌC trên đường ra. Bằng cách đó, chương trình con tự động hoạt động trên các bộ lọc liên tiếp trong bộ nhớ nếu được gọi nhiều lần. Với một macro bạn không cần một con trỏ vì bạn chuyển địa chỉ để hoạt động trên mỗi lần lặp.
Mã ví dụ
Dưới đây là ví dụ về macro như được mô tả ở trên cho PIC 18:
///////////////////////////////////////////////////// /////////////////////////////////
//
// Bộ lọc Macro LỌC
//
// Cập nhật một cực bộ lọc với giá trị mới trong NEWVAL. NEWVAL được cập nhật thành
// chứa giá trị được lọc mới.
//
// FILT là tên của biến trạng thái bộ lọc. Nó được giả định là 24 bit
// rộng và trong ngân hàng địa phương.
//
// Công thức cập nhật bộ lọc là:
//
// PHIM <- PHIM + FF (NEWVAL - PHIM)
//
// Nhân với FF được thực hiện bằng một sự dịch chuyển đúng của các bit FILTBITS.
//
/ bộ lọc macro
/ viết
ngân hàng lbankadr
Movf [arg 1] +0, w; NEWVAL <- NEWVAL - PHIM
subwf newval + 0
Movf [arg 1] +1, w
subwfb newval + 1
Movf [arg 1] +2, w
subwfb newval + 2
/ viết
/ loop n bộ lọc; một lần cho mỗi bit để dịch chuyển NEWVAL sang phải
rlcf newval + 2, w; thay đổi NEWVAL ngay một bit
rrcf newval + 2
rrcf newval + 1
rrcf newval + 0
/ endloop
/ viết
Movf newval + 0, w; thêm giá trị đã dịch chuyển vào bộ lọc và lưu trong NEWVAL
addwf [arg 1] +0, w
Movwf [arg 1] +0
Movwf newval + 0
Movf newval + 1, w
addwfc [arg 1] +1, w
Movwf [arg 1] +1
Movwf newval + 1
Movf newval + 2, w
addwfc [arg 1] +2, w
Movwf [arg 1] +2
Movwf newval + 2
/ endmac
Và đây là một macro tương tự cho PIC 24 hoặc DSPIC 30 hoặc 33:
///////////////////////////////////////////////////// /////////////////////////////////
//
// Ffbits Macro LỌC
//
// Cập nhật trạng thái của một bộ lọc thông thấp. Giá trị đầu vào mới nằm trong W1: W0
// và trạng thái bộ lọc được cập nhật được trỏ đến bởi W2.
//
// Giá trị bộ lọc được cập nhật cũng sẽ được trả về trong W1: W0 và W2 sẽ trỏ
// đến bộ nhớ đầu tiên qua trạng thái bộ lọc. Macro này do đó có thể là
// được gọi liên tiếp để cập nhật một loạt các bộ lọc thông thấp xếp tầng.
//
// Công thức lọc là:
//
// PHIM <- PHIM + FF (MỚI - PHIM)
//
// trong đó phép nhân với FF được thực hiện bởi sự dịch chuyển phải của số học của
// FFBITS.
//
// CẢNH BÁO: W3 bị vứt đi.
//
/ bộ lọc macro
/ var new ffbits số nguyên = [arg 1]; lấy số bit để dịch chuyển
/ viết
/ write "; Thực hiện lọc một cực thông thấp, shift bit =" ffbits
/ viết ";"
phụ w0, [w2 ++], w0; MỚI - PHIM -> W1: W0
phụ w1, [w2--], w1
lsr w0, # [v ffbits], w0; dịch chuyển kết quả trong W1: W0 sang phải
sl w1, # [- 16 khung hình], w3
ior w0, w3, w0
asr w1, # [v ffbits], w1
thêm w0, [w2 ++], w0; thêm PHIM để tạo kết quả cuối cùng trong W1: W0
addc w1, [w2--], w1
Mov w0, [w2 ++]; ghi kết quả vào trạng thái bộ lọc, con trỏ trước
Mov w1, [w2 ++]
/ viết
/ endmac
Cả hai ví dụ này đều được triển khai dưới dạng macro sử dụng bộ tiền xử lý trình biên dịch PIC của tôi , có khả năng cao hơn cả các tiện ích macro tích hợp.