Forum: Mikrocontroller und Digitale Elektronik Sinus - PWM erzeugen


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 Andreas Berglich (Gast)


Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Hallo zusammen,

ich habe einen Arduino und möchte mit diesem einen Sinus mittels PWM 
erzeugen.

Dazu habe ich vor, die 360° des Sinus' mit einem Array von 360 Elementen 
abzubilden. In jedem Element des Arrays soll ein Wert zwischen 0 und 255 
enthalten sein (8 bit -> AVR), was dann später dem Tastverhältnis (PWM) 
entsprechen soll.

In Excel habe ich dazu mit der Sinusfunktion einen Wertebereich von 
1°-360° berechnet und daraus dann die Werte zwischen 0 und 255 erzeugt.

Allerdings scheint in meiner Wertetabelle etwas nicht stimmen...siehe 
Graphen. Mir kommt der Sprung von 180° auf 181° seltsam vor.

Wisst ihr, wo das Problem liegen könnte?

Vielen Dank schon mal!


Grüße
Andreas

von Pandur S. (jetztnicht)


Bewertung
0 lesenswert
nicht lesenswert
Vergiss die 360 Grad. Falls irgendwas, dann den Kreis durch 256 teilen, 
das ergibt dann gerade einen Ringspeicher, der bei 8bit Ansteuerung 
rundrum laeuft. Wobei man dann eh nur 90 Grad davon abspeichern wuerde, 
die anderen Winkel ergeben sich durch Spiegelungen, Dh man benoetugt nur 
64 Samples.

Dh du musst nur 0- pi/2 durch 64 samples abbilden. Als Sin & Cos.

Fuer einen BLDC die Clark & Park Transformation nicht vergessen.

: Bearbeitet durch User
von Ben S. (theben)


Bewertung
1 lesenswert
nicht lesenswert
Bei deiner berechnung fehlt der Negativ anteil. Dein AVR wird ebenfalls 
perse keine Negativen spannungen ausgeben können. Du musst also darauf 
achten ob du mit deiner Sinuserzeugung gerade in der negativen Sinus 
halbwelle bist oder nicht.

Wenn du in der Negativen bist musst du dann vorkehrungen treffen dass 
die Werte negativ werden.

von Ben S. (theben)


Bewertung
1 lesenswert
nicht lesenswert
In deinem Fall is die Rechnung falsch. Du muss die ergebnisse durch 2 
teilen und in der posiven Halbwelle zusätzlich 128 addieren

von Roland F. (rhf)


Bewertung
0 lesenswert
nicht lesenswert
Andreas Berglich schrieb:

> Wisst ihr, wo das Problem liegen könnte?

Deine Wertetabelle lässt keine negativen Werte zu. Zeig doch mal wie du 
sie berechnet hast.

rhf

von Andreas Berglich (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Ok, Danke!

Das mit den 64 Werten klingt logisch.
Was ich nicht verstehe ist, warum ich den Kreis (360°) durch 256 teilen 
soll. Letztlich hätte ich einfach ein Array mit 360 Elementen erzeugt.

Vielmehr würde mich interessieren, wie ich auf die Werte des 
"Negativbereichs" komme.

Dass man mit 0 oder 1 keinen Negativbereich abbilden kann, ist mir klar.
Aber wie kann ich es in meiner Wertetabelle berechnen?

Danke!

von Ben S. (theben)


Bewertung
0 lesenswert
nicht lesenswert
mal -1

von Lothar M. (lkmiller) (Moderator) Benutzerseite


Bewertung
0 lesenswert
nicht lesenswert
Andreas Berglich schrieb:
> Letztlich hätte ich einfach ein Array mit 360 Elementen erzeugt.
Du solltest binär denken. Das macht es dem binären Rechner 
einfacher...

> Vielmehr würde mich interessieren, wie ich auf die Werte des
> "Negativbereichs" komme.
Du ziehst von den Werten, die sprunghaft nach oben gehen, einfach 255 
(oder eher 256) ab.

Und wenn du für die Minimalwerte und Maximalwerte deines Sinus nur 1 
Byte über hast, dann musst du ihn auf den Bereich -128..127 skalieren. 
Das pass als Zweierkomplement in ein Byte.

: Bearbeitet durch Moderator
von Falk B. (falk)


Bewertung
0 lesenswert
nicht lesenswert

von Pandur S. (jetztnicht)


Bewertung
1 lesenswert
nicht lesenswert
> warum ich den Kreis (360°) durch 256 teilen soll. Letztlich hätte ich einfach 
ein Array mit 360 Elementen erzeugt.

Die Anzahl : 360 Werte sind zufaellig. Es koennten auch 400 sein. Fuer 
Neugrad. Oder sinnvollerweise eine Zweierpotenz, zB 256. Allenfalls 
gehen auch 128. Oder es sollten besser 512 sein.

: Bearbeitet durch User
von Sven L. (svenl)


Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Hallo zusammen,

so etwas habe ich auch schon gemacht. Du solltest Dein Array so bilden, 
dass die Grundwelle ohne Tonausgabe bei der Hälfte der PWM-Frequenz 
steht.

Sprich: Dein Sinus hat bei Beginn einen Wert von 127, im positiven 
Maximum 254 und im negativen Maximum 0.

Es ist richtig, dass man prinzipiell nur 90° des Sinus abbilden muss und 
sich den Rest durch rückwärts lesen und Verschiebung durch Addition 
bilden kann. Das verkompliziert den Code für den Anfang allerdings.

Ich würde vorschlagen eine Sinustabelle mit 256 Werten zu nehmen, was 
einem Byte-Array von 256 Werten entspricht. Ein Timer steuert die PWM 
mit der maximalen Frequenz, um den Sinus durch Aliasing sauber hin zu 
bekommen, der zweite Timer inkrementiert den Pointer, der auf das 
aktuelle Arrayelement zeigt. Mit der Geschwindigkeit des 2. Timers 
steuerst Du die Frequenz.

Auf jeden Fall benötigt man einen sehr guten Tiefpass mind. 3. oder 
besser 5. Ordnung hinter dem PWM-Ausgang, um das Signal von Oberwellen 
zu befreien. Ich empfehle dafür den AADE-Filterdesigner. Für große 
Induktivitäten kann man Entstördrosseln verwenden.

Code kann ich im Moment nicht zeigen, aber ein Foto vom Scope.

Mehr Infos zum Thema: http://forum.db3om.de/ftopic24353.html

Viele Grüße!

Sven

von Lothar M. (lkmiller) (Moderator) Benutzerseite


Bewertung
1 lesenswert
nicht lesenswert
Sven L. schrieb:
> Es ist richtig, dass man prinzipiell nur 90° des Sinus abbilden muss und
> sich den Rest durch rückwärts lesen und Verschiebung durch Addition
> bilden kann. Das verkompliziert den Code für den Anfang allerdings.
Nicht, wenn man es schlau anstellt. Denn die Information, welcher Wert 
aus dem Viertelsinus zu werten ist, steht in den obersten beiden Bits.

Dort habe ich das mal mit VHDL beschrieben:
http://www.lothar-miller.de/s9y/archives/37-DDFS-mit-BROM.html
Der Viertelsinus hat 64 Werte, und der Ausgabewert berechnet sich 
ausgehend von einem "Vollsinus" mit 256 Punkten (=index) in C etwa so:
1
constant signed char viertelsinus[64] = { 0x02, 0x05, ... 0x7f }
2
unsigned char index;
3
signed char result
4
5
if (index&0x40) result = viertelsinus[63-(index&0x3f)]; // rückwärts
6
else            result = viertelsinus[   (index&0x3f)]; // vorwärts
7
8
if (index&0x40) result = -result;                       // negieren
Und wenn man mit "negativen Zahlen" nichts anfangen kann, dann muss man 
einfach nochmal alles um 128 nach oben verschieben...

: Bearbeitet durch Moderator
von Matthias S. (Firma: matzetronics) (mschoeldgen)


Bewertung
0 lesenswert
nicht lesenswert
http://www.daycounter.com/Calculators/Sine-Generator-Calculator.phtml

Wertebereich und gewünschte Länge angeben, heraus kommt eine direkt für 
C geeignete Copy&Paste Tabelle. Geschweifte Klammern um das Ganze und 
der Tabelle einen Namen geben. Bei Bedarf noch PROGMEM oder andere 
Spässchen hinzufügen. Nicht vergessen, das letzte Komma zu entfernen.

: Bearbeitet durch User
von Falk B. (falk)


Bewertung
0 lesenswert
nicht lesenswert
@Lothar Miller (lkmiller) (Moderator) Benutzerseite

>> Es ist richtig, dass man prinzipiell nur 90° des Sinus abbilden muss und
>> sich den Rest durch rückwärts lesen und Verschiebung durch Addition
>> bilden kann. Das verkompliziert den Code für den Anfang allerdings.

Eben.

>Nicht, wenn man es schlau anstellt. Denn die Information, welcher Wert
>aus dem Viertelsinus zu werten ist, steht in den obersten beiden Bits.

Lohnt sich das auf einem kleinen Controller? Was hat man eher übrig, 
Flash oder CPU-Leistung?


>if (index&0x40) result = viertelsinus[63-(index&0x3f)]; // rückwärts
>else            result = viertelsinus[   (index&0x3f)]; // vorwärts

>if (index&0x40) result = -result;                       // negieren

Ein einfaches

OCR1A = sinus[index];

ist da deutlich einfacher und schneller. Die paar hunder Bytes Speicher 
sind selten ein Problem.

von THOR (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Man kann auch am Anfang in der main() das Array mit sin(x) Werten füllen 
(Math.h) sofern man genug Speicherplatz hat.

PWM Erzeugung dann (mit dem 8 Bit Timer): OCRx = 128 + sintable[n]

wobei in sintable die Werte von +127 bis -127 stehen (in welchen 
Abstufungen musst du entscheiden, aber ein 256 Elemente Ringpuffer 
bietet sich an, sintable[n++] rotiert dich immer durch den Puffer 
durch).

Am PWM Pin kommt dann ein Sinus mit DC-Offset raus, den packst du mit 
Koppelkondensator (hat Nullstelle bei DC) an einen Tiefpassfilter 
(Rekonstruktionsfilter) mit geeignetem Amplitudengang und fertig ist 
dein symmetrischer Sinus.

von Thomas U. (thomasu)


Bewertung
-1 lesenswert
nicht lesenswert
Matthias S. schrieb:
> http://www.daycounter.com/Calculators/Sine-Generator-Calculator.phtml
>
> Wertebereich und gewünschte Länge angeben, heraus kommt eine direkt für
> C geeignete Copy&Paste Tabelle.

Aber eine nicht so besonder schlau gerundete mit zufälligem Offset.
Das sollte man lieber MATLAB überlassen. Außerdem zeigt sich daß die 
Umsetzung auf eine PWM auch noch zu einem Fehler führt, den man in der 
Tabelle berücksichtigen sollte, um ihn zu minimieren.

von M. K. (sylaina)


Bewertung
0 lesenswert
nicht lesenswert
Thomas U. schrieb:
> Aber eine nicht so besonder schlau gerundete mit zufälligem Offset.
> Das sollte man lieber MATLAB überlassen. Außerdem zeigt sich daß die
> Umsetzung auf eine PWM auch noch zu einem Fehler führt, den man in der
> Tabelle berücksichtigen sollte, um ihn zu minimieren.

Ich fürchte nur, nach fast einem Jahr hat das kaum noch Relevanz.

von Thomas U. (thomasu)


Bewertung
0 lesenswert
nicht lesenswert
Der link ist noch aktuell und die dort angebotenen Werte sind sicher die 
gleichen wie von vor einem Jahr. Und sie sind nicht sonderlich 
intelligent gerundet, als das sie Beispiel für eine gute Wertegeneration 
wären.

Ist aber nett, dass Du aufpasst.

von Jürgen S. (engineer) Benutzerseite


Bewertung
0 lesenswert
nicht lesenswert
Thomas U. schrieb:
> Matthias S. schrieb:
>> http://www.daycounter.com/Calculators/Sine-Generator-Calculator.phtml
>>
>> Wertebereich und gewünschte Länge angeben, heraus kommt eine direkt für
>> C geeignete Copy&Paste Tabelle.
>
> Aber eine nicht so besonder schlau gerundete mit zufälligem Offset.
> Das sollte man lieber MATLAB überlassen. Außerdem zeigt sich daß die
> Umsetzung auf eine PWM auch noch zu einem Fehler führt, den man in der
> Tabelle berücksichtigen sollte, um ihn zu minimieren.

Das ist ein Thema, das man doch besser im PWM-Modulator regeln sollte, 
weil die dafür nötige Vorverzerrung auf dessen Verhalten und Auflösung, 
sowie auch an das Folgesystem angepasst werden muss. In der Tabelle kann 
man das nur einbringen, wenn die Drehzahl und das Fehlerspektrum 
statisch sind und alles vorausberechnet werden kann - wenn der Modulator 
also stur geradeaus arbeitet und Linearität annimmt.

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]
  • [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.