Forum: Mikrocontroller und Digitale Elektronik sigma delta dac in c


Announcement: there is an English version of this forum on EmbDev.net. Posts you create there will be displayed on Mikrocontroller.net and EmbDev.net.
von chris (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Im Moment beschäftige ich mich gerade mit den Prinzipien der Sigma-Delta 
AD-Wandlung.

Um das mal praktisch auszuprobieren, habe ich einen Sinus Genrator 
programmiert:

http://hobby-roboter.de/forum/viewtopic.php?f=5&t=141

Man muss nur eine RC-Tiepass an den LED-Ausgang des Arduino anschließen 
und dann das Signal auf einen Lautsprecher geben.

von chris (Gast)


Bewertung
1 lesenswert
nicht lesenswert
Erstaunlich fand ich, wie wenig Codezeilen für eine Sigma Delta Dac 
benötigt werden.
// sigma delta DAC, hold the DAC value for n-steps constant
for(n=0;n<50;n++)
{
   integrator+=sollwert-oldValue;
   if(integrator>0)
   {
      oldValue=MAXVALUE;
      digitalWrite(13, HIGH);   // set the LED on
   }
   else
   {
      oldValue=0;
      digitalWrite(13, LOW);    // set the LED off
   }
}

Durch die Arduino digitalWrite Funktionen wird die Hauptschleife 
allerdings etwas langsam. Der DAC läuft in etwa mit 100kHz, sodass eine 
Schleife mit 50 Durchläufen in meinem Beipiel mit dem Sinus eine 
effektive Abtastfrequenz von 100kHz/50=2kHz ergibt. Bin gepsannt, wie 
schnell das Ganze wird, wenn die Funktionen durch direkte Portzugriffe 
ersetzt werden.

von Yalu X. (yalu) (Moderator)


Bewertung
0 lesenswert
nicht lesenswert
Mit GCC 4.2.4 oder 4.3.6 dauert ein Schleifendurchlauf 14 Taktzyklen.
Bei 20 MHz Taktfrequenz entspricht das 1,43 MHz, die Abtastrate ist 28,6
kHz. Neuere GCCs sind aber teilweise mehr als Faktor 2 langsamer. Ein
schon etwas älterer Snapshot von 4.8.0 braucht für jeden Schleifendurch-
lauf 36,5 Taktzyklen. Möglicherweise ist die Release-Version besser, ich
habe sie allerdings noch nicht getestet.

von chris (Gast)


Bewertung
0 lesenswert
nicht lesenswert
>Bei 20 MHz Taktfrequenz entspricht das 1,43 MHz

Das klingt gut. Auf dem Arduino mit 16MHz und digitalWrite waren es nur 
so um die 100kHz. Faktor 10 bringt da qualitativ viel. Stellt sich nur 
die Frage, mit welcher Optimierung komiliert?

von Yalu X. (yalu) (Moderator)


Bewertung
0 lesenswert
nicht lesenswert
chris schrieb:
> Stellt sich nur die Frage, mit welcher Optimierung komiliert?

Ach so, das habe ich ganz vergessen zuschreiben: Die angegebenen
Ergebnisse gelten für die Optimierung mit -O2. Bei -Os wird der Code
etwas langsamer und etwas kleiner. Die Unterschiede liegen in der
Größenordnung von 10%, sind also nicht so riesig.

Was tut eigentlich diese digitalWrite-Funktion alles, dass sie so extrem
langsam wird? Klar, sie muss die Pin-Nummer in ein I/O-Register und eine
Bitmaske umsetzen, dazu sind sicher ein paar Lookups und/oder Shifts
erforderlich, aber dass das Ganze gleich sooo lange dauert?

von chris (Gast)


Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
>Was tut eigentlich diese digitalWrite-Funktion alles, dass sie so extrem
>langsam wird?
Das weis ich leider auch nicht. Die Routine ist wohl in C++ geschrieben.

Ich habe noch mal ein wenig experimentiert. Mit dem direkten Zugriff auf 
PORTD komme ich auf 500kHz Abtastfrequenz.
Es war auch eine hochfrequente Störung auf dem Signal. Diese verschwand 
interessanterweise, als ich die Variablendefinitionen in die loop 
gesetzt habe ( vorher waren sie global )
void loop() {
  uint16_t phaseDelta=1070;
  int16_t integrator=0;
  uint8_t sollwert=64;
  uint8_t oldValue=0;
  uint16_t phase=0;
  cli();
  while(1)
  {
    // sin wave DDS ( direct digital synthesis )
    sollwert=128+sintab[phase>>8];
    phase+=phaseDelta;
    //phaseDelta++;
  
    // sigma delta DAC, hold the DAC value for n-steps constant
    DDRD|=(1<<2); // set pin as output
    for(n=0;n<25;n++)
    {
      integrator+=sollwert-oldValue;
      if(integrator>0) 
      {
        oldValue=MAXVALUE;
        PORTD|=(1<<2); // set pin high
      }
      else 
      {
        oldValue=0;
        PORTD&=~(1<<2); // set pin low
      }
    }
    DDRD&=~(1<<2); // set pin into high impedance state
    PORTD&=~(1<<2); // turn off pull up
  }
}
Den Sinus habe ich mit dem Mikrofon aufgenommen. Deshalb die 
tieffrequenten Schwingungen ( die man aber nicht hört )

von chris (Gast)


Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Hier das Spektrum des direkt mit dem Line-In augenommenen Signals.

von chris (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Man sieht die für einen Sigma-Delta Wandler typische Verlagerung des 
Rauschens zu hohen Freunzen.
Die harmonischen im unteren Frequenzbereich hätte ich in dieser Stärke 
nicht erwartet. Das könnte aber mit der geringen Auflösung des Sinus ( 8 
Bit ) zusammenhängen.

von Yalu X. (yalu) (Moderator)


Bewertung
0 lesenswert
nicht lesenswert
chris schrieb:
> Diese verschwand
> interessanterweise, als ich die Variablendefinitionen in die loop
> gesetzt habe ( vorher waren sie global )

Die alten GCCs (4.2.4 und 4.3.6) haben netterweise selber die Inhalte
der globalen in lokale Variablen (d.h. Register) kopiert, weswegen die
innere Schleife auch so schnell lief. Bei den neueren Versionen muss
der Programmierer etwas nachhelfen, so wie du es getan hast.

>     DDRD&=~(1<<2); // set pin into high impedance state
>     PORTD&=~(1<<2); // turn off pull up

Warum denn das? Das gibt doch nur zusätzliches Rauschen und kostet
Zyklen?

von chris (Gast)


Bewertung
0 lesenswert
nicht lesenswert
>Warum denn das? Das gibt doch nur zusätzliches Rauschen und kostet
>Zyklen?

Du hast recht, es kostet Zyklen. Allerdings gibt es am Ende der 
For-Schleife eine zeitliche Verzögerung. In der Zeit, in der dann der 
Sinuswert aktualisiert wird, bleibt der Ausgang auf dem letzten Wert. 
Ist dieser Wert High, wird der Kondensator des RC-Tiefpass am Ausgang ( 
bie mir 470Ohm, 100nF ) zu stark aufgeladen. Ist der Wert Low wird der 
Kondensator zu stark entladen. Wenn man den Ausgan hochohmig schaltet, 
hält der Kondensator den Wert ( zumindest wenn die Senke hochohmig genug 
ist ).

Mein Eindruck war, dass der Sinus mit dem "hochohmig Schalten" sauberer 
klingt.

von Alexxx (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Ein Sigma-Delta ADC mit weniger als 50dB SNR - Genial.

von Jonas B. (jibi)


Bewertung
0 lesenswert
nicht lesenswert
ADC != DAC - Genial.

gruß Jonas

von chris (Gast)


Bewertung
0 lesenswert
nicht lesenswert
>Ein Sigma-Delta ADC mit weniger als 50dB SNR - Genial.

Das SNR des DAC hängt vom Glättungsfilter ab. Dieser besteht momentan 
aus einem RC-Glied ( 470 Ohm, 100nF ). Durch einen zweiten 
nachgeschaltetn RC-Tiefpass ( 4700Ohm, 10nF ) sollte sich das SNR 
deutlich verbessern.

von Peter D. (peda)


Bewertung
0 lesenswert
nicht lesenswert

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.