Sida 1 av 1

Hur göra minnessnål medelvärdesalgoritm, helst snabb

Postat: 24 november 2006, 09:02:13
av bearing
Nuvarande koden ser ut såhär:

Kod: Markera allt

while (oldsec==sec)
{
	....

	//Beräkna medel
	antalvarden++;
	utrymme=~summa;
	if (!full||utrymme>=hastigheten)//Kolla att summa har plats för hastigheten
	{
		summa+=hastigheten;
		medelv=summa/antalvarden;
	}
	else	//Om inte, byt algoritm
	{
		full=1;
		diff=hastigheten-medelvh;								
		if (hastigheten>=medelvh)
		{
			diff/=antalvarden;
			medelv+=diff;
		}
		else
		{
			diff=-diff;
			diff/=antalvarden;
			medelv-=diff;
		}
	}
	
	....
}
Jag använder 16-bitars unsigned-variabler. Medel beräknas under 1 sekund, datan kommer i mellan 3 och 50 Hz. Vid höga hastigheter och/eller frekvenser kommer summa fyllas långt innan sekunden är slut, därför byts då algoritmen till en "grövre".

Är inte nöjd, det blev mycket kod. Finns det standardalgoritmer/andra- som beräknar medel på ett enklare/bättre sätt?

Postat: 24 november 2006, 11:20:05
av sodjan
Akitektur ? (PIC, AVR eller något annat ?)

Sen finns det massor av "shortcuts" för att undvika divisioner (eller
ersätta dom med shifts) o.s.v. T.ex genom att välja antalet värden
till en jämn potens av 2.

Men då måste man vet mycket mer om dataintervall m.m m.m.

Det finns dessutom flera olika definitioner på "medelvärde", eller
riktigare hur man beräknar det.

Postat: 24 november 2006, 11:49:59
av bearing
Det är en PIC 16F628.

Mäter periodtiden på ett hjul och beräknar varvtalet med formeln
v=konstant/T

Om perioden är lång kommer det få värden under sekunden, och varvtalet är lågt, så summa i min kod fylls inte.
Men vid högt varvtal fylls summa snabbt p.g.a stora varvtalsvärden med hög frekvens.

Min kod körs nu varje gång det "kommer" (från ett interrupt) en ny period.

Är det detta som kallas FIR-filter?

Detta är inte så viktigt, koden jag har duger, men ett bättre sätt kan vara bra att veta om senare eftersom medelvärdesberäkning antagligen är vanligt.

Postat: 24 november 2006, 12:23:11
av danei
Är det inte bättre att mäta tiden för ett antal varv. Hur många kan du ju variera beroende på hastighet.

Postat: 24 november 2006, 13:02:31
av bearing
Det är en bra ide'. Det är det jag egentligen skulle vilja göra, men begränsas av att demoversionen av kompilatorn bara klarar 16-bitars-variabler. Om jag gör divisionen v=konstant/T, och sedan v=v*antalvarv, med ett stort T får v få värdesiffror.
Jag skulle vilja göra: v=antalvarv*konstant/T. Då blir det många fler värdesiffror kvar efter divisonen, men kräver större variabler.

Postat: 24 november 2006, 13:13:09
av sodjan
Eller genom att ändra mätmetod helt så att du slipper divisionen.

Säg att du vill mäta upp till 3.000 rpm, och att det kommer en puls/varv.

3000 pulser/min = 50 pulser/sek. (= din övre gräns, eller hur ?)

Om du räknar pulser under 7.5 sekunder så får du 375 pulser (vid 3000 rpm)

Multiplikation med 8 (3 st snabba shift) så får du 3000 !

Så istället för ett antal multiplikationer och divisioner, så blev det bara 2 enkla shift.

Postat: 24 november 2006, 13:30:52
av bearing
Ja, egentligen skulle jag kunna göra så eftersom det inte krävs så stor upplösning. Men jag jag finner någon sorts tillfredställelse av att göra så hög upplösning som möjligt. Det skulle duga bra med en upplösning på 0,5 m/s, men metoden jag använder nu ger 1 cm/s.