Tiefpass-IIR-Filter, der alle Frequenzen dämpft

Ich versuche, mit dem mikroC-Compiler einen Tiefpass-IIR-Filter in dsPIC (dsPIC33FJ12MC202) zu erstellen. Ich habe Filterkoeffizienten mit dem Filter Design Tool generiert. Meine Filterspezifikationen sind wie folgt:
LPF, Wp=4KHz, Ws=5KHz, Ap=0, As=60, Abtastung etwa 20Khz

Geben Sie hier die Bildbeschreibung ein

Ich nehme den analogen Eingang von Kanal Null, filtere ihn und sende den gefilterten Wert über UART. Der Code sieht in etwa so aus:

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

Die IIR_Radix- Funktion wird vom mikroC-Compiler bereitgestellt. Ich erwarte also, dass unter 4 kHz unabhängig von der Eingabe eine Ausgabe erfolgen sollte und über 4 kHz die Eingabe gedämpft werden sollte.

Derzeit simuliere ich eine Schaltung mit Proteus und wenn ich einen Sinuswellengenerator (Amplitude 5 V, Freq = 1000 Hz) am ADC-Kanal anwende, erhalte ich eine Ausgabe mit einem Maximalwert von 95 (z. B. 0, 22, 69, 95, 69, 22, 0). ...) auf dem virtuellen Terminal. Aber 1000 Hz sind im Durchlassbereich, also sollte ich bekommen, was auch immer der Eingang ist, wie (0, 25, 499, 1023, 499, 25, 0 ...). Warum bekomme ich also selbst für Durchlassfrequenzen eine gedämpfte Ausgabe?

Ich analysiere die Ausgabe auf dem virtuellen Terminal innerhalb der Proteus-Simulation, siehe rechts.

Geben Sie hier die Bildbeschreibung ein

Antworten (1)

Sie sagen, dass die Abtastfrequenz "ungefähr 20 kHz" beträgt (vielleicht genau 22,1 kHz, typisch für Audio?). Die Periode einer 1-kHz-Sinuswelle sollte also etwa 20 Samples betragen.

Aber Ihre Daten haben einen Zeitraum von 6 Samples. Es sind nicht 1kHz, sondern eher 3,5kHz. Etwas nah an der Eckfrequenz, wenn auch nicht nah genug, um die Dämpfung um den Faktor 5 zu erklären.

Wenn man sich jedoch den Screenshot ansieht, ist jeder zweite Wert Null. Ihre Frequenz liegt also knapp unter fs/2. Und das ist solide im Stoppband.

Eigentlich ist mein Hauptziel, LPF für Audiosignale zu bauen, aber im Moment versuche ich nur, die DSP-Funktionen von dsPIC zu testen. Und 0, 22, 69, 95, 69, 22, 0...war nur ein Beispiel (nicht Zeitraum von 6 Proben). Ich gebe eine Verzögerung von 50 us an, sodass die Abtastrate ungefähr 20 kHz betragen würde, während die UART-Geschwindigkeit langsam ist, dh 115200. Dies kann der Grund dafür sein, dass nicht jeder Ausgabewert auf dem Terminal gedruckt wird. Übrigens habe ich Ihre Antwort nicht vollständig verstanden.