Implementierung FIR in C

OP #5905383
Lesenswert?
• ▲
▼
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 #5905498
Lesenswert?
• ▲
▼
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 #5905514
Lesenswert?
• ▲
▼
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 #5905648
Lesenswert?
• ▲
▼
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

Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt. Bitte hier nur auf die ursprüngliche Frage antworten, für neue Fragen einen neuen Beitrag erstellen.

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.