Обновление
This commit is contained in:
parent
92c25d5ed4
commit
98e1e67bb4
288
AdcFilter.c
288
AdcFilter.c
|
|
@ -1,17 +1,13 @@
|
|||
//
|
||||
// Created by cfif on 08.05.2026.
|
||||
//
|
||||
#include "AdcFilter.h"
|
||||
#include "stdbool.h"
|
||||
#include "stddef.h"
|
||||
|
||||
bool ADC_Filter_Init(ADC_Filter* filter, uint8_t size) {
|
||||
if (filter == NULL || size == 0 || size > MAX_ADC_FILTER_SIZE) {
|
||||
if (filter == NULL || size > MAX_ADC_FILTER_SIZE) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Обнуляем буфер
|
||||
for (uint8_t i = 0; i < MAX_ADC_FILTER_SIZE; i++) {
|
||||
// Разрешаем size == 0 (фильтр отключён)
|
||||
for (uint8_t i = 0; i < ADC_BUFFER_SIZE; i++) {
|
||||
filter->buffer[i] = 0;
|
||||
}
|
||||
|
||||
|
|
@ -23,38 +19,33 @@ bool ADC_Filter_Init(ADC_Filter* filter, uint8_t size) {
|
|||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Сброс фильтра в начальное состояние
|
||||
*/
|
||||
void ADC_Filter_Reset(ADC_Filter* filter) {
|
||||
if (filter == NULL) return;
|
||||
|
||||
for (uint8_t i = 0; i < filter->size; i++) {
|
||||
for (uint8_t i = 0; i < ADC_BUFFER_SIZE; i++) {
|
||||
filter->buffer[i] = 0;
|
||||
}
|
||||
|
||||
filter->sum = 0;
|
||||
filter->index = 0;
|
||||
filter->count = 0;
|
||||
// размер не меняем
|
||||
}
|
||||
|
||||
/**
|
||||
* Обновление фильтра новым значением АЦП
|
||||
* @param filter указатель на фильтр
|
||||
* @param adc_value новое значение АЦП (0-65535)
|
||||
* @return отфильтрованное значение
|
||||
*/
|
||||
uint16_t ADC_Filter_Update(ADC_Filter* filter, uint16_t adc_value) {
|
||||
if (filter == NULL) return 0;
|
||||
|
||||
// Если фильтр отключён, возвращаем сырое значение
|
||||
if (filter->size == 0) {
|
||||
return adc_value;
|
||||
}
|
||||
|
||||
// Переходный период (буфер не заполнен)
|
||||
if (filter->count < filter->size) {
|
||||
filter->buffer[filter->index] = adc_value;
|
||||
filter->sum += adc_value;
|
||||
filter->count++;
|
||||
filter->index = (filter->index + 1) % filter->size;
|
||||
|
||||
// Целочисленное деление (округляем вниз)
|
||||
return (uint16_t)(filter->sum / filter->count);
|
||||
}
|
||||
|
||||
|
|
@ -64,32 +55,25 @@ uint16_t ADC_Filter_Update(ADC_Filter* filter, uint16_t adc_value) {
|
|||
filter->sum = filter->sum - old_value + adc_value;
|
||||
filter->index = (filter->index + 1) % filter->size;
|
||||
|
||||
// Деление с округлением для большей точности
|
||||
// (сумма + половина размера) / размер
|
||||
// Округление при делении
|
||||
return (uint16_t)((filter->sum + (filter->size >> 1)) / filter->size);
|
||||
}
|
||||
|
||||
/**
|
||||
* Получение текущего значения без обновления
|
||||
*/
|
||||
uint16_t ADC_Filter_GetCurrent(const ADC_Filter* filter) {
|
||||
if (filter == NULL || filter->count == 0) return 0;
|
||||
if (filter == NULL || filter->count == 0 || filter->size == 0) {
|
||||
return 0;
|
||||
}
|
||||
return (uint16_t)((filter->sum + (filter->count >> 1)) / filter->count);
|
||||
}
|
||||
|
||||
/**
|
||||
* Проверка, заполнен ли буфер полностью
|
||||
*/
|
||||
bool ADC_Filter_IsReady(const ADC_Filter* filter) {
|
||||
return (filter != NULL && filter->count == filter->size);
|
||||
return (filter != NULL && filter->size > 0 && filter->count == filter->size);
|
||||
}
|
||||
|
||||
/**
|
||||
* Получение дисперсии (отклонения от среднего)
|
||||
* Полезно для обнаружения шумов
|
||||
*/
|
||||
uint16_t ADC_Filter_GetVariance(const ADC_Filter* filter) {
|
||||
if (filter == NULL || filter->count == 0) return 0;
|
||||
if (filter == NULL || filter->count == 0 || filter->size == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint16_t mean = ADC_Filter_GetCurrent(filter);
|
||||
uint32_t variance_sum = 0;
|
||||
|
|
@ -101,239 +85,3 @@ uint16_t ADC_Filter_GetVariance(const ADC_Filter* filter) {
|
|||
|
||||
return (uint16_t)(variance_sum / filter->count);
|
||||
}
|
||||
|
||||
/* ========================================================
|
||||
* ОПТИМИЗИРОВАННАЯ ВЕРСИЯ (размер = степень двойки)
|
||||
* Быстрее, так как использует сдвиги вместо деления
|
||||
* ======================================================== */
|
||||
/*
|
||||
typedef struct {
|
||||
uint16_t buffer[16]; // максимальный размер 16
|
||||
uint32_t sum;
|
||||
uint8_t shift; // сдвиг для деления (log2 размера)
|
||||
uint8_t index;
|
||||
uint8_t count;
|
||||
} ADC_FilterFast;
|
||||
|
||||
// Инициализация (размер должен быть степенью двойки: 1,2,4,8,16)
|
||||
bool ADC_FastFilter_Init(ADC_FilterFast* filter, uint8_t size) {
|
||||
if (filter == NULL || size == 0 || size > 16) return false;
|
||||
|
||||
// Проверка, что размер является степенью двойки
|
||||
if ((size & (size - 1)) != 0) return false;
|
||||
|
||||
for (uint8_t i = 0; i < size; i++) {
|
||||
filter->buffer[i] = 0;
|
||||
}
|
||||
|
||||
filter->sum = 0;
|
||||
filter->shift = 0;
|
||||
filter->index = 0;
|
||||
filter->count = 0;
|
||||
|
||||
// Вычисляем сдвиг: log2(size)
|
||||
uint8_t temp = size;
|
||||
while (temp > 1) {
|
||||
temp >>= 1;
|
||||
filter->shift++;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Быстрое обновление (без деления, только сдвиги)
|
||||
uint16_t ADC_FastFilter_Update(ADC_FilterFast* filter, uint16_t adc_value) {
|
||||
if (filter == NULL) return 0;
|
||||
|
||||
uint8_t size = 1 << filter->shift;
|
||||
|
||||
if (filter->count < size) {
|
||||
filter->buffer[filter->index] = adc_value;
|
||||
filter->sum += adc_value;
|
||||
filter->count++;
|
||||
filter->index = (filter->index + 1) & (size - 1); // быстрый modulo
|
||||
return (uint16_t)(filter->sum / filter->count);
|
||||
}
|
||||
|
||||
uint16_t old_value = filter->buffer[filter->index];
|
||||
filter->buffer[filter->index] = adc_value;
|
||||
filter->sum = filter->sum - old_value + adc_value;
|
||||
filter->index = (filter->index + 1) & (size - 1);
|
||||
|
||||
// Быстрое деление через сдвиг
|
||||
return (uint16_t)(filter->sum >> filter->shift);
|
||||
}
|
||||
*/
|
||||
/* ========================================================
|
||||
* МЕДИАННЫЙ ФИЛЬТР (для подавления импульсных помех)
|
||||
* Полезен, когда есть выбросы АЦП
|
||||
* ======================================================== */
|
||||
/*
|
||||
typedef struct {
|
||||
uint16_t buffer[16];
|
||||
uint16_t sorted[16]; // отсортированная копия
|
||||
uint8_t size;
|
||||
uint8_t index;
|
||||
uint8_t count;
|
||||
} ADC_MedianFilter;
|
||||
|
||||
bool ADC_MedianFilter_Init(ADC_MedianFilter* filter, uint8_t size) {
|
||||
if (filter == NULL || size == 0 || size > 16) return false;
|
||||
|
||||
for (uint8_t i = 0; i < size; i++) {
|
||||
filter->buffer[i] = 0;
|
||||
filter->sorted[i] = 0;
|
||||
}
|
||||
|
||||
filter->size = size;
|
||||
filter->index = 0;
|
||||
filter->count = 0;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Простая сортировка вставками для маленького массива
|
||||
static void sort_uint16(uint16_t* arr, uint8_t n) {
|
||||
for (uint8_t i = 1; i < n; i++) {
|
||||
uint16_t key = arr[i];
|
||||
int8_t j = i - 1;
|
||||
|
||||
while (j >= 0 && arr[j] > key) {
|
||||
arr[j + 1] = arr[j];
|
||||
j--;
|
||||
}
|
||||
arr[j + 1] = key;
|
||||
}
|
||||
}
|
||||
|
||||
uint16_t ADC_MedianFilter_Update(ADC_MedianFilter* filter, uint16_t adc_value) {
|
||||
if (filter == NULL) return 0;
|
||||
|
||||
// Сохраняем новое значение
|
||||
filter->buffer[filter->index] = adc_value;
|
||||
filter->index = (filter->index + 1) % filter->size;
|
||||
|
||||
if (filter->count < filter->size) {
|
||||
filter->count++;
|
||||
}
|
||||
|
||||
// Копируем в сортированный массив
|
||||
for (uint8_t i = 0; i < filter->count; i++) {
|
||||
filter->sorted[i] = filter->buffer[i];
|
||||
}
|
||||
|
||||
// Сортируем
|
||||
sort_uint16(filter->sorted, filter->count);
|
||||
|
||||
// Возвращаем медиану
|
||||
return filter->sorted[filter->count / 2];
|
||||
}
|
||||
*/
|
||||
/* ========================================================
|
||||
* ПРИМЕРЫ ИСПОЛЬЗОВАНИЯ
|
||||
* ======================================================== */
|
||||
|
||||
#ifdef TEST_MAIN
|
||||
#include <stdio.h>
|
||||
|
||||
// Пример 1: Фильтрация зашумленного сигнала АЦП
|
||||
void example_basic_filter(void) {
|
||||
printf("=== Базовый фильтр АЦП (окно 8) ===\n");
|
||||
|
||||
ADC_Filter filter;
|
||||
ADC_Filter_Init(&filter, 8);
|
||||
|
||||
// Симулируем зашумленные показания АЦП (например, датчик температуры)
|
||||
uint16_t adc_values[] = {
|
||||
512, 515, 508, 1024, // выброс!
|
||||
510, 513, 509, 511, 507, 514, 508, 512
|
||||
};
|
||||
|
||||
for (int i = 0; i < 12; i++) {
|
||||
uint16_t filtered = ADC_Filter_Update(&filter, adc_values[i]);
|
||||
printf("ADC: %4u -> Фильтр: %4u", adc_values[i], filtered);
|
||||
|
||||
if (ADC_Filter_IsReady(&filter)) {
|
||||
printf(" (стабильно)");
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
|
||||
// Пример 2: Оптимизированный фильтр со сдвигами
|
||||
void example_fast_filter(void) {
|
||||
printf("\n=== Быстрый фильтр (окно 16) ===\n");
|
||||
|
||||
ADC_FilterFast filter;
|
||||
ADC_FastFilter_Init(&filter, 16);
|
||||
|
||||
// Генерируем тестовые данные
|
||||
for (int i = 0; i < 20; i++) {
|
||||
uint16_t adc = 2048 + (i * 10) + (rand() % 50); // тренд + шум
|
||||
uint16_t filtered = ADC_FastFilter_Update(&filter, adc);
|
||||
printf("ADC: %4u -> Фильтр: %4u\n", adc, filtered);
|
||||
}
|
||||
}
|
||||
|
||||
// Пример 3: Медианный фильтр для подавления выбросов
|
||||
void example_median_filter(void) {
|
||||
printf("\n=== Медианный фильтр (окно 5) ===\n");
|
||||
|
||||
ADC_MedianFilter filter;
|
||||
ADC_MedianFilter_Init(&filter, 5);
|
||||
|
||||
// Данные с сильными выбросами
|
||||
uint16_t adc_data[] = {
|
||||
500, 502, 498, 1000, // сильный выброс
|
||||
501, 503, 497, 2000, // ещё выброс
|
||||
502, 499, 501, 503
|
||||
};
|
||||
|
||||
for (int i = 0; i < 12; i++) {
|
||||
uint16_t filtered = ADC_MedianFilter_Update(&filter, adc_data[i]);
|
||||
printf("ADC: %4u -> Медиана: %4u\n", adc_data[i], filtered);
|
||||
}
|
||||
}
|
||||
|
||||
// Пример 4: Реальный сценарий - сглаживание АЦП для измерения температуры
|
||||
void example_temperature_sensor(void) {
|
||||
printf("\n=== Фильтрация температуры (NTC термистор) ===\n");
|
||||
|
||||
ADC_Filter temp_filter;
|
||||
ADC_Filter_Init(&temp_filter, 10);
|
||||
|
||||
// Симуляция 50 измерений температуры с шумом
|
||||
float base_temp = 25.0; // базовая температура
|
||||
|
||||
for (int i = 0; i < 50; i++) {
|
||||
// Симуляция АЦП (10 бит = 0-1023)
|
||||
// Предполагаем, что 512 = 25°C, 1 LSB = 0.1°C
|
||||
int adc_noise = (rand() % 100) - 50; // шум ±5 LSB
|
||||
uint16_t adc_raw = 512 + adc_noise;
|
||||
|
||||
if (i > 20 && i < 30) {
|
||||
adc_raw += 100; // резкое изменение температуры
|
||||
}
|
||||
|
||||
uint16_t adc_filtered = ADC_Filter_Update(&temp_filter, adc_raw);
|
||||
|
||||
// Конвертируем в температуру
|
||||
float temp_raw = 25.0 + (adc_raw - 512) * 0.1;
|
||||
float temp_filtered = 25.0 + (adc_filtered - 512) * 0.1;
|
||||
|
||||
if (i % 5 == 0 || (i > 20 && i < 30)) {
|
||||
printf("Измерение %2d: сырая=%.1f°C, фильтрованная=%.1f°C\n",
|
||||
i, temp_raw, temp_filtered);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int main(void) {
|
||||
example_basic_filter();
|
||||
example_fast_filter();
|
||||
example_median_filter();
|
||||
example_temperature_sensor();
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
33
AdcFilter.h
33
AdcFilter.h
|
|
@ -1,27 +1,34 @@
|
|||
//
|
||||
// Created by cfif on 08.05.2026.
|
||||
//
|
||||
|
||||
#ifndef HVAC_M7_ADCFILTER_H
|
||||
#define HVAC_M7_ADCFILTER_H
|
||||
|
||||
#include "stdint.h"
|
||||
#include "stdbool.h"
|
||||
|
||||
// Максимальный размер фильтра (измените под свои нужды)
|
||||
// Рекомендации: 4, 8, 16, 32 (степень двойки для оптимизации)
|
||||
#define MAX_ADC_FILTER_SIZE 16
|
||||
// Максимальный размер фильтра (может быть 0 для отключения)
|
||||
#ifndef MAX_ADC_FILTER_SIZE
|
||||
#define MAX_ADC_FILTER_SIZE 0
|
||||
#endif
|
||||
|
||||
// Если размер равен 0, используем буфер из 1 элемента (для избежания ошибок компиляции)
|
||||
#if MAX_ADC_FILTER_SIZE == 0
|
||||
#define ADC_BUFFER_SIZE 1
|
||||
#else
|
||||
#define ADC_BUFFER_SIZE MAX_ADC_FILTER_SIZE
|
||||
#endif
|
||||
|
||||
// Структура фильтра АЦП
|
||||
typedef struct {
|
||||
uint16_t buffer[MAX_ADC_FILTER_SIZE]; // кольцевой буфер
|
||||
uint32_t sum; // сумма элементов (32 бита достаточно)
|
||||
uint8_t size; // размер окна (<= MAX_ADC_FILTER_SIZE)
|
||||
uint8_t index; // текущий индекс
|
||||
uint8_t count; // количество накопленных данных
|
||||
uint16_t buffer[ADC_BUFFER_SIZE]; // кольцевой буфер
|
||||
uint32_t sum; // сумма элементов
|
||||
uint8_t size; // размер окна (0 – фильтр отключён)
|
||||
uint8_t index; // текущий индекс
|
||||
uint8_t count; // количество накопленных данных
|
||||
} ADC_Filter;
|
||||
|
||||
bool ADC_Filter_Init(ADC_Filter* filter, uint8_t size);
|
||||
uint16_t ADC_Filter_Update(ADC_Filter* filter, uint16_t adc_value);
|
||||
uint16_t ADC_Filter_GetCurrent(const ADC_Filter* filter);
|
||||
bool ADC_Filter_IsReady(const ADC_Filter* filter);
|
||||
uint16_t ADC_Filter_GetVariance(const ADC_Filter* filter);
|
||||
void ADC_Filter_Reset(ADC_Filter* filter);
|
||||
|
||||
#endif //HVAC_M7_ADCFILTER_H
|
||||
|
|
@ -555,7 +555,7 @@ static _Noreturn void Adc0_Thread(tAdc0Task *env) {
|
|||
++env->step;
|
||||
|
||||
if (env->step > MAX_ADC_FILTER_SIZE * 2) {
|
||||
SystemDelayMs(10);
|
||||
// SystemDelayMs(10);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -703,7 +703,7 @@ static _Noreturn void Adc1_Thread(tAdc1Task *env) {
|
|||
++env->step;
|
||||
|
||||
if (env->step > MAX_ADC_FILTER_SIZE * 2) {
|
||||
SystemDelayMs(10);
|
||||
// SystemDelayMs(10);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue