Forum: Digitale Signalverarbeitung / DSP / Machine Learning Matlab FIR Filter Design für dsPIC


von MAX (Gast)


Lesenswert?

Hallo DSP profis ;-)

hab eine kleine frag und zwar:
ich möchte ein einfaches FIR filter mit matlab (fdatool) designen und
später dann in einem dsPIc laufen lassen. ich habe mit dem fdatool die
koeffizienten generiert (sind mindestens im bereich von ca -1.0000 bis
+1.0000). da ich später dann im dsPIC die koeffizienten als signed int
abspeichern und auch die filterschleife mit integer rechnen möchte, hab
ich mir gedacht ich multiplizier die koeffitienen mit 2^15, somit
befinden sie sich dann im bereich von -32767 bis +32767. das
eingangssignal kommt vom 12bit ADC. meine frage nun: wie muss ich die
filter routine anpassen, damit das gefilterte ausgangssignal wieder auf
einem 12bit DAC ausgegeben werden kann.

hier meine bisherige filterroutene für Matlab:

...

f0=1000;
f1=3000;
fa=8000;                   %Abtastfrequenz

n=[0:1/fa:(N-1)/fa];       %Abtastvariable für abgetastetes Signal

s=sin(2*pi*f0*n)+cos(2*pi*f1*n);    %Signal abtasten

%FIR-Filter
ord=length(coef)-1;

for i=1:length(s),
    sum=0;
    for j=1:ord,
        if i>ord
            sum=sum+s(i-j)*coef(j);
        end
    end
    y(i)=sum;
end

...

ich hab auch schon gesehen, dass das fdatool die koeffitienten als
signed int als header datei exporteren kann, so kann man diese dann
gleich mit einbinden.

wäre toll, wenn mir jemand helfen kann. - Danke schon mal,
MAX

von Detlef A (Gast)


Lesenswert?

Hi,

einige Punkte:
.......
so wäre weniger aufwendig.

for i=ord+1:length(s),
    sum=0;
    for j=1:ord,
            sum=sum+s(i-j)*coef(j);
    end
    y(i-ord)=sum;
end

Vorsicht bei Migration von Matlab zu C. Bei Matlab starten Indizes bei
1, in C bei 0.

......
Die Skalierung Deiner Koeffizienten und die Skalierung auf den ADC
hängt mit Deiner Rechendynamik zusammen. Angenommen :

Deine Koeffizienten sind skaliert mit signed 16Bit, also
-32768...32767, brauchse 16Bit
Die Eingangswerte haben 12Bit , brauchse zusammen 28Bit
Dein Filter macht 40dB Verstärkung für eine Frequenz, Faktor 100, sind
nochmal 7Bit, brauchse zusammen 35Bit (Schlecht für 32 Bit Rechnung,
Koeffizienten dann grober skalieren).
Um die auf dem 12Bit DAC auszugeben mußte dann um 23 Bit shiften.

Vorsicht auch bei Zwischenergebnissen der Summe
(sum=sum+s(i-j)*coef(j);), da kann es zu filterinternen Überläufen
kommen. Vorher alles gut in integer aufm PC checken.

Cheers
Detlef

von MAX (Gast)


Lesenswert?

Hi Detlef,

erstmal danke für die antwort!
also seh ich das dann richtig so: meine summe muss immer mindestens
12bit (ADC) + 16bit (koeffizienten) = 28bit sein, jedoch wie kommst du
auf die 40dB für eine Frequenz vom Filter. - kannst du das bitte
genauer erklären? ... ich hab mal wo gelesen, dass die Summe aller
koeffizienten die Versärkung ist, aber hat das nichts mit dem zu tun?
ich denke mal, dass sum  long und somit 32bit sein soll. was fürdest du
sagen was ist die niedrigste auflösung für die koeffizienten in bits
ist, damit das ergebnis noch passabel ist? - hab leider noch überhaupt
keine ahnung wie das dann in der praxis aussieht ;-)?

sum+=sum+s(i-j)*coef(j); müsste auf gehn oder meinst du eher nicht?
werd morgen mal das ganze in C auf dem PC etwas testen.. mal sehn.

wie würdest du die tiefpässe am ein- und ausgang für fa/2 realisieren?
werden in der praxis aktive filter mit OPs verwendet? wenn ja
wievielter odernung? - am liebsten wär mir ja ne schaltung mit
berechnungsformel zur dimensionierung ;-) ... so wie im tietze schenk.

Danke noch mal für die hilfe,
gruß,
MAX

von Detlef _. (detlef_a)


Lesenswert?

Hi,

40dB ist Faktor 100. Kenne die Anzahl Deiner Koeffizienten nich
('ord'), aber angenommen, die ist 100, alle Koeffizienten sind =1
(Mittelwertfilter) und Du schiebst immer Einsen rein (Gleichspannung),
dann kommt nach ner Weile immer 100 raus, also zusätzliche 7 Bit. Wenn
Du dann mit 12 Bit ADC-Daten reingehst und die Summe mit 32 Bit
rechnest bleiben noch 13Bit (naja, nimm lieber 12) für die
Quantisierung der Koeffizienten übrig.

fa/2 Filter: Das ist schwierig zu sagen, ohne Details zu kennen.

Cheers
Detlef

von MAX (Gast)


Lesenswert?

Hallo,

so jetzt hab i's super verstanden, danke!

ok hier ein paar details, wobei die nicht 100% sicher sind, denn ich
will ja nur die grundsätzliche funktion von einem FIR testen.

ein bsp.:
FIR filter, Hanning Fenster
Ordnung = 51
fa=8000Hz

und der ein- und gangstiefpass soll nun auf 4000 Hz bandbegrenzen. und
muss nicht extrem steil sein. wenn der übergangsbereich von ca. 3800
bis 4100Hz geht ist das schon ok, denk ich.

gruß,
MAX

von Detlef _. (detlef_a)


Lesenswert?

Hi,

hört sich nach Audio an. Frequenzanteile jenseits von fa/2 siehst Du
gespiegelt um fa/2, 5kHz am Eingang bei fa/2=4kHz kommen als 3kHz an.
Hört sich dann eventuell schlecht an, kann man aber recht einfach mit
z.B. Matlab mal ausprobieren. Ich weiß aber, daß das Ohr tolerant ist
und glaube, daß ne leichte Filterung ausreichen könnte, würde ich
einfach mal mit nem passiven Tiefpaß probieren.

Cheers
Detlef

von MAX (Gast)


Lesenswert?

Hallo,

hab mir grad mal denn inneren aufbau des dsPICs angesehn und gesehen,
dass die MAC einheit einen 40bit accumulator und einen 40bit
barrel-shifter hat, kann ich in diesem fall sie koeffizienten und die
anzahl der bits des ADCs erhöhen? - bzw. auf wieviel kann ich die
maximal dimensionieren?

schöne grüße,
MAX

von Detlef _. (detlef_a)


Lesenswert?

Hi,

12 Bit vom ADC, 16 von Deinen skalierten Coeffs und 6 für die 51er
Anzahl, macht 34, da sollten 40 reichen. 22 mal rechtsschieben und Du
hast die 12 Bit Eingangsdaten für den DAC.

Cheers
Detlef

von MAX (Gast)


Lesenswert?

Hallo,

bei mir ist gerade die frage aufgekommen, ob es sinnvoll ist den ADC
zum bsp mit 10bit und den DAC mit 12bit oder sogar 16bit zu skalieren?
wird das ergebnis dadurch besser als nur mit einem 10bit DAC?

MAx

von Detlef _. (detlef_a)


Lesenswert?

Hi,

augewogenes Verhältnis zwischen ADC und DAC macht Sinn, bei 10Bit rein
und 12Bit raus sind die 2 Bit ja geraten (bei gleichen Abtastraten).
Klar issn 16Bit DAC besser als ein 10Bit DAC, aber wenn die unteren 6
Bit Rauschen sind, bringt das nix. Lieber genau rein (12Bit) und genau
raus (12Bit).

Cheers
Detlef

von MAX (Gast)


Angehängte Dateien:

Lesenswert?

Hallo,

ich poste hier mal mein designetes filter. wird eigentlich beim C30
compiler, die mac einheit automatisch verwendet, oder muss ich die
filter kern routine in assembler programmieren?

MAX

von MAX (Gast)


Angehängte Dateien:

Lesenswert?

hier noch der header mit den koeffizienten

von Detlef _. (detlef_a)


Lesenswert?

Hi,

ich kenne c30 und dsPIC nicht, vermute aber, daß normales C die 40Bit
MAC-Einheit nicht nutzen kann aber daß es von C aus eine einfache
Routine gibt, um da ranzukommen.

Du sprachst oben von fa=8KHz, das Ding im .jpg ist für fa=16kHz
ausgelegt!?

Die Grenzfrequenz Deines Filters liegt für fa=8kHz ja unter 1kHz, da
kannst Du Deinen anti-aliasing Eingangstiefpaß tiefer legen, z.B. auf
ne Grenzfrequnz von 1kHz.

Die Koeffizienten sind symmetrisch, damit kannst Du Dir die Hälfte der
Multiplikationen sparen.

Cheers
Detlef

von MAX (Gast)


Lesenswert?

ja stimmt, normalerweiße kann ich auch 8khz abtastfrequenz verwenden,
abe nur etwas herumgespielt.

wie meinst du das mit dem multiplikationen sparen? meinst du es in etwa
so:

for i=1:length(s),
    sum=0;
    for j=1:ord/2,
         sum=sum+2*s(i-j)*coef(j);
    end
    y(i)=sum;
end

oder hab ich das was falsch verstanden?

danke für die hilfe und gruß,
MAX

von Detlef _. (detlef_a)


Angehängte Dateien:

Lesenswert?

Hi,

nee, Du kannst natürlich nicht die Hälfte der Koeffizienten weglassen
und dafür mal 2 nehmen! Bei der rohen Rechnung mit symmetrischen
Koeffizienten multipliziert Du jeden Abtastwert zweimal mit demgleichen
Koeffizienten. Das machts Du bei der Sparversion nicht, sondern
speicherst Dir die Teilergebnisse ab. C-Code hab ich momentan dafür
nich auf Tasche, angehängtes Strukturbild zeigt aber den Umbau von der
Roh- auf die Sparversion für 5te Ordnung.

BTW: Matlab ohne 'for' is besser! Dein Codesegment

   sum=0;
    for j=1:ord,
            sum=sum+s(i-j)*coef(j);
    end
    y(i-ord)=sum;

läßt ich eindampfen auf:

y(i-ord)=s(i-j:i-j+ord-1)*coef(j)';

(angenommen, daß s und coef 'liegende' Vektoren sind , also nur eine
Zeile und mehrere Spalten haben).

Die brutalstmögliche Sparversion ist das eingebaute 'filter' von
Matlab:

y=filter(coef,1,s);

fettich
Cheers
Detlef

von Detlef _. (detlef_a)


Lesenswert?

Ähm, so:

y(i-ord)=s(i-j:i-j+ord-1)*coef';

von MAX (Gast)


Lesenswert?

danke detlef!

werd mir mal überlegen, wie ich das dann einfach in C implementieren
kann.

MAX

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.