Filtro IIR de paso bajo que atenúa todas las frecuencias

Estoy tratando de hacer un filtro IIR de paso bajo en dsPIC (dsPIC33FJ12MC202) usando el compilador mikroC. He generado coeficientes de filtro utilizando la herramienta de diseño de filtros. Las especificaciones de mi filtro son las siguientes:
LPF, Wp=4KHz, Ws=5KHz, Ap=0, As=60, Muestreo de unos 20Khz

ingrese la descripción de la imagen aquí

Estoy tomando la entrada analógica del canal cero, filtrándola y enviando el valor filtrado a través de UART. El código se parece a esto:

int adcValue;
char result[6];

const unsigned int BUFFER_SIZE   = 8;
const unsigned int FILTER_ORDER  = 3;

const unsigned int COEFF_B[FILTER_ORDER+1] = {0x17D9, 0x478B, 0x478B, 0x17D9};
const unsigned int COEFF_A[FILTER_ORDER+1] = {0x8000, 0xAF27, 0x383C, 0xF802};

const unsigned int SCALE_B = 1;
const unsigned int SCALE_A = 0;

unsigned int inext;
ydata unsigned int input[BUFFER_SIZE];
ydata unsigned int output[BUFFER_SIZE];

void filter(unsigned int adcValue)
{
  unsigned int CurrentValue;
  input[inext] = adcValue;

  CurrentValue = IIR_Radix( SCALE_B,
                            SCALE_A,
                            COEFF_B,        // b coefficients of the filter
                            COEFF_A,        // a coefficients of the filter
                            FILTER_ORDER+1, // Filter order + 1
                            input,          // Input buffer
                            BUFFER_SIZE,    // Input buffer length
                            output,         // Output buffer
                            inext);         // Current sample

  //CurrentValue = 2048;

  output[inext] = CurrentValue;
  inext = (inext+1) & (BUFFER_SIZE-1);    // inext = (inext + 1) mod BUFFER_SIZE;

  //Sending filtered value via UART
  WordToStr(CurrentValue, result);
  strcat(result, "\n\r");
  UART1_Write_Text(result);
}


void main()
{  
   inext  = 0;                                 // Initialize buffer index
   Vector_Set(input, BUFFER_SIZE, 0);         // Clear input buffer
   Vector_Set(output, BUFFER_SIZE, 0);       // Clear output buffer

   //Using R12, R13 for Rx, Tx
   PPS_Mapping(12, _INPUT, _U1RX);
   PPS_Mapping(13, _OUTPUT, _U1TX);

   UART1_Init(115200);
   ADC1_Init();

   while(1)
   {
      adcValue = ADC1_Read(0);
      Delay_us(50);
      filter(adcValue);
   }
}

La función IIR_Radix es proporcionada por el compilador mikroC, por lo que espero que por debajo de 4Khz debería dar salida sea cual sea la entrada y por encima de 4KHz debería atenuar la entrada.

Actualmente estoy simulando un circuito usando Proteus y cuando aplico el generador de onda sinusoidal (amplitud 5v, frecuencia = 1000 Hz) en el canal ADC obtengo una salida que tiene un valor máximo de 95 (por ejemplo, 0, 22, 69, 95, 69, 22, 0 ...) en la Terminal Virtual. Pero 1000 Hz está en banda de paso, por lo que debería obtener la entrada, como (0, 25, 499, 1023, 499, 25, 0...). Entonces, ¿por qué obtengo una salida atenuada incluso para frecuencias de banda de paso?

Estoy analizando la salida en la terminal virtual dentro de la simulación de Proteus, vea a la derecha.

ingrese la descripción de la imagen aquí

Respuestas (1)

Usted dice que la frecuencia de muestreo es "alrededor de 20 kHz" (¿quizás exactamente 22.1 kHz, típicamente para audio?). Entonces, el período de una onda sinusoidal de 1 kHz debe ser de aproximadamente 20 muestras.

Pero sus datos tienen un período de 6 muestras. No es 1kHz, sino más bien 3.5kHz. Acercándose un poco a la frecuencia de esquina, aunque no lo suficientemente cerca como para explicar la atenuación por un factor de 5.

Sin embargo, mirando la captura de pantalla, cada segundo valor es cero. Entonces su frecuencia está justo por debajo de fs/2. Y eso está sólidamente en la stopband.

En realidad, mi objetivo principal es construir LPF para la señal de audio, pero por ahora solo estoy tratando de probar las funciones DSP de dsPIC. Y 0, 22, 69, 95, 69, 22, 0...fue solo un ejemplo (no un período de 6 muestras). Estoy dando una demora de 50 us, por lo que la frecuencia de muestreo sería de aproximadamente 20 KHz, mientras que la velocidad de UART es lenta, es decir, 115200, esa puede ser la razón por la que no está imprimiendo todos los valores de salida en la terminal. Por cierto, no obtuve tu respuesta por completo.