Implementierung FIR in C

OP #5905383
Hallo zusammen,

ich habe ein FIR-System implementiert (Cortex M4F), das die Ableitung 
einer Zahlenreihe aus 64-Bit-Integer bilden soll. Quick & Dirty (siehe 
untenstehender Quelltext) funktioniert das auch.

Allerdings habe ich das Gefühl, dass es auch in C "schöner" geht, als 
z.B. die Koeffizienten bei jedem Aufruf neu zu berechnen.

Da die Ordnung N auf jeden Fall recht klein bleiben wird, könnte ich die 
lookup-table für die Koeffizienten auch explizit hinschreiben und per 
switch-case auswählen. Oder in der Status-Variablen hinterlegen. Oder 
die Schleife komplett ausschreiben und die Filterordnung per switch-case 
auswählen. Ich könnte mir das Umspeichern bei jedem Aufruf irgendwie 
sparen. Oder.

Wie macht man soetwas in C "richtig" und "schön" ?

1
#define DERIVATIVE_N_VALUES 5
2

3
typedef struct
4
{
5
    int64_t lastValues[DERIVATIVE_N_VALUES];
6
}
7
Diff64state_t;
8

9

10
/* Differenzierer fuer grosse Zahlen
11
 * Steigung der Ausgleichsgerade durch die Zahlenreihe u(z), u(z^-1), .... u(z^-n) */
12
float differentiate64(int64_t u, Diff64state_t *State)
13
{
14
    assert( State != NULL );
15

16
    // Letzte n Werte speichern, um die Ableitung zu bilden
17
    memmove( &(State->lastValues[1]), &(State->lastValues[0]), (DERIVATIVE_N_VALUES-1)*sizeof(int64_t));
18
    State->lastValues[0] = u;
19

20

21
    // FIR-Koeffizienten-Array bestuecken (erste Haelfte)
22
    // Das Koeffizienten-Array ist antisymmetrisch, deswegen wird nur ueber die Haelfte iteriert
23
    int n = DERIVATIVE_N_VALUES;
24
    float b[n];
25
    float c = 6.f/((float) ( n*(n*n-1) ) );
26
    for( int i = 0; i<n/2; i++ )
27
    {
28
        b[i] = c * ((float) (2*i - n + 1) );
29
    }
30

31

32
    // FIR
33
    // Die paarweise Differenz der Eingangswerte verhindert einen Ueberlauf, da fuer alle n
34
    // aufeinanderfolgende Werte sicher gilt: max(u(z^i)) - min(u(z^i)) < 2^16
35
    float d = 0.f;
36
    int64_t *v = State->lastValues;
37
    int64_t *w = State->lastValues + (DERIVATIVE_N_VALUES -1);
38
    for( int i = 0; i<n/2; i++ )
39
    {
40
        int32_t diff = *w-- - *v++;
41
        d += b[i] * ( (float) diff );
42
    }
43

44
    return d;
45
}
Gast
Also das memcpy mit den vergangenen Werten kann man sich sparen, wenn 
man einen Ringbuffer nutzt.

Und die Werte für den Filter kann man in eine dedizierte Init-Funktion 
verschieben, wenn sie sich zwischen den Filter-Aufrufen normalerweise 
nicht ändern.

Man kann dann z.B. eine eigene Struktur haben für Ringbuffer und Filter, 
die man an die Filterfunktion als Zeiger übergibt.
Gast
Nop schrieb:

> Also das memcpy mit den vergangenen Werten kann man sich sparen, wenn
> man einen Ringbuffer nutzt.

Das ist nicht notwendigerweise effizienter. Hängt sehr stark von der 
Zielarchitektur ab, aber auch davon, wie großzügig man mit dem RAM 
umgehen kann. Und natürlich davon, wie groß die History des Filters sein 
muss.

Tendenziell wird der Ringpuffer umso interessanter, ja umfangreicher die 
History ist. Bei FIR (mit im Vergleich zu IIR tendenziell 
umfangreicherer History) dürfte aber wohl tatsächlich der Ringpuffer 
i.d.R. das Mittel der Wahl sein.
Gast
c-hater schrieb:

> Das ist nicht notwendigerweise effizienter.

Bei einem Ringbuffer hat man natürlich den wrap-around, spart sich dafür 
aber eine Kopierschleife in selber Länge. Solange man als Buffergröße 
eine Zweierpotenz nimmt, ist der wrap-around lediglich ein &, was nur 
eine Instruktion ist.

Antwort schreiben

Eine eigene Frage? Dieser Thread ist über 7 Jahre alt. Stell sie in einem eigenen Thread – dort lesen mehr Leute mit, und sie wird öfter und schneller beantwortet.

Neuen Thread starten

Eine Lösung, Ergänzung oder Rückmeldung zu diesem Thread? Dann antworte hier.

Formatierung
  • [c]C-Code[/c]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] – Link zu einem Artikel
  • Verweis auf einen anderen Beitrag: Rechtsklick auf dessen Beitrags-ID (#8078628), „Adresse kopieren“, in den Text einfügen

Mehr zur Formatierung

Längeren Sourcecode als Anhang, nicht in den Text. JPG nur für Fotos und Scans; Zeichnungen und Screenshots als PNG oder GIF. Siehe Bildformate.

Schon registriert? Anmelden

Wird nicht angezeigt. Wir schicken dir einen Link; sobald du damit bestätigst, erscheint dein Beitrag.

Mit dem Abschicken legst du einen kostenlosen Account an und erkennst die Nutzungsbedingungen und die Datenschutzerklärung an.