Обновление

This commit is contained in:
cfif 2026-06-18 15:13:32 +03:00
parent 92c25d5ed4
commit 98e1e67bb4
3 changed files with 42 additions and 287 deletions

View File

@ -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 <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
}

View File

@ -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

View File

@ -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);
}
}
}