/**
******************************************************************************
* @file    filters.c
* @brief   Реализация библиотеки фильтров
******************************************************************************
*/
#include "filters.h"

#ifdef FILTERS_ENABLE


#define check_init_filter(_filter_) \
do{   if (filter == NULL) return -1;   \
      filter->state = FILTER_NOT_INIT;}while(0);

#define check_process_filter(_filter_) \
do{   if ((filter == NULL) || (filter->state != FILTER_ENABLE)) return input;}while(0);

// ==================== FLOAT ВЕРСИИ ====================

// Вспомогательная функция для сравнения float
static int Filter_float_compare(const void *a, const void *b) {
    float fa = *(const float*)a;
    float fb = *(const float*)b;
    if (fa < fb) return -1;
    if (fa > fb) return 1;
    return 0;
}

/**
  * @brief Инициализация медианного фильтра (float)
  * @param filter Указатель на структуру фильтра
  * @return 0 - успех, -1 - ошибка
  */
int FilterMedian_Init(FilterMedian_t* filter, uint8_t size, float init_val) {
  check_init_filter(filter);
  if (size == 0 || size > FILTER_MEDIAN_MAX_SIZE) return -1;
  
  for (int i = 0; i < size; i++)
  {
    filter->buffer[i] = init_val;
  }
  filter->index = 0;
  filter->size = size;
  
  filter->state = FILTER_READY;
  filter->reset   = &FilterMedian_Init;
  filter->process = &FilterMedian_Process;
  return 0;
}

/**
  * @brief Обработка значения медианным фильтром (float)
  * @param filter Указатель на структуру фильтра
  * @param input Входное значение
  * @return Отфильтрованное значение
  */
float FilterMedian_Process(FilterMedian_t* filter, float input) {
  check_process_filter(filter);
  
  // Добавляем значение в буфер
  filter->buffer[filter->index] = input;
  filter->index = (filter->index + 1) % filter->size;
  
  // Копируем буфер для сортировки
  float sort_buffer[FILTER_MEDIAN_MAX_SIZE];
  memcpy(sort_buffer, filter->buffer, sizeof(sort_buffer));
  
  // Сортируем и возвращаем медиану
  qsort(sort_buffer, filter->size, sizeof(float), Filter_float_compare);
  return sort_buffer[filter->size / 2];
}

/**
  * @brief Инициализация экспоненциального фильтра (float)
  * @param filter Указатель на структуру фильтра
  * @param alpha Коэффициент сглаживания (0..1)
  * @return 0 - успех, -1 - ошибка
  */
int FilterExp_Init(FilterExp_t* filter, float alpha) {
  check_init_filter(filter);
  
  filter->alpha = alpha;
  filter->value = 0.0f;
  filter->initialized = 0;
  
  filter->state = FILTER_READY;
  filter->reset   = &FilterExp_Init;
  filter->process = &FilterExp_Process;
  return 0;
}

/**
  * @brief Обработка значения экспоненциальным фильтром (float)
  * @param filter Указатель на структуру фильтра
  * @param input Входное значение
  * @return Отфильтрованное значение
  */
float FilterExp_Process(FilterExp_t* filter, float input) {
  check_process_filter(filter);
  
  if (!filter->initialized) {
      filter->value = input;
      filter->initialized = 1;
      return input;
  }
  
  filter->value = filter->alpha * input + (1.0f - filter->alpha) * filter->value;
  return filter->value;
}

/**
  * @brief Инициализация фильтра скользящего среднего (float)
  * @param filter Указатель на структуру фильтра
  * @return 0 - успех, -1 - ошибка
  */
int FilterAverage_Init(FilterAverage_t* filter, uint32_t size, FilterMode_t mode) {
  check_init_filter(filter);
  if (size == 0 || size > FILTER_AVERAGE_MAX_SIZE) return -1;
  
#ifndef FILTERS_DISABLE_MOVING_AVERAGE
  memset(filter->buffer, 0, sizeof(filter->buffer));
#endif
  filter->size = size;
  filter->sum = 0.0f;
  filter->index = 0;
  filter->count = 0;
  filter->mode = mode;
  
  filter->state = FILTER_READY;
  filter->reset   = &FilterAverage_Init;
  filter->process = &FilterAverage_Process;
  return 0;
}

/**
  * @brief Обработка значения фильтром скользящего среднего (float)
  * @param filter Указатель на структуру фильтра
  * @param input Входное значение
  * @return Отфильтрованное значение
  */
float FilterAverage_Process(FilterAverage_t* filter, float input) {
  check_process_filter(filter);
  
  // Общая логика для обоих режимов
  filter->sum += input;
  filter->count++;
  filter->dataProcessing = 1;
  // Логика скользящего среднего
  if (filter->mode == FILTER_MODE_MOVING) {
#ifndef FILTERS_DISABLE_MOVING_AVERAGE
    if (filter->count > filter->size) {
      filter->sum -= filter->buffer[filter->index];
      filter->count = filter->size; // Поддерживаем фиксированный размер окна
    }
    filter->buffer[filter->index] = input;
    filter->index = (filter->index + 1) % filter->size;
    filter->lastValue = filter->sum / filter->count;
    filter->dataProcessing = 0;
#endif
  }
  else
  {
    if (filter->count >= filter->size)
    {
      filter->lastValue = filter->sum / filter->count;
      filter->count = 0;
      filter->sum = 0;
      filter->dataProcessing = 0;
    }
  }
  
  return filter->lastValue;  
}

/**
  * @brief Инициализация полиномиальной коррекции (float)
  * @param filter Указатель на структуру коррекции
  * @param coeffs Массив коэффициентов полинома
  * @param order Порядок полинома
  * @return 0 - успех, -1 - ошибка
  */
int FilterPoly_Init(FilterPoly_t* filter, float* coeffs, uint8_t order) {
  check_init_filter(filter);
  if ((coeffs == NULL) || (order > FILTER_POLY_MAX_ORDER)) return -1;
  
  filter->order = order;
  memcpy(filter->coefficients, coeffs, (order + 1) * sizeof(float));
  
  filter->state = FILTER_READY;
  filter->reset   = &FilterPoly_Init;
  filter->process = &FilterPoly_Process;
  return 0;
}

/**
  * @brief Применение полиномиальной коррекции к значению (float)
  * @param filter Указатель на структуру коррекции
  * @param input Входное значение
  * @return Скорректированное значение
  */
float FilterPoly_Process(FilterPoly_t* filter, float input) {
  check_process_filter(filter);
  
  float result = 0.0f;
  float x_power = 1.0f;
  
  for (uint8_t i = 0; i <= filter->order; i++) {
    result += filter->coefficients[i] * x_power;
    x_power *= input;
  }
  
  return result;
}

/**
  * @brief Инициализация табличного фильтра (float)
  * @param filter Указатель на структуру фильтра
  * @param input_arr Массив входных значений (должен быть отсортирован по возрастанию)
  * @param output_arr Массив выходных значений
  * @param size Размер таблицы
  * @param interpolation Флаг интерполяции (0 - ближайшее значение, 1 - линейная интерполяция)
  * @return 0 - успех, -1 - ошибка
  */
int FilterLUT_Init(FilterLUT_t* filter, float* input_arr, float* output_arr, uint16_t size, uint8_t interpolation) {
  check_init_filter(filter);
  if ((input_arr == NULL) || (output_arr == NULL)) return -1;
  
  filter->input_values = input_arr;
  filter->output_values = output_arr;
  filter->size = size;
  filter->interpolation = interpolation;
  
  filter->state = FILTER_READY;
  filter->reset   = &FilterLUT_Init;
  filter->process = &FilterLUT_Process;
  return 0;
}

/**
  * @brief Обработка значения табличным фильтром (float)
  * @param filter Указатель на структуру фильтра
  * @param input Входное значение
  * @return Выходное значение по таблице
  */
float FilterLUT_Process(FilterLUT_t* filter, float input) {
  check_process_filter(filter);
  if((filter->input_values == NULL) || (filter->output_values == NULL)) {
    return input;
  }
  
  // Поиск ближайших значений в таблице
  uint16_t left_index = 0;
  uint16_t right_index = filter->size - 1;
  
  // Если значение за пределами таблицы - возвращаем крайние значения
  if (input <= filter->input_values[0]) {
    return filter->output_values[0];
  }
  if (input >= filter->input_values[right_index]) {
    return filter->output_values[right_index];
  }
  
  // Бинарный поиск позиции
  while (right_index - left_index > 1) {
    uint16_t mid_index = left_index + (right_index - left_index) / 2;
    if (input <= filter->input_values[mid_index]) {
      right_index = mid_index;
    } else {
      left_index = mid_index;
    }
  }
  
  // Без интерполяции - возвращаем значение левой границы
  if (!filter->interpolation) {
    return filter->output_values[left_index];
  }
  
  // Линейная интерполяция
  float x0 = filter->input_values[left_index];
  float x1 = filter->input_values[right_index];
  float y0 = filter->output_values[left_index];
  float y1 = filter->output_values[right_index];
  
  if (x1 == x0) {
    return y0; // Избегаем деления на ноль
  }
  
  return y0 + (input - x0) * (y1 - y0) / (x1 - x0);
}

/**
  * @brief Инициализация RMS фильтра (float)
  */
int FilterRMS_Init(FilterRMS_t* filter, uint32_t window_size) {
  check_init_filter(filter);
  
  if (window_size == 0 || window_size > FILTER_RMS_MAX_SIZE) return -1;
  
  filter->window_size = window_size;
  filter->sum_squares = 0.0f;
  filter->last_rms = 0.0f;
  filter->index = 0;
  filter->count = 0;
  
  // Инициализируем буфер нулями
  memset(filter->buffer_sq, 0, sizeof(filter->buffer_sq[0]) * window_size);
  
  filter->state = FILTER_READY;
  filter->reset   = &FilterRMS_Init;
  filter->process = &FilterRMS_Process;
  return 0;
}

/**
  * @brief Обработка значения RMS фильтром (float)
  * @details Эффективный алгоритм с циклическим буфером
  */
float FilterRMS_Process(FilterRMS_t* filter, float input) {
  check_process_filter(filter);
  
  // Вычисляем квадрат входного значения
  float square = input * input;
  
  if (filter->count < filter->window_size) {
    // Фаза накопления - просто добавляем в сумму
    filter->sum_squares += square;
    filter->buffer_sq[filter->index] = square;
    filter->count++;
  } else {
    // Фаза скользящего окна - вычитаем старое, добавляем новое
    filter->sum_squares -= filter->buffer_sq[filter->index]; // Вычитаем старое значение
    filter->sum_squares += square;                          // Добавляем новое
    filter->buffer_sq[filter->index] = square;              // Сохраняем в буфер
  }
  
  // Увеличиваем индекс с зацикливанием
  filter->index++;
  if (filter->index >= filter->window_size) {
    filter->index = 0;
  }
  
  // Вычисляем RMS (проверяем что есть хотя бы одно значение)
  if (filter->count > 0) {
    float mean_square = filter->sum_squares / filter->count;
    // Защита от отрицательных значений из-за ошибок округления
    if (mean_square < 0.0f) mean_square = 0.0f;
    filter->last_rms = _sqrtf(mean_square);
  }
  
  return filter->last_rms;
}


// ==================== INT32_T ВЕРСИИ ====================

// Вспомогательная функция для сравнения int32_t
static int Filter_int32_compare(const void *a, const void *b) {
  int32_t ia = *(const int32_t*)a;
  int32_t ib = *(const int32_t*)b;
  if (ia < ib) return -1;
  if (ia > ib) return 1;
  return 0;
}

/**
  * @brief Инициализация медианного фильтра (int32_t)
  * @param filter Указатель на структуру фильтра
  * @return 0 - успех, -1 - ошибка
  */
int FilterMedianInt_Init(FilterMedianInt_t* filter, uint8_t size, int32_t init_val) {
  check_init_filter(filter);
  if (size == 0 || size > FILTER_MEDIAN_MAX_SIZE) return -1;
  
  for (int i = 0; i < size; i++)
  {
    filter->buffer[i] = init_val;
    filter->sorted[i] = init_val;
  }

  filter->index = 0;
  filter->size = size;
  
  filter->state = FILTER_READY;
  filter->reset   = &FilterMedianInt_Init;
  filter->process = &FilterMedianInt_Process;
  return 0;
}

/**
  * @brief Обработка значения медианным фильтром (int32_t)
  * @param filter Указатель на структуру фильтра
  * @param input Входное значение
  * @return Отфильтрованное значение
  */
int32_t FilterMedianInt_Process(FilterMedianInt_t* filter, int32_t input) {
    check_process_filter(filter);
    
    register int32_t old_value = filter->buffer[filter->index];
    register uint8_t size = filter->size;
    register uint8_t idx = filter->index;
    int32_t* sorted = filter->sorted;
    
    // Обновляем circular buffer
    filter->buffer[idx] = input;
    idx++;
    if (idx >= size) idx = 0;
    filter->index = idx;
    
    // Одновременно ищем позицию для удаления и вставки
    uint8_t remove_pos = 0;
    uint8_t insert_pos = 0;
    uint8_t found_remove = 0;
    
    // Проход по массиву sorted (только один раз!)
    for (uint8_t i = 0; i < size; i++) {
        int32_t current = sorted[i];
        
        // Ищем позицию для удаления старого значения
        if (!found_remove && current == old_value) {
            remove_pos = i;
            found_remove = 1;
        }
        
        // Ищем позицию для вставки нового значения
        if (input > current) {
            insert_pos = i + 1;
        }
    }
    
    // Если insert_pos указывает на место после удаляемого элемента,
    // нужно скорректировать, так как массив уменьшится на 1 элемент
    if (insert_pos > remove_pos) {
        insert_pos--;
    }
    
    // Оптимизированное удаление и вставка за один проход
    if (insert_pos == remove_pos) {
        // Случай 1: Вставляем на то же место, откуда удаляем
        sorted[remove_pos] = input;
    } 
    else if (insert_pos < remove_pos) {
        // Случай 2: Вставляем левее, чем удаляем
        // Сдвигаем элементы [insert_pos, remove_pos-1] вправо
        for (uint8_t j = remove_pos; j > insert_pos; j--) {
            sorted[j] = sorted[j - 1];
        }
        sorted[insert_pos] = input;
    } 
    else {
        // Случай 3: Вставляем правее, чем удаляем (insert_pos > remove_pos)
        // Сдвигаем элементы [remove_pos+1, insert_pos] влево
        for (uint8_t j = remove_pos; j < insert_pos; j++) {
            sorted[j] = sorted[j + 1];
        }
        sorted[insert_pos - 1] = input;
    }
    
    return sorted[size >> 1];
}

/**
  * @brief Инициализация экспоненциального фильтра (int32_t)
  * @param filter Указатель на структуру фильтра
  * @param alpha Коэффициент сглаживания в масштабированном виде
  * @param scale Масштаб коэффициента (например 100 для работы с процентами)
  * @return 0 - успех, -1 - ошибка
  */
int FilterExpInt_Init(FilterExpInt_t* filter, int32_t alpha, int32_t scale) {
  check_init_filter(filter);
  
  filter->alpha = alpha;
  filter->scale = scale;
  filter->value = 0;
  filter->initialized = 0;
  
  filter->state = FILTER_READY;
  filter->reset   = &FilterExpInt_Init;
  filter->process = &FilterExpInt_Process;
  return 0;
}

/**
  * @brief Обработка значения экспоненциальным фильтром (int32_t)
  * @param filter Указатель на структуру фильтра
  * @param input Входное значение
  * @return Отфильтрованное значение
  */
int32_t FilterExpInt_Process(FilterExpInt_t* filter, int32_t input) {
  check_process_filter(filter);
  
  if (!filter->initialized) {
    filter->value = input;
    filter->initialized = 1;
    return input;
  }
  
  // value = (alpha * input + (scale - alpha) * value) / scale
  int64_t result = (int64_t)filter->alpha * input + 
                  (int64_t)(filter->scale - filter->alpha) * filter->value;
  filter->value = (int32_t)(result / filter->scale);
  
  return filter->value;
}

/**
  * @brief Инициализация фильтра скользящего среднего (int32_t)
  * @param filter Указатель на структуру фильтра
  * @return 0 - успех, -1 - ошибка
  */
int FilterAverageInt_Init(FilterAverageInt_t* filter, uint32_t size, FilterMode_t mode) {
  check_init_filter(filter);
  if (size == 0 || size > FILTER_AVERAGE_MAX_SIZE) return - 1;
#ifndef FILTERS_DISABLE_MOVING_AVERAGE
  memset(filter->buffer, 0, sizeof(filter->buffer));
#endif
  filter->size = size;
  filter->sum = 0;
  filter->index = 0;
  filter->count = 0;
  filter->mode = mode;
  
  filter->state = FILTER_READY;
  filter->reset   = &FilterAverageInt_Init;
  filter->process = &FilterAverageInt_Process;
  return 0;
}

/**
  * @brief Обработка значения фильтром скользящего среднего (int32_t)
  * @param filter Указатель на структуру фильтра
  * @param input Входное значение
  * @return Отфильтрованное значение
  */
int32_t FilterAverageInt_Process(FilterAverageInt_t* filter, int32_t input) {
  check_process_filter(filter);
  
  // Общая логика для обоих режимов
  filter->sum += input;
  filter->count++;
  
  // Логика скользящего среднего
  if (filter->mode == FILTER_MODE_MOVING) {
#ifndef FILTERS_DISABLE_MOVING_AVERAGE
    if (filter->count > filter->size) {
      filter->sum -= filter->buffer[filter->index];
      filter->count = filter->size; // Поддерживаем фиксированный размер окна
    }
    filter->buffer[filter->index] = input;
    filter->index = (filter->index + 1) % filter->size;
    filter->lastValue = filter->sum / filter->count;
#endif
  }
  else
  {
    if (filter->count >= filter->size)
    {
      filter->lastValue = filter->sum / filter->count;
      filter->count = 0;
      filter->sum = 0;
    }
  }
  
  return filter->lastValue;  
}

/**
  * @brief Инициализация полиномиальной коррекции (int32_t)
  * @param filter Указатель на структуру коррекции
  * @param coeffs Массив коэффициентов полинома в масштабированном виде
  * @param order Порядок полинома
  * @param scale Масштаб коэффициентов
  * @return 0 - успех, -1 - ошибка
  */
int FilterPolyInt_Init(FilterPolyInt_t* filter, int32_t* coeffs, uint8_t order, int32_t scale) {
  check_init_filter(filter);
  if ((coeffs == NULL) || (order > FILTER_POLY_MAX_ORDER)) return -1;
  
  filter->order = order;
  filter->scale = scale;
  memcpy(filter->coefficients, coeffs, (order + 1) * sizeof(int32_t));
  
  filter->state = FILTER_READY;
  filter->reset   = &FilterPolyInt_Init;
  filter->process = &FilterPolyInt_Process;
  return 0;
}

/**
  * @brief Применение полиномиальной коррекции к значению (int32_t)
  * @param filter Указатель на структуру коррекции
  * @param input Входное значение
  * @return Скорректированное значение
  */
int32_t FilterPolyInt_Process(FilterPolyInt_t* filter, int32_t input) {
  check_process_filter(filter);
  
  // coefficients[0] = a_n * scale
  // coefficients[1] = a_{n-1} * scale  
  // ...
  // coefficients[n] = a_0 * scale
  
  int64_t result = filter->coefficients[0]; // Старший коэффициент
  int64_t x_scaled = input;
  
  for (uint8_t i = 1; i <= filter->order; i++) {
    result = (result * x_scaled) / filter->scale + filter->coefficients[i];
  }
  
  // Домножаем на scale для a_0
  result = (result * filter->scale);
  
  return (int32_t)(result / filter->scale);
}

/**
  * @brief Инициализация табличного фильтра (int32_t)
  * @param filter Указатель на структуру фильтра
  * @param input_arr Массив входных значений (должен быть отсортирован по возрастанию)
  * @param output_arr Массив выходных значений
  * @param size Размер таблицы
  * @param interpolation Флаг интерполяции (0 - ближайшее значение, 1 - линейная интерполяция)
  * @return 0 - успех, -1 - ошибка
  */
int FilterLUTInt_Init(FilterLUTInt_t* filter, int32_t* input_arr, int32_t* output_arr, uint16_t size, uint8_t interpolation) {
  check_init_filter(filter);
  if ((input_arr == NULL) || (output_arr == NULL)) return -1;
  
  filter->input_values = input_arr;
  filter->output_values = output_arr;
  filter->size = size;
  filter->interpolation = interpolation;
  
  filter->state = FILTER_READY;
  filter->reset   = &FilterLUTInt_Init;
  filter->process = &FilterLUTInt_Process;
  return 0;
}

/**
  * @brief Обработка значения табличным фильтром (int32_t)
  * @param filter Указатель на структуру фильтра
  * @param input Входное значение
  * @return Выходное значение по таблице
  */
int32_t FilterLUTInt_Process(FilterLUTInt_t* filter, int32_t input) {
  check_process_filter(filter);    
  if((filter->input_values == NULL) || (filter->output_values == NULL)) {
    return input;
  }
  
  // Поиск ближайших значений в таблице
  uint16_t left_index = 0;
  uint16_t right_index = filter->size - 1;
  
  // Если значение за пределами таблицы - возвращаем крайние значения
  if (input <= filter->input_values[0]) {
    return filter->output_values[0];
  }
  if (input >= filter->input_values[right_index]) {
    return filter->output_values[right_index];
  }
  
  // Бинарный поиск позиции
  while (right_index - left_index > 1) {
    uint16_t mid_index = left_index + (right_index - left_index) / 2;
    if (input <= filter->input_values[mid_index]) {
      right_index = mid_index;
    } else {
      left_index = mid_index;
    }
  }
  
  // Без интерполяции - возвращаем значение левой границы
  if (!filter->interpolation) {
    return filter->output_values[left_index];
  }
  
  // Линейная интерполяция (целочисленная)
  int64_t x0 = filter->input_values[left_index];
  int64_t x1 = filter->input_values[right_index];
  int64_t y0 = filter->output_values[left_index];
  int64_t y1 = filter->output_values[right_index];
  
  if (x1 == x0) {
    return (int32_t)y0; // Избегаем деления на ноль
  }
  
  int64_t result = y0 + (input - x0) * (y1 - y0) / (x1 - x0);
  return (int32_t)result;
}




/**
  * @brief Инициализация RMS фильтра (int32_t)
  */
int FilterRMSInt_Init(FilterRMSInt_t* filter, uint32_t window_size) {
  check_init_filter(filter);
  
  if (window_size == 0 || window_size > FILTER_RMS_MAX_SIZE) return -1;
  
  filter->window_size = window_size;
  filter->sum_squares = 0;
  filter->last_rms = 0;
  filter->index = 0;
  filter->count = 0;
  
  // Инициализируем буфер нулями
  memset(filter->buffer_sq, 0, sizeof(filter->buffer_sq[0]) * window_size);
  
  filter->state = FILTER_READY;
  filter->reset   = &FilterRMSInt_Init;
  filter->process = &FilterRMSInt_Process;
  return 0;
}

/**
  * @brief Обработка значения RMS фильтром (int32_t)
  */
int32_t FilterRMSInt_Process(FilterRMSInt_t* filter, int32_t input) {
  check_process_filter(filter);
  
  // Вычисляем квадрат входного значения
  int64_t square = (int64_t)input * input;
  
  if (filter->count < filter->window_size) {
    // Фаза накопления
    filter->sum_squares += square;
    filter->buffer_sq[filter->index] = square;
    filter->count++;
  } else {
    // Фаза скользящего окна
    filter->sum_squares -= filter->buffer_sq[filter->index]; // Вычитаем старое
    filter->sum_squares += square;                          // Добавляем новое
    filter->buffer_sq[filter->index] = square;              // Сохраняем в буфер
  }
  
  // Увеличиваем индекс с зацикливанием
  filter->index++;
  if (filter->index >= filter->window_size) {
    filter->index = 0;
  }
  
  // Вычисляем RMS
  if (filter->count > 0) {
    int64_t mean_square = filter->sum_squares / filter->count;
    // Защита от отрицательных значений
    if (mean_square < 0) mean_square = 0;
    filter->last_rms = (int32_t)sqrt((double)mean_square);
  }
  
  return filter->last_rms;
}




#ifdef DSP_FITLERS

/**
  * @brief Инициализация биквадратного фильтра с CMSIS-DSP
  */
int FilterBiquad_Init(FilterBiquad_t* filter, const float32_t coeffs[5])
{
  check_init_filter(filter);
  
  if (coeffs == NULL) return -1;
  
  memcpy(filter->coeffs, coeffs, sizeof(filter->coeffs));
  memset(filter->state_buffer, 0, sizeof(filter->state_buffer));
  
  // Инициализация CMSIS-DSP структуры (1 каскад)
  arm_biquad_cascade_df2T_init_f32(&filter->instance, 
                                    1, 
                                    filter->coeffs, 
                                    filter->state_buffer);
  
  filter->state = FILTER_READY;
  filter->reset   = &FilterBiquad_Init;
  filter->process = &FilterBiquad_Process;
  return 0;
}

/**
  * @brief Обработка значения биквадратным фильтром CMSIS-DSP
  */
float FilterBiquad_Process(FilterBiquad_t* filter, float input)
{
    check_process_filter(filter);
    
    float32_t in_arr[1] = {input};
    float32_t out_arr[1];
    
    arm_biquad_cascade_df2T_f32(&filter->instance, in_arr, out_arr, 1);
    
    return out_arr[0];
}
#endif

#endif // FILTERS_ENABLE
