Lågpassfilter i C-kod

PIC, AVR, Arduino, Raspberry Pi, Basic Stamp, PLC mm.
Agwan
Inlägg: 1617
Blev medlem: 15 september 2009, 09:05:14

Lågpassfilter i C-kod

Inlägg av Agwan »

Har googlat runt en massa efter ett enkelt lågpassfilter i C-kod för realtid. Alla resultaten ger bara svar av typen skriv newFilter(param1, param2) så är det klart alternativt av typen mata in vektorn med alla dina mätvärden så filtrerar du såhär, och så ett kodexempel. Men då var det ju inte längre realtid, jag får ju in värden eftersom.

Någon som har en snutt kod eller som har bättre tips på sökord?
Användarvisningsbild
Icecap
Inlägg: 26632
Blev medlem: 10 januari 2005, 14:52:15
Ort: Starup (Haderslev), Danmark

Re: Lågpassfilter i C-kod

Inlägg av Icecap »

Det har varit upp tidigare och jag använder det mycket numera.

Definiera två värden:
short AD_Intermediate;
char AD_Result;

Definiera ett shift-värde:
#define AD_SHIFT 4

Räkna sedan:
AD_Intermediate = (AD_Intermediate - (AD_Intermediate >> AD_LIGHT_SHIFT)) + AD_Value;
AD_Result = AD_Intermediate >> AD_LIGHT_SHIFT;

AD_Value är ingångsvärdet.

Kom ihåg:
AD_Intermediate MÅSTE kunde hålla alla bit som kommer + antal shiftningar! Är det t.ex. 10-bit AD-värden som kommer in och de ska shiftas 6 gg måste Intermediate-värdet klara minst 16 bit.

AD_Result måste såklart klara att hålla utgångsvärdet som har samma antal bits som ingångsvärdet.
Agwan
Inlägg: 1617
Blev medlem: 15 september 2009, 09:05:14

Re: Lågpassfilter i C-kod

Inlägg av Agwan »

Ok, det där filtret tar 1 - halva eller en fjärdedel eller en åttondel av föregående värde och lägger det till nya värdet. Det betyder att amplituden ut påverkas av konstanten AD_SHIFT.

Det är lite för quick and dirty för min applikation, men tack ändå för förslaget. Jag vill gärna att det är ett matematiskt korrekt filter som det går att räkna på. Så att jag vet brytfrekvensen tex. Det filter jag har idag är ett ställbart 1-99 långt flytande medelvärde och det är med flyttal.
Nerre
Inlägg: 27188
Blev medlem: 19 maj 2008, 07:51:04
Ort: Upplands väsby

Re: Lågpassfilter i C-kod

Inlägg av Nerre »

Här hittar du en förklaring av hur man bygger upp filter i kod. Det är relativt enkelt, man har helt enkelt en array med "tidigare sampel" och en med "tidigare utvärde" och sen är filtret helt enkelt en addition av varje sampel/utvärde multiplicerat med en konstant (är konstanten negativ blir det en subtraktion).

http://en.wikipedia.org/wiki/Digital_fi ... ealization

Om jag inte minns helt fel så är antalet "sparade" samples lika stort som graden, så ett andra gradens filter har två sparade värden.

Så det blir typ nåt sånt här:

In[2]=In[1]
In[1]=In[0]
In[0]=Nytt_invärde
Ut[2]=Ut[1]
Ut[1]=Ut[0]
Ut[0] = k1 * In[0] + k2 * In[1] + k3 * In[2] + k4 * Ut[1] + k5 * Ut[2]


Det luriga är alltså att räkna ut konstanterna (och de har jag glömt hur man gjorde...:), men det står högre upp på den där sidan (Z-transform verkar det vara man ska köra).


Här verkar det som man kan få källkoden fixad automagiskt!
http://www-users.cs.york.ac.uk/~fisher/mkfilter/
bearing
Inlägg: 11672
Blev medlem: 2 mars 2006, 01:01:45
Ort: Ängelholm

Re: Lågpassfilter i C-kod

Inlägg av bearing »

Agwan skrev:Ok, det där filtret tar 1 - halva eller en fjärdedel eller en åttondel av föregående värde och lägger det till nya värdet. Det betyder att amplituden ut påverkas av konstanten AD_SHIFT.

Det är lite för quick and dirty för min applikation, men tack ändå för förslaget. Jag vill gärna att det är ett matematiskt korrekt filter som det går att räkna på. Så att jag vet brytfrekvensen tex. Det filter jag har idag är ett ställbart 1-99 långt flytande medelvärde och det är med flyttal.
Nja, amplituden borde väl inte påverkas. Det beror på i vilken ordning plus- samt minus-operationerna görs.
Här är den gamla tråden:
http://elektronikforumet.com/forum/view ... =7&t=50406

Enligt dina önskemål har jag skrivit följande funktion:

Kod: Markera allt

double low_pass_filter(double input, double RC_constant, double calls_per_second)
{
  static double output;
  static double intermediate;

  intermediate -= output;
  intermediate += input;

  output= intermediate / (RC_constant * calls_per_second);

  return output;
}
(Har inte kompilerat koden)

Det här med att ha både output och intermediate som static var en grej jag kom på en dag. Det gör ju att man bara behöver göra en division (eller skiftning när det ska gå fort) istället för två, som i den tidigare koden.
blueint
Inlägg: 23238
Blev medlem: 4 juli 2006, 19:26:11
Kontakt:

Re: Lågpassfilter i C-kod

Inlägg av blueint »

@Agwan, hur kraftig processor (DSP?) vill du använda och hur snabb dataström är det som skall bearbetas?
Agwan
Inlägg: 1617
Blev medlem: 15 september 2009, 09:05:14

Re: Lågpassfilter i C-kod

Inlägg av Agwan »

Det är en 8-bitars 18MHz AVR. 1kHz samplerate vardera på två kanaler..

Skall titta på övriga svaren nästa gång dottern sover.
blueint
Inlägg: 23238
Blev medlem: 4 juli 2006, 19:26:11
Kontakt:

Re: Lågpassfilter i C-kod

Inlägg av blueint »

En metod är ju annars att stoppa in signalen i en FFT och kasta bort de höga frekvensdelarna?
Agwan
Inlägg: 1617
Blev medlem: 15 september 2009, 09:05:14

Re: Lågpassfilter i C-kod

Inlägg av Agwan »

FFT är kanske lite för tungt för 2 x 1000Hz på 8-bitar och 18MHz. Jag har aldrig gjort FFT på 8-bitars, så jag är inte säker.

Annars verkar den där länken till sidan som genererar C-kod väldigt fin. Provade att mata in koden och det ser ut att bli riktigt bra. Ett enda problem bara som kanske förblir olöst. Det finns tre parametrar som genereras av hemsidan som sätter filtrets gränsfrekvens. Jag skulle behöva kunna skjuta filtrets gränsfrekvens on the fly genom att skicka en parameter till AVR:en. Får klura på om det finns en ekvation som beskriver dem.
Findecanor
Inlägg: 1044
Blev medlem: 2 juli 2010, 23:04:07

Re: Lågpassfilter i C-kod

Inlägg av Findecanor »

Wavelets då? :?
Användarvisningsbild
Icecap
Inlägg: 26632
Blev medlem: 10 januari 2005, 14:52:15
Ort: Starup (Haderslev), Danmark

Re: Lågpassfilter i C-kod

Inlägg av Icecap »

Agwan: "Det är en 8-bitars 18MHz AVR. 1kHz samplerate vardera på två kanaler."
Detta låter ganska tungt att lösa med floats faktisk! Har du testat att den klarar detta?
blueint
Inlägg: 23238
Blev medlem: 4 juli 2006, 19:26:11
Kontakt:

Re: Lågpassfilter i C-kod

Inlägg av blueint »

"Fixed point float" kanske är värt att prova?
sodjan
EF Sponsor
Inlägg: 43247
Blev medlem: 10 maj 2005, 16:29:20
Ort: Söderköping

Re: Lågpassfilter i C-kod

Inlägg av sodjan »

Vad är det? :D
"fixed" och "float" är varandras motsatser!
Man kan inte ha "fixed decimal point" och
"floating decimal point" samtidigt... :-)
Agwan
Inlägg: 1617
Blev medlem: 15 september 2009, 09:05:14

Re: Lågpassfilter i C-kod

Inlägg av Agwan »

100 värden vardera på de två kanalerna flytande medelvärde som summeras varje sample och det i 1kHz/kanal fungerar fint.

Så 2x1kHz med filtret som det tipsas om skall inte vara något problem. Det är ju jätteenkelt att implementera och bara några rader kod. Jag ser inte att man kan behöva förenkla mer än de, och de är ju riktiga filter.
Länken igen.
http://www-users.cs.york.ac.uk/~fisher/mkfilter/
Man får ut bodeplottar och allt så att man direkt kan se vad man kan förvänta sig för inverkan på signalen.

Klistrar in ett exempel på koden som genereras för att visa hur enkelt det är.

Kod: Markera allt

#define NZEROS 0
#define NPOLES 2
#define GAIN   6.246389348e+02

static float xv[NZEROS+1], yv[NPOLES+1];

static void filterloop()
  { for (;;)
      { 
        xv[0] = next input value / GAIN;
        yv[0] = yv[1]; yv[1] = yv[2]; 
        yv[2] =   xv[0]
                     + ( -0.9455487639 * yv[0]) + (  1.9439478391 * yv[1]);
        next output value = yv[2];
      }
  }
Skriv svar