diff --git a/AdcFilter.c b/AdcFilter.c index c9ec4c7..4c95c22 100644 --- a/AdcFilter.c +++ b/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; @@ -100,240 +84,4 @@ 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 - -// Пример 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 \ No newline at end of file +} \ No newline at end of file diff --git a/AdcFilter.h b/AdcFilter.h index cfea4a0..0448020 100644 --- a/AdcFilter.h +++ b/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 +#endif //HVAC_M7_ADCFILTER_H \ No newline at end of file diff --git a/AdcTasks.c b/AdcTasks.c index 8ca0fa5..88fb5d1 100644 --- a/AdcTasks.c +++ b/AdcTasks.c @@ -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); } } }