Übungsaufgabe: Digitales Filter

Für die Realisierung eines digitalen Filters ist die entsprechende Software in der Programmiersprache C zu erstellen.

1. Genaue Beschreibung der Aufgabe :

1.1 Filteralgorithmus:

nx und ny sind durch die Ordnung des Filters bestimmt. Typische Werte sind 2, 3. Aj und Bj sind die Filterkoeffizienten. Man findet sie z.B. im Buch Tietze, Schenk: Halbleiterschaltungstechnik

1.2 Typ der Daten:

Die Eingangsgrößen xk sind Gleitkommazahlen. Die xk Werte werden mit einer Funktion erzeugt oder können auch von einer Textdatei, die eine Zahl pro Zeile enthält, gelesen werden.

2. Problemanalyse

2.1 Überlegungen zum Algorithmus

Man kann sich die Funktion des Filters in einem Blockdiagramm vorstellen:

xk sind die Eingangswerte, aus diesen Werten werden die Ausgangswerte yk berechnet.

Andererseits kann man die den Algorithmus beschreibende Formel einfach analysieren und in einem Programm umsetzen, ohne sich mit dem fachtheoretischen Hintergrund dieser Formel auseinanderzusetzen. Dazu schreibt man sich die Summe, die ja offensichtlich nicht über viele Summanden geht, einmal an:

Bringt man den Term in Klammer auf die linke Seite, so entsteht eine Darstellung, die weitere Rückschlüsse auf die Entstehung der Formel zulassen würde. Der aktuelle Ausgangswert yk hängt vom aktuellen Eingangswert xk, von den zwei letzten Eingangswerten xk-1 und xk-2, aber auch von den beiden letzten Ausgangswerten yk-1 und yk-2 abhängt. Letzteres kann nur als Rückkopplung des Ausgangssignals interpretiert werden.

Erfahrungsgemäß neigt der Anfänger bei einer solchen Aufgabenstellung, irregeleitet durch die Indizierung der Eingangs- und Ausgangswerte und die Testsituation mit einer überschaubaren Anzahl von xk-Werten dazu, für die xk und yk je zwei Vektoren mit einer großen Zahl von Elementen zu verwenden. In Wirklichkeit ergibt sich damit eine völlig unbrauchbare Lösung. Der Algorithmus muß naturgemäß für eine beliebig große Anzahl von Eingangswerten (das reale Filter im Dauereinsatz) geeignet sein. Zudem zeigt sich, daß nur jeweils wenige x und y Werte verfügbar sein müssen und weiter zurückliegende Werte nicht mehr gebraucht werden.

Eine wesentliche Idee ist die Vorstellung, das wir das aktuelle k immer als 0 betrachten, die Vorgänger sind dann x[-1], x[-2] usw. Die dabei auftretenden negativen Indizes werden im Programm durch positive ersetzt, d.h. x[j] im Programm entspricht x[k-j] in der Formel. Die Vektoren x[] und y[] sind die Datenstruktur für zwei Schieberegister, die als Element mit dem Index 0 den jeweils aktuellen Eingangs- und Ausgangswert enthalten. Die weiteren Werte sind die jeweils einen Takt zurückliegenden Werte.

2.2 Modulspezifikationen:

Filter

enthält die Funktionen initfilter und filter

Die Routine double filter ( double x ) berechnet laut der Formel aus dem aktuellen Eingangswert den Ausgangswert. Die Filterkoeffizienten und die letzten x und y Werte sind für den ganzen Modul definiert. Dies entspricht der Black-Box Funktion des Filters (Lokalitätsprinzip, Datenkapselung).

Skelett (Entwurf) des Moduls:

#define NMAX 5 
#define MMAX 5

/* Vektoren fuer die Filterkoeffizienten */
double A[] = {6.923E-4, 13.846E-4, 6.923E-4}; 
double B[] = {1, -1.937, 0.940 }; 
/* alte x und y Werte */ 
double x[NMAX]; /* die letzten x[k] Werte */ 
double y[NMAX]; 

void initfilter ( ... ) 
{ 
} 

double filter (double x0) 
{ 
/* x-Werte verschieben: */
.......... 
/* y-Werte verschieben */ 
.......... 
/* neuen y-Wert = y[0] berechnen */ 
return y[0]; 
} 

main:

Das Hauptprogramm berechnet die x-Werte oder liest sie aus einer Datei, übergibt den aktuellen x-Wert der Funktion Filter und schreibt die Werte x und y, ergänzt um einen Zähler k auf eine Datei.

Ausgangsdatei:

k   x[k]    y[k]

Test

Für den Test sind folgende xk-Werte zu verwenden.

a) Sprungfunktion: Die ersten 5 Werte sind 0, weitere 45 Werte sind 100 (Sprungfunktion).

b) Sinusfunktion + Oberwelle

Das ist die Überlagerung eines 50 Hz Grundsignals mit einer Oberwelle von 500 Hz. Die Abtastfrequenz ist 10 kHz, also von k bis k + 1 sind es 0.1 ms.

k = 0 bis 4 * 200, das sind 4 Perioden des 50 Hz Signals.

Resultat:

Quellcode einer Lösung

/* filter.c
   Digitales Filter
*/

#define NMAX 5
#define MMAX 5

static double A[] = {6.923E-4, 13.846E-4, 6.923E-4};
static double B[] = {0, -1.937, 0.94};

/* die Koeffizienten sollen spaeter mit einer Funktion
   festgelegt werden */

double filter (double x0)
{
  /* Koeffizienten fuer Tschebyscheff-Tiefpass 2. Ordnung
     mit 3 dB Welligkeit
     Grenzfrequenz 100 Hz
     Abtastfreqeuenz 10 kHz
     Lit. Tietze, Schenk 10. Aufl. Seite 840 */

  static double x[MMAX], y[NMAX];
  int nx = 2, ny = 2, j;

  /* alte Werte verschieben */

  for (j = nx; j > 0; j--) x[j] = x[j-1];
  x[0] = x0;
  for (j = ny; j > 0; j--) y[j] = y[j-1];

  /* neuen Ausgangswert berechnen */

  y[0] = 0;
  for (j = 0; j <= ny; j++)
    y[0] += A[j]*x[j];
  for (j = 1; j <= nx; j++)
    y[0] -= B[j]*y[j];

  return y[0];

} /* end filter */


/* File: filtertest.c */

#include <stdio.h>
#include <math.h>

double filter (double x0);

double xWert (int k)
{
   double A1 = 100, f1 =  50;
   double A2 = 20,  f2 = 500;
   double fa = 10000.0;
   double pi = 3.1415926535;

   return (A1*sin(k*2*pi*f1/fa) + A2*sin(k*2*pi*f2/fa));
}


int main(void)
{
   FILE *fout;
   char fout_name[12];
   int k;
   double x, y;

   printf("File fuer die Resultate: ");
   scanf("%s", fout_name);
   fout = fopen (fout_name, "w");

   for (k = 0; k < 800; k++) {
     x = xWert(k);
     y = filter(x);
     fprintf(fout, "%3d %10.2f %10.2f\n", k, x, y);
   }

   fclose (fout);
   return 0;

} /* end main */

Eine Ebene zurück