Lågpassfilter i mjukvara!

PIC, AVR, Arduino, Raspberry Pi, Basic Stamp, PLC mm.
Användarvisningsbild
jesse
Inlägg: 9240
Blev medlem: 10 september 2007, 12:03:55
Ort: Alingsås

Re: Lågpassfilter i mjukvara!

Inlägg av jesse »

jag hoppades att snigelen skull tända på idén och presentera färdiga kurvor här så jag slipper :D
snigelen
Inlägg: 815
Blev medlem: 8 maj 2009, 11:02:14
Ort: Lund

Re: Lågpassfilter i mjukvara!

Inlägg av snigelen »

Nja z-plan och så var väl kanske inte nödvändigt att dra in, jag bara tänkte att det skulle bli ett lite bättre filter med min modifikation, men fortfarande enkelt. Annars är det med hjälp av Z-transformen man hamnar i z-planet, det är väl ungefär den tids-diskreta mosvarigheten till Laplace-transformen.

Lägger du till flera gamla insignaler så blir det väl fortfarande LP-filter, men det går mer och mer mot ett kam-filter (tror jag) som blockar flera jämnt utspridda frekvenser. Men då finns det väl bättre sätt att göra högre ordningens LP-filter. Men inte lika enkelt som detta...
Användarvisningsbild
Icecap
Inlägg: 26630
Blev medlem: 10 januari 2005, 14:52:15
Ort: Starup (Haderslev), Danmark

Re: Lågpassfilter i mjukvara!

Inlägg av Icecap »

Nu har jag lekt lite med detta rent praktisk och jag är mycket nöjd!

Det mynnade ut i denna fil:
/*----------------------*/
/* File: Low_Pass_100.h */
/* Date: 20110711 */
/* ---------------------*/

/* How to use this software low pass filter: */
/* - Incoming is the value to be filtered. */
/* - Intermediate is a static value, one location for each different value to filter */
/* - Return value is the normalized filtered value. */
/* - Shifts is the number of shifts to do, high number means slower rise */
/* - With a suitable randomness in the input signal extra bits can be extracted from the Intermediate-value */

int Low_Pass(int * Incoming, long * Intermediate, int Shifts)
{
*Intermediate = (*Intermediate - (*Intermediate >> Shifts)) + *Incoming;
return(*Intermediate >> Shifts);
}

Jag har testat att använda denna rutin till lite olika saker i ett projekt och jag fick lite bättre värden än med det förra sätt men det gick åt en del mindre programplats. Jag är mycket glad för att detta blev lagt in, tack Jesse.
Användarvisningsbild
Korken
Inlägg: 2230
Blev medlem: 3 februari 2006, 19:19:36
Ort: Luleå, Porsön

Re: Lågpassfilter i mjukvara!

Inlägg av Korken »

Mycket bra filter! :tumupp:
Användarvisningsbild
jesse
Inlägg: 9240
Blev medlem: 10 september 2007, 12:03:55
Ort: Alingsås

Re: Lågpassfilter i mjukvara!

Inlägg av jesse »

Kul att nån har glädje av det! :)

>jag fick lite bättre värden än med det förra

hmm... är de inte identiska i funktionen, men att du använder pekare istället för vanliga variabler?

Originalkod:

Kod: Markera allt

filter_reg =  filter_reg  -   ( filter_reg >> FILTER_SHIFT)  +  filter_input ;
output  =  filter_reg >> FILTER_SHIFT
Varför måste du skicka med intermediate som argument i varje anrop? kan du inte ha den som en statisk variabel inuti funktionen? Och Shifts kan ju (oftast) vara en kostant lagrad i en macro:

Kod: Markera allt

#define SHIFTS 8
int Low_Pass(int * Incoming)
{
static  long Intermediate = START_VALUE;
Intermediate = (Intermediate - (Intermediate >> SHIFTS)) + *Incoming;
return(Intermediate >> SHIFTS);
}
Användarvisningsbild
Icecap
Inlägg: 26630
Blev medlem: 10 januari 2005, 14:52:15
Ort: Starup (Haderslev), Danmark

Re: Lågpassfilter i mjukvara!

Inlägg av Icecap »

"Med det förra" var bristfälligt skrivit, det skulle nog stå "med det sätt jag gjorde förut" för att det skulle vara korrekt.

Och jag kan INTE ha Intermediate som en static i funktionen, jag använder samma filter på 8 kanaler fast med lite olika shift-steg, därav pekarna.

Jag använder samma rutin till att filtrera 7 kanaler direkt från AD-omvandlaren med relativt låga värden på shift, sedan använder jag den till att "rensa" lambda-värdet och då är det med ett ganska högt shift-värde vilket ger trögheten jag vill ha.
Användarvisningsbild
jesse
Inlägg: 9240
Blev medlem: 10 september 2007, 12:03:55
Ort: Alingsås

Re: Lågpassfilter i mjukvara!

Inlägg av jesse »

>Och jag kan INTE ha Intermediate som en static i funktionen, jag använder samma filter på 8 kanaler fast med lite olika shift-steg, därav pekarna.

Ah, visst ja. :doh:

Själv kör jag samma filter på 96 ADC-kanaler parallellt, och då pekar pekarna direkt till en array. jag skickar bara ADC-kanalens nummer som argument, så hittar den själv indata, utdata och "intermediate"-data.
Användarvisningsbild
Icecap
Inlägg: 26630
Blev medlem: 10 januari 2005, 14:52:15
Ort: Starup (Haderslev), Danmark

Re: Lågpassfilter i mjukvara!

Inlägg av Icecap »

Jag testade att ha funktionen direkt i AD-ISN'n innan jag lade ut den i egen fil och jag testade att kompilera båda versioner.

Det visade sig att versionen med pekare var programmet kännbart mindre, sannolikt för att den inte ska räkna index vid båda läsa o skriva - fler gångar. Med färre programsteg bör programmet gå lite snabbare också och det gillar jag!
bearing
Inlägg: 11672
Blev medlem: 2 mars 2006, 01:01:45
Ort: Ängelholm

Re: Lågpassfilter i mjukvara!

Inlägg av bearing »

Med bakgrund av mitt inlägg i Lågpassfilter i C-kod, tänkte jag att jag kan uppdatera den här tråden också.

Jag har kommit på att man kan göra filtret lite snabbare enbart genom att stuva om, samt deklarera en extra static:

Kod: Markera allt

//FILTER_SHIFTS = log2(RC_constant * calls_per_second)
#define FILTER_SHIFTS 10
uint16_t low_pass_filter(uint16_t input)
{
  static uint16_t output;
  static uint32_t intermediate;

  intermediate -= output;
  intermediate += input;

  output = intermediate >> FILTER_SHIFTS;

  return output;
}
Nu behövs bara en skiftoperation, istället för två.
(Har inte kompilerat koden)

Vet inte om det stod tidigare i tråden, men jag har iaf förstått hur såna här filter beter sig jämfört med ett vanligt RC-filter. Filtrets svar påverkas av hur ofta filterfunktionen körs, vilket kanske inte är helt självklart från början. Om man önskar att filtret ska motsvara ett RC-filter, samt vet hur ofta filterfunktionen körs, kan man räkna ut hur många skiftningar som behövs, med hjälp av log2. (Om din miniräknare saknar log2 kan du istället använda log10 eller naturliga logaritmen (ln), såhär:
//FILTER_SHIFTS = ln(RC_constant * calls_per_second) / ln(2)
Användarvisningsbild
jesse
Inlägg: 9240
Blev medlem: 10 september 2007, 12:03:55
Ort: Alingsås

Re: Lågpassfilter i mjukvara!

Inlägg av jesse »

Mycket bra :bravo:

Formeln var trevlig att få. Hade säkert kunnat räkna ut den själv, men det har aldrig blivit av.
Den kommer jag att ha nytta av!
Användarvisningsbild
Andax
Inlägg: 4379
Blev medlem: 4 juli 2005, 23:27:38
Ort: Jönköping

Re: Lågpassfilter i mjukvara!

Inlägg av Andax »

Intressant kod. Dock bör man väl initiera static variablerna.
Hur blir det eftersom man trunkerar intermediate när man tilldelar output. Kan det bli konstiga effekter att intermediate driver?
Ska se om jag har tid att testa för det är ju definitivt en kompakt och effektiv lösning.
bearing
Inlägg: 11672
Blev medlem: 2 mars 2006, 01:01:45
Ort: Ängelholm

Re: Lågpassfilter i mjukvara!

Inlägg av bearing »

Ja, det kan man göra. Var inte menat som komplett kod. Jag brukar ibland deklarera intermediate utanför funktionen, och initiera till min första input << FILTER_SHIFTS. output borde man också initiera - till input, men det har jag inte tänkt på tidigare.

EDIT: angående att intermediate driver förstår jag inte riktigt vad du menar?
Om man ändrar till return intermediate; i slutet, för att få en förstärkning, kommer intermediate fastna på slumpvärdet ifall input och output är 0.
Skriv svar