tidsbrist... atmega32

PIC, AVR, Arduino, Raspberry Pi, Basic Stamp, PLC mm.
frejo
Inlägg: 496
Blev medlem: 21 april 2004, 21:43:01
Ort: Linköping

tidsbrist... atmega32

Inlägg av frejo »

Håller på och bygger en nummerpresentatör där jag ska göra dtmf-detektering i mjukvaran som en extrauppgift i kursen Signaler och System.

Har dock sprungit in i en vägg eller nått :S känns som att det bara är att riva koden och börja från scratch.

Strukturen är följande.
Jag har två buffertar om 250st 16bitars tal. Sen har jag ett interrupt som sker med en frekvens om 8Khz, 125uS mellan varje. I interruprutinen samplas signalen och sparas i en av buffertarna, när den aktuella bufferten fyllts ändras adressen på en pekare så att den andra bufferten börjar fyllas och en flagga sätts så att programmet vet att det är ok att börja beräkna på värdena i den första bufferten.

Det samplade värdet läggs även i en mindre buffert om 30 poster som fylls kontinuerligt, runt runt.

Den stora bufferten blir med 250 värden ca 3.1ms lång och då dtmf-tonen kan vara upp till 100ms lång använder jag den lilla bufferten för att se när det blivit tyst så jag kan va bered på nästa ton.

Idén jag hade var att göra alla beräkningar mellan varje interrupt för att förenkla kodningen. Men som det är nu har jag en tidslucka på knappt 100uS mellan varje sampling, vilket i 16Mhz bör ge ca 1600 instruktioner om jag räknat rätt.

Redan vid detekteringen av signalen har jag nu kört fast då det tar allldeles för lång tid, bland annat så summers din lilla bufferten vilket blir 30 summeringar med 16-bitars tal. 1600 instruktioner borde väl räcka till gott och väl men det finns lite switch satser och sådant med också. Hur som helst går det åt skogen, tiden räcker inte helt enkelt (tror jag).

Den lösning jag ser just nu är att avbryta all sampling under 2-3ms och på så sätt få massa tid över för beräkningar. Vad jag förstått kan signalen va upp till 100ms lång och luckorna ca 50ms långa och då borde det gå att göra så utan att missa något men är inte helt säker på dom uppgifterna.

Ett problem dock är att jag använder en hel del libbar som sparade mig massa tid i början av projektet:
#include "uart.h" // include uart function library
#include "rprintf.h" // include printf function library
#include "a2d.h" // include A/D converter function library
#include "timer.h" // include timer function library (timing, PWM, etc)
#include "vt100.h" // include vt100 terminal support
#include "cmdline.h" // include cmdline function library

Nu verkar dom dock vara ivägen, jag kan inte sätta cli() och sei() runt min kod utan att programmet spårar ur, tror bland annat timer-libben förlitar sig på interrupts... så det lutar åt att skriva om det i en renare form, vilket känns lite tungt så här 1-2 veckor innan redovisning.

Kom just på att jag skulle kunna gå direkt på tondetektering och skippa den lilla bufferten och summeringen av den och istället se när frekvensen försvinner för att hitta tomrummen...

Tänkte ändå jag skulle fråga här innan jag skriver om allting ifall nån har något bättre förslag på strukturen i programmet?
cyr
Inlägg: 2712
Blev medlem: 27 maj 2003, 16:02:39
Ort: linköping
Kontakt:

Inlägg av cyr »

Det första jag kommer på är, behövs det verkligen 16bits tal? Att nöja sig med 8 lär väl göra ganska mycket på en 8bits processor...

Du kan ha summan av alla tal i den lilla bufferten i en variabel, uppdatera den varje gång du lägger in ett sampel i den (subtrahera samples du ska skriva över och addera det ny samplet). Så slipper du iaf addera alla samples varje gång...
Användarvisningsbild
Icecap
Inlägg: 26647
Blev medlem: 10 januari 2005, 14:52:15
Ort: Starup (Haderslev), Danmark

Inlägg av Icecap »

Vad jag förstår kör du FFT för att detektera tonerna men vad jag inte förstår är om du behöver en buffert alls. Jag har aldrig kört FFT men som jag har förstådd kan man räkna 1 steg åt gången och allt eftersom justera talen i en buffert.

Jag har förstådd som att du samplar ett värde in i bufferten och sedan räknar hela klabbet på hela bufferten, har jag missuppfattat eller är den stora buffert ditt "spektrumminne"?

Och sedan den lilla med 16-bit.......som cyr skriver: kör ner till 8 bit, summera vid att:
1: ha en summa-variabel. (initialisera till 0 liksom hela bufferten)
2: flytta pekaren.
3: subtrahera det värde som pekaren nu pekar på från summan.
4: lägg in det nua värdet i tabellen
5: addera det nya värde till summan
frejo
Inlägg: 496
Blev medlem: 21 april 2004, 21:43:01
Ort: Linköping

Inlägg av frejo »

Anledningen till att jag kör 16-bitars är att jag var lite lat och inte orkade löda dit en opamp. Istället kör jag ad:n i 10-bitars differential mode och 10x förstärkning. Signalen på ca 100-1500mV blir då ett värde runt -200 till +200 och när det inte är signal har jag ett värde på ca 3-4. Med 8 bitars läget är jag inte säker på hur det kommer se ut, signalen kan väl hamna runt 40 i värde och bruset kanske kommer lite väl nära. Men det är ett väldigt vettigt påpekande, ska se vad jag kan göra åt saken.

Jag kör inte fft utan en variant av den kallad Goertzels algoritm, står lite mer om projektet här:
http://www.elektronikforumet.com//forum ... php?t=4954

Just nu funderar jag på att skippa den lilla bufferten helt och istället låta 250 värde ackumuleras och sen disabla interruptsen i max 1ms (16000 instruktioner...) för att göra tondetektering på den bufferten innan jag snurrar vidare. Då skulle det iofs räcka med en buffert...
frejo
Inlägg: 496
Blev medlem: 21 april 2004, 21:43:01
Ort: Linköping

Inlägg av frejo »

Nu har jag löst samplingsbiten och buffertsystemet. Det tar upp < 5us var 125:e us så det finns gott om tid över.

Nu är problemet min implementering av Goertzels algoritm, den tar 250ms! och bör inte ta mer än 5-10ms max för att jag inte ska missa något.

Kod: Markera allt

void computeGoertzel(u08* resultPtr)
{
sbi(PORTB,PB0);	
	timer_enable_int (0); // disable interrupts while doing calculations on the buffert
	
	u08 freqStr[8];
	float Q0,Q1,Q2;
	float max;
	u08 maxpos=0;
	
	for(i=0;i<8;i++)
	{
		Q0=0;
		Q1=0;
		Q2=0;
		for(j=0;j<250;j++)
		{
			Q0 = coeff[i] * Q1 * Q2 + buffert[j];
			Q2 = Q1;
			Q1 = Q0;
		}
		freqStr[i] = Q1*Q1 + Q2*Q2-Q1*Q2*coeff[i];
	}
	
	// find max and 2nd max
	max=freqStr[0];
	for(i=1;i<8;i++)
	{
		if(freqStr[i] > max)
		{
			max = freqStr[i];
			maxpos=i;
		}
	}
	*(resultPtr + 0)=maxpos;
	*(resultPtr + 1)=max;
	
	freqStr[maxpos]=0;
	max=freqStr[0];
	maxpos=0;
	for(i=1;i<8;i++)
	{
		if(freqStr[i] > max)
		{
			max = freqStr[i];
			maxpos=i;
		}
	}
	*(resultPtr + 2)=maxpos;
	*(resultPtr + 3)=max;
	
	ADC_STATE=BUFFERT_BUSY; 
	cbi(PORTB,PB0);	
	timer_enable_int (_BV (OCIE1A)); // enable interrupts before returning
	return;
}
Problemet här ligger nog i att alla variabler är float, dvs 32-bitars i en 8-bitars uC...

Vad jag förstått skulle jag kunna använda "fixed point arithmetics" men har googlat lite och inte mer än nån vettig sida med info. Nån som har mer info om var man kan läsa på just "fixed point arithmetics" eller nått förslag på smartare implementering?

Kan tillägga att coeff ser ut så här:
coeff[0] = 0.847261012173;
coeff[1] = 0.815430994891;
coeff[2] = 0.776486512687;
coeff[3] = 0.730579528559;
coeff[4] = 0.571787960228;
coeff[5] = 0.487250125725;
coeff[6] = 0.387756916378;
coeff[7] = 0.272196276643;
frejo
Inlägg: 496
Blev medlem: 21 april 2004, 21:43:01
Ort: Linköping

Inlägg av frejo »

Det löste sig efter en dags plöjande i online material... nu kör jag signed fixed point med 5 bitar heltalsdel och 10 bitar bråkdel.
:)
Skriv svar