ADC

algemene C code
Berichten: 163
Geregistreerd: 15 Dec 2012, 21:02
Woonplaats: Delfzijl

ADC

Berichtdoor FPCUser » 14 Jun 2018, 14:16

Zoals ik al eerder aangaf om een nieuw topic te starten betreffende de nauwkeurigheid van ADC metingen,
i.p.v. de discussie over array's te vertroebelen.

Voor de duidelijkheid heb ik de berichten van Koepel en shooter gequoot.


>> Re: arrays
Berichtdoor Koepel » 06 Jun 2018, 03:38

@FPCUser, Over mooie oefening gesproken, er is een standaard manier voor.

Code: Alles selecteren
int total = 0;
for( i=0; i<10; i++) // maximum 30 times
{
total += analogRead( A0);
}
int average = total / 10;


Bij de laatste regel "int average = total / 10" verdwijnen de laagste bits. Door die berekening met 'float' te doen is meer resolutie mogelijk dan de 10-bit van de ADC. Een (kleine) ruis op het signaal kan gebruikt worden om meer resolutie te krijgen.
Verder moet het totale getal natuurlijk in de variabele 'total' passen. In het voorbeeld hierboven kun je maar tot ongeveer 30 gaan. Toch is het beter om het optellen van alle waarden met integers te doen, zodat geen enkele bit verloren gaat.
En tot slot kan er zelfs nog een correctie gedaan worden van een halve bit. Die halve bit is een lang verhaal, het heeft de maken hoe de ADC werkt.

De ADC gaat pas naar de volgende stap als dat voltage bereikt is. Dus het gemiddelde ingangssignaal zit midden tussen twee stappen van de ADC.

Code: Alles selecteren
const unsigned int n = 100;
unsigned long total = 0;
for( unsigned int i=0; i<n; i++)
{
total += analogRead( A0);
}
total += n / 2; // half bit correction
float voltage = (float) total / (float) n; // average as float, to get extra resolution
voltage = voltage / 1024.0 * 5.0; // convert to voltage



Door 1024 te kiezen in plaats van 1023 en door een halve bit correctie toe te voegen kun je de indruk wekken dat je er verstand van hebt ;)
Tutorial: https://www.gammon.com.au/adc

In het voorbeeld hierboven kan het gemiddelde van zo'n 60.000 waarden berekend worden. Als meer nodig is, dan is het nodig dat 'n' en 'i' ook een 'unsigned long' worden.


Re: arrays
Berichtdoor FPCUser » 06 Jun 2018, 09:20

@Koepel

Je verhaal om de nauwkeurigheid van de ADC metingen te verhogen is zeker interessant, maar de uitwerking is mij nog niet duidelijk.
Met name de 1/2 bit correctie in de code. Dat de meting tussen twee bits kan zitten wel, maar hoe je dat kan verwerken niet.
Je verhoogd het totaal van 100 metingen met de vaste waarde 50?

Ik zal het stuk van Nick Gammon proberen te begrijpen. Misschien wordt het dan duidelijk. Staat overigens vol met nuttige dingen (referentie spanningen, e.d.).
Bedankt voor je link!


Re: arrays
Berichtdoor Koepel » 06 Jun 2018, 10:28

De ADC heeft 1024 stappen. Daarom is het nodig om te delen door 1024. De ADC kan net geen 5V meten, want dat zou de 1025-ste stap zijn.

Stel de Arduino werkt op 5.000V, dan is iedere stap van de ADC 4.88 mV (5 / 1024).
Maar pas als op de ingang echt een voltage van 4.88 mV staat, dan springt de ADC naar de volgende stap en geeft een waarde 1.
Dus als de ADC een waarde 0 geeft, dan zit de ingangsspanning ergens tussen 0 en 4.88 mV. De ingang is dan dus gemiddeld 2.44 mV.
De ingangsspanning is dan niet 0 Volt, maar gemiddeld 2.44 mV, en dat is een halve stap, oftewel een halve bit extra.

Bij het gemiddelde nemen van 100 metingen, zijn er 100 halve bits (halve stappen) extra, dus 50 erbij optellen. Dat valt grotendeels weg door het daarna door 100 te delen om het gemiddelde te nemen, maar dit gaat om extra resolutie (verder dan de 10 bit van de ADC). Zeg maar de extra bits achter de komma.


Re: arrays
Berichtdoor shooter » 06 Jun 2018, 21:57

je kunt de voedingsspanning van een arduino niet direct meten omdat de reference aan diezelfde spanning zit, het kan wel als je een andere ref gebruikt. zie handleing.
paul deelen
shooter@home.nl


Re: arrays
Berichtdoor FPCUser » 07 Jun 2018, 10:24

@Koepel:
Het kwartje is nog niet helemaal gevallen :D
Maar gun me nog even wat tijd.

Overigens lijkt mij het beter om hierover een nieuw topic te starten.
Dan kan f8voa ook reageren of hij uit de voeten kan met de antwoorden op zijn oorspronkelijke vraag betreffende array's.

Advertisement

Berichten: 163
Geregistreerd: 15 Dec 2012, 21:02
Woonplaats: Delfzijl

Re: ADC

Berichtdoor FPCUser » 14 Jun 2018, 14:22

Het heeft even geduurd, maar ik ben eruit.

Het verhaal van Koepel is duidelijk, maar als ik het met m'n eigen woorden moet uitleggen dan krijg je het volgende:
Stel dat je een spanning op een analoge ingang aanbied van een halve voedingsspanning, dan zou je iets uit de ADC moeten
krijgen van 512.
Maar dat kan in werkelijkheid ook wel iets tussen de 512.1 of 512.9 geweest moeten zijn: de ADC maakt er in alle gevallen 512 van.
We nemen dan maar een gemiddelde waarde aan van 512.5.
We komen daarmee 0.5 tekort na 1 analoge meting.
Als we een gemiddelde nemen van n metingen, dan komen we n x 0.5 (= n/2) tekort.
Daarom wordt het totaal van n metingen verhoogd met n/2, vervolgens wordt het gemiddelde berekend door het totaal door n te delen.

Hierbij een testje met 10 meetwaarden (gebroken getallen), die een gemiddelde geven van 512.5

cpp code
#include <stdio.h>

/* werkelijke waarden, dus met floats */
double total = 0.0;

const unsigned int n = 10;
float metingen[] = {513.1, 512.0, 512.5, 512.9, 512.4,
512.2, 512.3, 512.6, 512.0, 513.0};

int main() {
for (unsigned int i=0; i<n; i++) {
total += metingen[i];
}
printf("%f \n", total);

float avg = total / n;
printf("%f \n", avg);

return 0;
}



Vervolgens een testje met 10 meetwaarden die de ADC zou geven na omzetting. Dit zijn dus gehele getallen.
Dit geeft een gemiddelde van 512.2

cpp code
#include <stdio.h>

/* met meetwaarden, dus integers */
unsigned long total = 0;

const unsigned int n = 10;
int metingen[] = {513, 512, 512, 512, 512, 512, 512, 512, 512, 513};

int main() {
for (unsigned int i=0; i<n; i++) {
total += metingen[i];
}
printf("%d \n", total);

float avg = (float)total / n;
printf("%f \n", avg);

return 0;
}



En als laatste een testje met dezelfde 10 gehele getallen, maar nu met de correctie van 10/2.
Dit geeft een gemiddelde van 512.7

cpp code
#include <stdio.h>

/* met meetwaarden, dus integers. Nu gecorrigeerd */
unsigned long total = 0;

const unsigned int n = 10;
int metingen[] = {513, 512, 512, 512, 512, 512, 512, 512, 512, 513};

int main() {
for (unsigned int i=0; i<n; i++) {
total += metingen[i];
}
printf("%d \n", total);

/* correctie: voor elke meting 0.5 erbij optellen */
total += n / 2;

float avg = (float)total / n;
printf("%f \n", avg);

return 0;
}

Gebruikers-avatar
Berichten: 2655
Geregistreerd: 06 Aug 2016, 01:03

Re: ADC

Berichtdoor Koepel » 14 Jun 2018, 19:19

Ruis, het gaat om ruis. Je weet wel, van die mooie egaal verdeelde ruis :mrgreen:
Je uitleg is correct.

Stel dat het ingangssignaal overeen komt met een ADC waarde van 77.77777. De ADC ziet echter alleen maar 77.
Door ruis toe te voegen krijgt de ADC een veelheid van waarden binnen.
Door vervolgens het gemiddelde te nemen en te corrigeren met de halve bit, is het toch mogelijk om in de buurt van 77.77777 te geraken.

Hieronder een programmaatje om meer bits achter de komma te meten.
Ik moest 100000 waarden middelen voor een redelijk resultaat. Dat komt waarschijnlijk om mijn berekening van ruis niet goed is.
Het resultaat is 77.778920

cpp code
#include <stdio.h>
#include <stdlib.h>

// Gebruik de ruis om extra bits achter de komma te meten.
// Stel dat het signaal 77.77777 is, met een ruis van -10.000 tot +10.000

unsigned long total = 0;

const unsigned long n = 100000;

double original = 77.77777;


int main()
{
for( unsigned long i=0; i<n; i++)
{
// Ruis in millisteps, dus van -10000 tot +10000
int noise = (rand() %20000 ) - 10000;
double noisyValue = original + ( double( noise) / 1000.0);

// De ADC rond als het ware af naar beneden.
int adcValue = int( noisyValue); // simuleer ADC door af te ronden naar beneden.
total += adcValue;
}

total += n / 2; // corrigeer halve bit voor ADC

double result = double( total) / double( n);

printf("%lf\n", result);

return 0;
}


Aanvulling: Inmiddels heb ik gelezen dat "rand() % 20000" helemaal geen goede ruis geeft.

Terug naar C code

Wie is er online?

Gebruikers in dit forum: Geen geregistreerde gebruikers en 3 gasten