Mục lục:

Trung bình đang chạy cho các dự án vi điều khiển của bạn: 6 bước
Trung bình đang chạy cho các dự án vi điều khiển của bạn: 6 bước

Video: Trung bình đang chạy cho các dự án vi điều khiển của bạn: 6 bước

Video: Trung bình đang chạy cho các dự án vi điều khiển của bạn: 6 bước
Video: Xé toạc không gian bằng MẮT của bạn | khanhtrungsi 2024, Tháng mười một
Anonim
Trung bình đang chạy cho các dự án vi điều khiển của bạn
Trung bình đang chạy cho các dự án vi điều khiển của bạn

Trong phần hướng dẫn này, tôi sẽ giải thích trung bình chạy là gì và tại sao bạn nên quan tâm đến nó, cũng như chỉ cho bạn cách thực hiện nó để đạt hiệu quả tính toán tối đa (đừng lo lắng về sự phức tạp, nó rất đơn giản để hiểu và tôi sẽ cung cấp một thư viện dễ sử dụng cho các dự án arduino của bạn:)

Trung bình chạy, còn thường được gọi là trung bình động, trung bình động hoặc trung bình chạy, là một thuật ngữ được sử dụng để mô tả giá trị trung bình của N giá trị cuối cùng trong chuỗi dữ liệu. Nó có thể được tính như mức trung bình bình thường hoặc bạn có thể sử dụng một thủ thuật để làm cho nó có tác động tối thiểu đến hiệu suất mã của bạn.

Bước 1: Trường hợp sử dụng: Làm mịn các phép đo ADC

Trường hợp sử dụng: Làm mịn các phép đo ADC
Trường hợp sử dụng: Làm mịn các phép đo ADC

Arduino có một ADC 10 bit khá tốt với rất ít nhiễu. Khi đo giá trị trên một cảm biến như chiết áp, điện trở quang hoặc các bộ phận có độ nhiễu cao khác, khó có thể tin rằng phép đo đó là chính xác.

Một giải pháp là thực hiện nhiều phép đo mỗi khi bạn muốn đọc cảm biến của mình và lấy giá trị trung bình. Trong một số trường hợp, đây là một giải pháp khả thi nhưng không phải lúc nào cũng vậy. Nếu bạn muốn đọc ADC 1000 lần mỗi giây, bạn sẽ phải 10 000 nếu bạn lấy trung bình 10 phép đo. Một sự lãng phí lớn về thời gian tính toán.

Giải pháp được đề xuất của tôi là thực hiện các phép đo 1000 lần một giây, cập nhật mức trung bình chạy mỗi lần và sử dụng nó làm giá trị hiện tại. Phương pháp này giới thiệu một số độ trễ nhưng làm giảm độ phức tạp tính toán của ứng dụng của bạn, mang lại cho bạn nhiều thời gian hơn để xử lý bổ sung.

Trong hình trên, tôi đã sử dụng trung bình chạy của 32 lần đo gần đây nhất. Bạn sẽ thấy rằng phương pháp này không chống thất bại 100% nhưng nó cải thiện độ chính xác đáng kể (nó không tệ hơn so với việc lấy trung bình 32 mẫu mỗi lần). Nếu bạn muốn tính trung bình 32 phép đo mỗi lần, điều đó sẽ mất hơn 0,25 ms trên Arduino UNO chỉ cho các phép đo!

Bước 2: Trường hợp sử dụng: Đo thành phần DC của tín hiệu micrô

Trường hợp sử dụng: Đo thành phần DC của tín hiệu micrô
Trường hợp sử dụng: Đo thành phần DC của tín hiệu micrô
Trường hợp sử dụng: Đo thành phần DC của tín hiệu micrô
Trường hợp sử dụng: Đo thành phần DC của tín hiệu micrô
Trường hợp sử dụng: Đo thành phần DC của tín hiệu micrô
Trường hợp sử dụng: Đo thành phần DC của tín hiệu micrô

Arduino có thể đo điện áp từ 0 đến Vcc (thường là 5 V). Tín hiệu âm thanh hoàn toàn là AC và nếu bạn muốn đo nó trên vi điều khiển, bạn phải thiên vị nó khoảng 1/2 Vcc. Trong một dự án Arduino UNO có nghĩa là khoảng 2,5 V (DC) + tín hiệu âm thanh (AC). Khi sử dụng nguồn cung cấp ADC 10 bit và 5 V, độ lệch 2,5 V nên đo bằng 512. Vì vậy, để có được giá trị AC của tín hiệu, 512 phải được trừ đi từ phép đo ADC và đó là nó, phải không?

Trong một thế giới lý tưởng, điều đó sẽ đúng. Thật không may, cuộc sống thực phức tạp hơn và sự sai lệch tín hiệu của chúng ta có xu hướng thay đổi. Rất phổ biến là tiếng ồn 50 Hz (60 Hz nếu bạn sống ở Hoa Kỳ) từ mạng điện. Thông thường, tất cả không phải là quá vấn đề nhưng thật tốt khi biết nó tồn tại. Vấn đề nhiều hơn là trôi tuyến tính từ quá trình gia nhiệt của các thành phần. Bạn cẩn thận đặt hiệu chỉnh bù DC khi bắt đầu và nó từ từ biến mất khi ứng dụng của bạn đang chạy.

Tôi sẽ minh họa vấn đề này bằng máy dò nhịp (nhạc). Bạn thiết lập loại bỏ thiên vị và nhịp điệu của bạn rõ ràng (hình 2). Sau một thời gian, các chuyển động và nhịp đập thiên vị DC hầu như không nhận thấy được đối với bộ vi điều khiển (hình 3). Thuật toán phát hiện nhịp sẽ được khám phá chuyên sâu trong một tương lai có thể hướng dẫn vì nó vượt quá phạm vi của bài viết này.

May mắn thay, có một cách để liên tục tính toán bù DC của âm thanh. Sẽ không có gì ngạc nhiên khi trung bình chạy, chủ đề của hướng dẫn này, cung cấp một giải pháp.

Chúng ta biết rằng giá trị trung bình của bất kỳ tín hiệu AC nào là 0. Sử dụng kiến thức này, chúng ta có thể suy ra giá trị trung bình của tín hiệu AC + DC đó là độ lệch DC. Để loại bỏ nó, chúng tôi có thể lấy giá trị trung bình đang hoạt động của một vài giá trị cuối cùng và trừ nó khỏi việc đọc ADC hiện tại. Lưu ý rằng bạn cần sử dụng mức trung bình chạy đủ dài. Đối với âm thanh, một phần mười giây (số lượng mẫu phụ thuộc vào tốc độ lấy mẫu của bạn) là đủ nhưng hãy biết rằng trung bình dài hơn hoạt động tốt hơn. Trong hình đầu tiên, bạn có thể thấy ví dụ về tính toán thiên vị DC thực với mức trung bình chạy với 64 phần tử ở tốc độ mẫu 1 kHz (ít hơn tôi khuyến nghị nhưng nó vẫn hoạt động).

Bước 3: Tính toán

Phép tính
Phép tính

Bạn có thể tưởng tượng trung bình chạy là trọng lượng trung bình của những người trong phòng chờ của bác sĩ. Bác sĩ khám xong cho một bệnh nhân và đồng thời một người mới bước vào phòng chờ.

Để biết cân nặng trung bình của tất cả các bệnh nhân đang chờ trong phòng chờ, sau đó y tá có thể hỏi từng bệnh nhân về cân nặng của họ, cộng các số đó lên và chia cho số bệnh nhân. Mỗi khi bác sĩ tiếp nhận bệnh nhân mới, y tá sẽ lặp lại toàn bộ quy trình.

Bạn có thể nghĩ: "Điều này nghe có vẻ không quá hiệu quả … Phải có một cách tốt hơn để làm điều này." Và bạn sẽ chính xác.

Để tối ưu hóa quy trình này, y tá có thể ghi lại tổng trọng lượng của nhóm bệnh nhân hiện tại. Một khi bác sĩ gọi bệnh nhân mới đến, y tá sẽ hỏi anh ta về cân nặng của anh ta và trừ nó ra khỏi tổng số nhóm và để anh ta đi. Sau đó, y tá sẽ hỏi bệnh nhân vừa bước vào phòng chờ về cân nặng của anh ta và cộng vào tổng số. Cân nặng trung bình của bệnh nhân sau mỗi ca sẽ là tổng trọng lượng chia cho số bệnh nhân (vâng, giống như trước đây nhưng bây giờ y tá chỉ hỏi hai người về cân nặng của họ thay vì tất cả họ). Tôi nhận thấy đoạn này có thể hơi khó hiểu vì vậy vui lòng xem hình minh họa ở trên để rõ hơn (hoặc đặt câu hỏi trong phần bình luận).

Nhưng ngay cả khi bạn không tìm thấy đoạn cuối cùng khiến bạn khó hiểu, bạn có thể có những câu hỏi như những gì nên có trong bộ tích lũy ngay từ đầu, làm cách nào để đặt những gì tôi vừa đọc vào một mã C thực sự? Điều đó sẽ được giải quyết trong bước tiếp theo, nơi bạn cũng sẽ nhận được mã nguồn của tôi.

Bước 4: Mã

Mật mã
Mật mã

Để tính toán trung bình chạy, trước tiên bạn cần một cách để lưu trữ N giá trị cuối cùng. bạn có thể có một mảng với N phần tử và di chuyển toàn bộ nội dung vào một nơi mỗi khi bạn thêm một phần tử (vui lòng không làm điều này), hoặc bạn có thể ghi đè một phần tử cũ và điều chỉnh con trỏ đến phần tử tiếp theo bị loại bỏ (vui lòng làm điều này:)

Bộ tích lũy sẽ bắt đầu được khởi tạo thành 0, tương tự với tất cả các phần tử trong dòng trễ. Trong trường hợp khác, đường trung bình của bạn sẽ luôn sai. Bạn sẽ thấy delayLine_init đảm nhận việc khởi tạo dòng trễ, bạn nên tự lo cho bộ tích lũy.

thêm một phần tử vào dòng trễ cũng dễ dàng như giảm chỉ số của phần tử mới nhất đi 1, đảm bảo phần tử đó không chỉ ra bên ngoài của mảng dòng trễ. sau khi giảm chỉ số khi nó bằng 0, nó sẽ lặp lại thành 255 (vì nó là một số nguyên 8 bit không dấu). Toán tử modulo (%) với kích thước của mảng dòng trễ sẽ đảm bảo chỉ mục sẽ trỏ đến một phần tử hợp lệ.

Việc tính toán mức trung bình chạy sẽ dễ hiểu nếu bạn làm theo phép loại suy của tôi ở bước trước. Trừ phần tử cũ nhất khỏi bộ tích lũy, thêm giá trị mới nhất vào bộ tích lũy, đẩy giá trị mới nhất vào dòng trễ, trả về bộ tích lũy chia cho số phần tử.

Dễ dàng, phải không?

Vui lòng thử nghiệm bằng cách sử dụng mã đính kèm để hiểu rõ hơn về cách hoạt động của tất cả những điều này. Như hiện tại, arduino đọc giá trị tương tự trên chân tương tự A0 và in "[giá trị ADC], [trung bình chạy]" trên cổng nối tiếp ở tốc độ 115200 baud. Nếu bạn mở máy vẽ nối tiếp của arduino trên tốc độ truyền chính xác, bạn sẽ thấy hai dòng: giá trị ADC (màu xanh) và giá trị được làm mịn (màu đỏ).

Bước 5: Bổ sung

Bổ sung
Bổ sung

Có một số điều mà bạn không nhất thiết phải biết để sử dụng trung bình chạy trong dự án của bạn.

trì hoãn: Tôi sẽ bắt đầu với việc nói về minh họa của bước này. Bạn sẽ nhận thấy rằng trung bình chạy của nhiều phần tử hơn dẫn đến độ trễ lớn hơn. Nếu thời gian phản hồi của bạn để thay đổi giá trị là rất quan trọng, bạn có thể muốn sử dụng trung bình chạy ngắn hơn hoặc tăng tốc độ lấy mẫu (đo thường xuyên hơn).

Tiếp tục.

khởi tạo: Khi tôi nói về việc khởi tạo các phần tử tích lũy và trì hoãn, tôi đã nói bạn nên khởi tạo tất cả chúng bằng 0. Ngoài ra, bạn có thể khởi tạo dòng trễ thành bất kỳ thứ gì bạn thích nhưng bộ tích lũy phải bắt đầu dưới dạng tổng N phần tử mới nhất trong dòng trễ (trong đó N là số phần tử trong trung bình hoạt động của bạn). Nếu bộ tích lũy bắt đầu bằng bất kỳ giá trị nào khác, giá trị trung bình được tính toán sẽ sai - quá thấp hoặc quá cao, luôn bằng cùng một số tiền (giả sử cùng một điều kiện ban đầu). Tôi khuyên bạn nên thử tìm hiểu lý do tại sao lại như vậy bằng cách sử dụng một số "mô phỏng bút và giấy".

kích thước bộ tích lũy: Bạn cũng nên lưu ý rằng bộ tích lũy phải đủ lớn để lưu trữ tổng của tất cả các phần tử trong dòng trễ nếu tất cả chúng đều là cực đại dương hoặc âm. Trên thực tế, điều đó có nghĩa là bộ tích lũy phải là một kiểu dữ liệu lớn hơn các phần tử dòng trễ và được ký, nếu các phần tử dòng trễ được ký.

mẹo: Các đường trễ dài sẽ chiếm nhiều bộ nhớ. Điều đó có thể nhanh chóng trở thành một vấn đề. Nếu bạn rất hạn chế bộ nhớ và không quan tâm nhiều đến độ chính xác, bạn có thể ước tính trung bình chạy bằng cách bỏ qua hoàn toàn độ trễ và thay vào đó làm điều này: trừ bộ tích lũy 1 / N * khỏi bộ tích lũy và thêm giá trị mới (ví dụ: 8 trung bình chạy dài: Tích lũy = Tích lũy * 7/8 + Giá trị mới). Phương pháp này cho kết quả sai nhưng nó là một phương pháp tốt để tính toán trung bình chạy khi bạn sắp hết bộ nhớ.

ngôn ngữ học: "trung bình chạy / trung bình" thường được sử dụng khi đề cập đến tính trung bình theo thời gian thực trong khi "trung bình động / trung bình" thường có nghĩa là thuật toán đang chạy trên tập dữ liệu tĩnh, chẳng hạn như bảng tính excel.

Bước 6: Kết luận

Tôi hy vọng hướng dẫn này đủ dễ hiểu và nó sẽ giúp ích cho bạn trong các dự án tương lai của bạn. Vui lòng gửi câu hỏi trong phần bình luận bên dưới nếu có bất kỳ điều gì chưa rõ ràng.

Đề xuất: