6-Phasen Sinus-Tabelle berrechnen.

Guten morgen Liebe Community,

Ich habe vor einen Sinus in eine Tabelle auszulagern um mit diesem eine PWM später auszugeben.
Um das lustig zu gestalten sollen es insgesamt 6-Sinus Tabellen mit einer Phasenverschiebung von 60° werden. Der Sinus wird auf 400 Stützwerten aufgebaut. Ebenfalls sollen diese einen Off-set von 1250 haben und im Werte Bereich von 2375 bis 125 bleiben.
Dafür habe ich mir folgenden Code überlegt.

  for(i;i<stuetzWerte;i++){
    sine_1[i]=((1125*sin(((pi*2)/stuetzWerte)*i))+1250);
    sine_2[i]=((1125*sin((((pi*2)/stuetzWerte)*i)+((1/3)*pi))+1250));
    sine_3[i]=((1125*sin((((pi*2)/stuetzWerte)*i)+((2/3)*pi))+1250));
    sine_4[i]=((1125*sin((((pi*2)/stuetzWerte)*i)+pi)+1250));
    sine_5[i]=((1125*sin((((pi*2)/stuetzWerte)*i)+((4/3)*pi))+1250));
    sine_6[i]=((1125*sin((((pi*2)/stuetzWerte)*i)+((5/3)*pi))+1250));
    }
  }

Jedoch erhalte ich scheinbar nicht das Richtige ergebniss.
Ich habe mir di Arrays über die Loop-Funktion mittels Serial.println() ausgeben lassen und mir in eine Excel-Tabelle eingefügt.
Dabei unterscheiden sich die Arrays in ihren Werten nicht. Lediglich die letzten 3 Sinus Tabellen sind invertiert.

Woran könnte das liegen?

Ich speichere die Sinus-Werte in ein Int-Array und habe schon versucht die Werte über (int) zu casten jedoch ohne Erfolg.

Variablendefinition fehlt. Wird i auf 0 initialisiert?

Für einen Uno sind 400 * 6 int übrigens zu viel (und für eine Sinuswert-Tabelle auch ;))

Brauchst du überhaupt die 6 Tabellen? Im Endeffekt kannst du von vornherein 3Tabellen sparen, da sie nur die ersten drei invertiert sind (sinus(x)= -sinus(x+180°)). Wenn du bei dem Aufruf einen Phasenwinkel nutzt, kannst du zwei weitere sparen. Sinus2(1)=Sinus1(67)

@ Michael_x
Ja die Variable i wird initialisiert. Habe nur einen kleinen Auszug des Codes gepostet.
Hier nochmal der Gesamte mit allen Variablen die benötigt werden.

int sine_1[400];
int sine_2[400];
int sine_3[400];
int sine_4[400];
int sine_5[400];
int sine_6[400];
const float pi = 3.14159;
int stuetzWerte = 400;

void setup() {
  Serial.begin(9600);
  set_sinus_1();
}

void set_sinus_1(){
  int i=0;
  for(i;i<stuetzWerte;i++){
    sine_1[i]=((1125*sin(((pi*2)/stuetzWerte)*i))+1250);
    sine_2[i]=((1125*sin((((pi*2)/stuetzWerte)*i)+((1/3)*pi))+1250));
    sine_3[i]=((1125*sin((((pi*2)/stuetzWerte)*i)+((2/3)*pi))+1250));
    sine_4[i]=((1125*sin((((pi*2)/stuetzWerte)*i)+pi)+1250));
    sine_5[i]=((1125*sin((((pi*2)/stuetzWerte)*i)+((4/3)*pi))+1250));
    sine_6[i]=((1125*sin((((pi*2)/stuetzWerte)*i)+((5/3)*pi))+1250));
    }
  }

Desweiteren verwende ich einen Arduino Mega. Bei diesem wird mir angezeigt das erst 61% ausgelastet sind.

@Theseus

Ja ich brauche die 6 Tabellen, da ich auf die Tabellen mit einer Timer Interrupt zugreife alle paar Mikrosekunden. Die Anzahl der Werte lässt leider keine Verschiebung von 1 Tabelle zu.
Wenn ich die Ersten Drei Sinus Phasen um 180° verschiebe spare ich mir im Endeffekt nur das Anwende von der sin()- Funktion. Da dies jedoch alle am Anfang passiert habe ich s gerne übersichtlich. Das Erstaunliche ist ja, dass die letzten 3 Tabellen Invertiert sind, jedoch keine Phasenverschiebung untereinander enthalte.

@guntherb

Dem zu Folge, wenn wir deine Rechnung weiter führen müsste das Ergebniss innerhalb des Sinus immer 0 sein. Denn sin(0)=0
Dann müsste in meinm Array ich permanent den Wert 1250 drinne stehen haben.
Jedoch habe ich mir die Werte bereit ausgeben lassen und Sie erzeugen einen Sinus.
Also die Werte für keine Phasenverschiebung sind perfekt. Ebenso die Werte für 180°. Nur die Dazwischen liegenden Phasen bekomme ich keinen Wert.

Würde ich gerne die Excel Tabelle schicken jedoch kann ich diese nicht hochladen.
Eine Idee dafür vllt.??

jerry134:
@Theseus

Ja ich brauche die 6 Tabellen, da ich auf die Tabellen mit einer Timer Interrupt zugreife alle paar Mikrosekunden. Die Anzahl der Werte lässt leider keine Verschiebung von 1 Tabelle zu.

Nein, brauchst du nicht.

(Das ist nur ein kleiner Teil der Antwort, ich mache das wie du mit deinem Kode.)

@Michael_x
Das war einer meiner Ersten versuche im ISR die Werte für den Sinus zu errechnen. Jedoch müsste ich für genaue Ergebnisse mit Float variablen rechnen, da sonst zu hohe Rundungsfehler auftreten. Mit Float Zahlen tut sich de Mega jedoch ziemlich schwer, da er scheinbar keine Float-Uni besitzt, was wiederum über die Interrupt Time kommt.

@ Wandhall

Ich habe den Code gepostet. Das einzige was nicht enthalten ist ist die Loop-Funktion in der ich mir die Arrays per Serial.println() ausgeben lasse.

Habe die Excel Tabelle in eine Zip.Datei gepackt.

SinusWerte.zip (17.9 KB)

Der Mega2560 ist ein 8 bit Controller ohne hardware-Float unterstützung. Richtig.
Zur Optimierung würde ich auf 128 oder 256 Stützstellen runtergehen, die auf pi/2 verteilen. Und den index als byte nehmen.

Auch für eine Arduino MEGA sind 4800byte in einem Array verbraucht zuviel.

Dein Problem ist daß (1/3)*pi) und (2/3)*pi) 0 ergibt weil 1/3 bzw 2/3 zu 0 gerundet wird. Du mußt 1.0/3.0 schreiben).

Auch wenn Du einen Timer Interrupt verwendest kannst Du die 6 Phasen durch einen offset im Index realisieren. So brauchst Du nur ein Array. Nur durch Negierung und Addition eines Offset der 2. Halbwelle bzw spiegeln der 1. Halbwelle brauchst Du eine Wertetabelle für 1/4 der Sinuswelle.
Benutze eine Anzahl der Elemente der Wertetabelle die durch 60 teilbar ist.
grüße Uwe

Dein Problem ist daß (1/3)*pi) und (2/3)*pi) 0 ergibt weil 1/3 bzw 2/3 zu 0 gerundet wird

Endlich mal jemand, der genau hinschaut!

Vielen Dank an uwefed.
Das Problem ist gelöst. Ich wusste nicht, dass Arduino dies als Int rechnet.
Ich erhalte nun 6 Wunderebare veschobene Sinus-Tabellen.

Desweiteren verstehe ich trotzdem nicht, weshalb ihr uch an den 6 Tabellen stört.
Ich habe einbischen rumprobiert und es wäre möglich die um 180° versetzte Sinus-Tabellen einfacher zu berechnen und mir zu ersparren. Aber wenn ich grade einmal bei 61% Auslastung bin habe ich doch noch genug Platz.
Kritisiert ihr dies, weil es bei größeren Programmierungen es unvorteilhaft wäre soviel Speicherplatz zu verschwenden oder hat es grobe Auswirkungen auf den Programmablauf?

jerry134:
Kritisiert ihr dies, weil es bei größeren Programmierungen es unvorteilhaft wäre soviel Speicherplatz zu verschwenden oder hat es grobe Auswirkungen auf den Programmablauf?

Wenn man nicht aufpasst und das Projekt erweitert wird, ist man schnell mit den Arrays über dem maximalen Speicherplatz gelangt. Das mäkelt der Compiler nicht unbedingt an, statt dessen gibt es unerklärliche, nicht unbedingt reproduzierbare Programmabstürze, seltsame Ergebnisse oder Ausführungsfehler. In der Folge sucht man sich einen Wolf.

Wir wissen nicht, warum du überhaupt einen Mega2560 brauchst (wegen der 8kB RAM ?).
Oder wofür das Ganze überhaupt gut ist.

Und du hast recht, ob der vorhandene Speicherplatz ungenutzt ist oder die fast gleiche Tabelle mehrfach geladen ist, macht keinen Unterschied.
Die Upload-Zeit ist auch egal.

OK, wenn du bei der eigentlichen Aufgabe des Mega2560 nicht an RAM-Grenzen kommst, ist es egal. Wenn doch, weißt du wo die Reserven sind;)
Wie Theseus schon schrieb: RAM Überlauf ist gern mal ein schwer zu entdeckendes Problem.

Wieso soll(en) die Tabelle(n) überhaupt in den RAM?

Okay, vielen dank für die hilfreichen Antworten.

Die ganzen Tabellen werden angefertigt, um eine PWM für einen Asynchronmotor zu machen.
Dabei wird eine Dreieck-Sinus-Simulation zur PWM Ermittlung benutzt.
Da ich nicht jedes mal exakt einen Interrupt bekommen kann, wenn sich der Dreieck und der Sinus schneiden, habe ich mir gedacht ich taste das mit einer gewissen Rate ab.
Momentan halt 400 mal die Frequenz von meinen Sinus. Die Abtastrate bestimme ich mit einem Timer und ich habe bereits einmal versucht innerhalb der ISR mir die Sinus Werte direkt zu errechnen, jedoch dauerte dies zu lange. Deshalb wollte/habe ich den Sinus ausgelagert in einer Tabelle um innerhalb der ISR nur auf ein Array zuzugreifen.

Hallo,

Whandall meint damit, dass du die vorberechneten Sinuswerte auch in den Flashspeicher schreiben kannst und damit deinen RAM frei hälst. Stichwort progmem. Du liest die arrays im Programm ja nur noch aus. Aus Flash lesen kann aber unter Umständen etwas mehr Zeit kosten. RAM wird wohl etwas schneller sein. Ob das stört kommt drauf an.

Ich sag’s nur ungern nochmal, aber so wird das nichts, zumindest nicht mit einem Mega :frowning:

Ich hatte schon in einem der vorhergehenden Threads gepostet, daß so ein Controller bei 36 Stützstellen pro Schwingung und direkter Ausgabe von 8 Bit auf einen Port und freilaufend (ohne exaktes Timing) auf maximal 11kHz für 1 Signal kommt (getestet). Nimmt man noch die Zeitsteuerung und den Vergleich mit dem Dreieck dazu, und das 6 mal, dann wird man nicht weit über 50Hz kommen.

Wie es trotzdem gehen könnte, hatte ich auch schon mehrfach gepostet, das wiederhole ich jetzt nicht nochmal. Wenn auch sonst kein Lerneffekt oder auch nur Bereitschaft zum Lernen feststellbar ist, klinke ich mich hier aus. Wem nicht zu raten ist, dem ist auch nicht zu helfen :-(

jerry134:
Desweiteren verstehe ich trotzdem nicht, weshalb ihr uch an den 6 Tabellen stört.
Ich habe einbischen rumprobiert und es wäre möglich die um 180° versetzte Sinus-Tabellen einfacher zu berechnen und mir zu ersparren. Aber wenn ich grade einmal bei 61% Auslastung bin habe ich doch noch genug Platz.
Kritisiert ihr dies, weil es bei größeren Programmierungen es unvorteilhaft wäre soviel Speicherplatz zu verschwenden oder hat es grobe Auswirkungen auf den Programmablauf?

Zuviel Speicherverbrauch. die 61% von 8KByte RAM ist nicht der ganze RAMverbrauch Der Microcontroller verbraucht auch dynamich während der ausführung des Sketches RAM zB Serial.print("Hallo"); verbraucht auch RAM weil es "Hallo" zuerst vom Flash Speicher ins RAm kopiert und dann ausgiebt.

Der Stack für Rücksprungadressen und ähnliches wird auch nicht in die 61% gerechnet

Grüße Uwe