ADC waarden niet constant

free_electron

Silicon Member

float float float.. en wat is er mis met integer arithmetic ? maak een sliding window integrator. in machienetaal is dit mechanisme slechts een 10 tal instrcuties en gebruikt het een 20 tal cycli van de processor. plus een tiental byte ram. je merkt niet eens dat het er in zit.

code:


dim arry[8] as word
dim ptr as byte
dim total as word

function get_adc() as byte
   ptr = ptr+1
   if ptr = 8 then ptr=0
   arry[ptr] = adc_result
   total=0
   dim x
   for x = 0 to 7
    total = total +arry[x]
   next x
   total >> 3 ' schuif 'total' 3 bits naar rechts = delen door 8
   return lowbyte(total)
end function

zet zelf om in picbasic. bovenstaande de code is 'generic' basic

als je veel rotzooi moet wegfilteren kan je naar 16 gaan ( array 16 maken , de for next ook tot 15 laten lopen en de shift operatie met 4 bits in plaats van 3 bits doen.

analoge ingang affilteren. voedingslijnen naar PIC ook.
en de potmeter via een buffertrap op de A/D hangen. de ingang van een pic heeft geen oneindige impedantie en vormt een belasting voor de potmeter.
je kan eventueel nog een 'foefje' uithalen door de pic voeding iets lager te zetten dan de potmeter voeding : zet een shottky diode naar de pic toe. zo draait die op 4.6 volt en de potmeter kan tot 5 volt gaan.

het probleem is de referentie diode . jouw pic heeft er geen. en aangezien je niet aan de vref kunt... ( ik zou anders die omlaag halen met een halve volt )

Professioneel ElectronenTemmer - siliconvalleygarage.com - De voltooid verleden tijd van 'halfgeleider' is 'zand' ... US 8,032,693 / US 7,714,746 / US 7,355,303 / US 7,098,557 / US 6,762,632 / EP 1804159 - Real programmers write Hex into ROM

Dat kan nog iets efficiënter: je kunt een lopend totaal bijhouden, en daar steeds de nieuwste waarde bij optellen en de oudste waarde van aftrekken, dan hoef je niet steeds de hele array door om alles op te tellen. Dat wordt vooral interessant als je over een groot aantal samples gaat filteren.

En nu even miereneuken (eh, is dat miereneuken of mierenneuken?):
"if ptr = 8 then prt = 0" kun je vervangen door
"ptr = ptr & 0x07", dat scheelt een branch instructie.

Een manager is iemand die denkt dat negen vrouwen in één maand een kind kunnen maken
Anoniem

Op 3 maart 2009 01:36:00 schreef free_electron:
float float float.. en wat is er mis met integer arithmetic ? maak een sliding window integrator. in machienetaal is dit mechanisme slechts een 10 tal instrcuties en gebruikt het een 20 tal cycli van de processor. plus een tiental byte ram. je merkt niet eens dat het er in zit.

code:


dim arry[8] as word
dim ptr as byte
dim total as word

function get_adc() as byte
   ptr = ptr+1
   if ptr = 8 then ptr=0
   arry[ptr] = adc_result
   total=0
   dim x
   for x = 0 to 7
    total = total +arry[x]
   next x
   total >> 3 ' schuif 'total' 3 bits naar rechts = delen door 8
   return lowbyte(total)
end function

zet zelf om in picbasic. bovenstaande de code is 'generic' basic

als je veel rotzooi moet wegfilteren kan je naar 16 gaan ( array 16 maken , de for next ook tot 15 laten lopen en de shift operatie met 4 bits in plaats van 3 bits doen.

Hier doe je eigelijk niks anders dan een circulaire buffer vullen, daar het gemiddelde uit berekenen en vervolgens naar een byte omzetten. Mocht ik het fout hebben, laat het me weten, ik ben niet zo thuis in Basic. C FTW :+. Anyway, dit doe ik al :). Het enige punt waar ik de float gebruik is de berekening om het ingelezen bereik van 7 t/m 252 om te rekenen naar een bereik van 0 t/m 255. Hier word overigens een int vermenigvuldigd met een float (1.041) en weer weggeschreven als een int. Verder word er nergens met floats gewerkt.

analoge ingang affilteren. voedingslijnen naar PIC ook.
en de potmeter via een buffertrap op de A/D hangen. de ingang van een pic heeft geen oneindige impedantie en vormt een belasting voor de potmeter.

Dit ga ik met een beetje geluk vandaag testen.

je kan eventueel nog een 'foefje' uithalen door de pic voeding iets lager te zetten dan de potmeter voeding : zet een shottky diode naar de pic toe. zo draait die op 4.6 volt en de potmeter kan tot 5 volt gaan.

het probleem is de referentie diode . jouw pic heeft er geen. en aangezien je niet aan de vref kunt... ( ik zou anders die omlaag halen met een halve volt )

Opzich kan het, alleen gaat de fader ook niet helemaal naar 0 Ohm dus moet ik een dergelijke truck ook met de gnd uithalen. Dan wordt het wel een erg smerige oplossing denk ik ;).

Ik zou die voeding maar eens aanpakken. Dan heb je al die trucages niet nodig.
Ik heb in diverse projectjes verschillende picjes en potmeters toegepast, dat loopt altijd netjes van 0 tot 1023. Het kan hoogstens eens 1 stapje verschillen.

Een float vermenigvuldiging met 1.041 kun je ook doen door met 246 te vermenigvuldigen en dan het resultaat 8 posities naar rechts te schuiven (= delen door 256), of de vermenigvuldigen met 62955 en de shiften met 16, als je toch al in 32 bit integers bezig bent. Dit scheelt een hoop rekentijd en een hele library in je program flash.

Een manager is iemand die denkt dat negen vrouwen in één maand een kind kunnen maken
Henry S.

Moderator

Op 3 maart 2009 01:36:00 schreef free_electron:
het probleem is de referentie diode . jouw pic heeft er geen. en aangezien je niet aan de vref kunt... ( ik zou anders die omlaag halen met een halve volt )

Externe Uref en een buffer.

Zit je alleen nog met het probleem dat de slider geen 0Ω haalt.

Je zou de ADC resolutie kunnen verhogen naar 1024 waarden (0-1023), de meetwaarde 2 keer naar rechts shiften (ben je onderste waarden ook kwijt) en met de buffer zorgen dat je slider de 1023 (na shifts 255) haalt.

Dan heb je onderin nog een hele kleine fout, acceptabel?

Floats is een beetje zonde, of je moet het 100% precies hebben, de truuk van SparkyGSX is ook heel mooi.

Deze post is niet door ChatGPT gegenereerd. De 2019 CO labvoeding.
free_electron

Silicon Member

Op 3 maart 2009 02:16:40 schreef SparkyGSX:
Dat kan nog iets efficiënter: je kunt een lopend totaal bijhouden, en daar steeds de nieuwste waarde bij optellen en de oudste waarde van aftrekken, dan hoef je niet steeds de hele array door om alles op te tellen. Dat wordt vooral interessant als je over een groot aantal samples gaat filteren.

En nu even miereneuken (eh, is dat miereneuken of mierenneuken?):
"if ptr = 8 then prt = 0" kun je vervangen door
"ptr = ptr & 0x07", dat scheelt een branch instructie.

en hoe denkt meneer de oudste waarde bij te houden ? voor de volgende cycles heb je oudste -1 nodig ... die array heb je hoe dan ook nodig. ik ga wel akkoord dat je de for next kan kwijtspelen en met wat pointer bewerkingen de truuk kan uithalen. alhoewel je bij rollover van de array weer twee if then else constructies aan je broek hebt.. tzal een tradeoff worden...

de or functie op de pointer is wel goed gevonden. ik had zover nog niet gedacht.

Professioneel ElectronenTemmer - siliconvalleygarage.com - De voltooid verleden tijd van 'halfgeleider' is 'zand' ... US 8,032,693 / US 7,714,746 / US 7,355,303 / US 7,098,557 / US 6,762,632 / EP 1804159 - Real programmers write Hex into ROM
Anoniem

Op 3 maart 2009 16:39:29 schreef SparkyGSX:
Een float vermenigvuldiging met 1.041 kun je ook doen door met 246 te vermenigvuldigen en dan het resultaat 8 posities naar rechts te schuiven (= delen door 256), of de vermenigvuldigen met 62955 en de shiften met 16, als je toch al in 32 bit integers bezig bent. Dit scheelt een hoop rekentijd en een hele library in je program flash.

Het ligt waarschijnlijk aan mij, maar ik zie niet in hoe dit mn huidige berekening kan vervangen. De ingelezen waarden liggen tussen 7 en 252.

ADC_uit = (ADC_uit-7) * 1.041;
Deze berekening rekent de ingelezen waarde om naar een waarde in het bereik van 0-255.

Vermenigvuldigen met 246 en delen door 256 (of 8x bitshiften) levert toch niet hetzelfde resultaat op als vermenigvuldigen met 1.041? Hoe kom je eigelijk aan het getal 246?

Even iets anders, de waarden die je nu hebt. Zijn dat gemiddelde waarden?

Zo ja, hoe ziet de data eruit als je niet middeld? Als die nog sterk fluctueren zou ik eerst zorgen dat, dat niet meer gebeurd.
Schone voeding en buffer tussen fader en ADC. Misschien kun je de fader ook nog wat ontdenderen. Klein c-tje van de loper naar de GND.

Maak me niet gek, ik ben al gek.
Anoniem

Dat is geen probleem meer, lineaire voeding is echt noodzakelijk :).

Damn, die 246 was voor een deling door 1.041. Voor een vermenigvuldiging moet je 256 * 1.041 ~= 266 hebben.

Dus vermenigvuldigen met 266, right-shiften met 8, dat geeft een vermenigvuldiging met 266 / 256 ~= 1.039

Met 32-bit registers (die je toch nodig gaat hebben, gezien je 10-bit ADC waarde) zou je op 65536 * 1.041 ~= 68223 uitkomen. Dat geeft een factor van 68223 / 65536 ~= 1.041

Je zou het trouwens ook nog met 16-bit registers kunnen doen, maar dan heb je maar 6 bits voor je vermenigvuldigingsfactor, waardoor de afwijking groter wordt.
64 * 1.041 ~= 67. factor is 67 / 64 ~= 1.047, dus die afwijking lijkt me wat te groot.

@FE: die bitwise AND op de pointer is redelijk standaard, maar dan moet je array lengte natuurlijk wel een macht van 2 zijn.

Ik heb ook nooit gezegd dat je de hele array weg kunt laten, maar dat je die niet steeds hoeft op te tellen. Dat loont wel als je lange array hebt, maar helaas kan dat niet meer met Gaussian of zelfs Chebyshev filters.

Overigens zou in dit geval een moving median filter naar mijn idee beter zijn dan een moving average, maar dan wordt het toch wel moeilijk om aan een hoop branch instructies te ontkomen.

EDIT: ja, digitale signaal bewerking was wel een van mijn favoriete vakken.

Een manager is iemand die denkt dat negen vrouwen in één maand een kind kunnen maken

Op 4 maart 2009 00:35:38 schreef M14:
Dat is geen probleem meer, lineaire voeding is echt noodzakelijk :).

Dat weet ik, maar hoe ziet je data eruit als je niet middeld? Die mag niet meer dan 1 bit fluctueren.

Maak me niet gek, ik ben al gek.