Hallo zusammen,
..habe mich verrannt und benötige mal Unterstützung.
Ich benötige vom DAC des STM32F446 (Nucleo & CubeIDE) einen Sinus von 50
Hz der auf Knopfdruck moduliert wird mit 183Hz. Habe Ansätze aber komme
nicht weiter. 1 Ansatz:
in einer Tabelle werden beide Signale einmal errechnet abgelegt. Auf
Knopfdruck wird dann der 50Hz Sinus mit 183Hz addiert und dann dem DAC
übergeben. Das geht, aber die Modulation der 183 auf den 50 Hz ist starr
und nicht fortlaufend.
siehe Auszug:
sine_val_183[i]=((sin(i*2*PI/55)+1)*(4095/26));// ca. 5%
18
}
19
}
20
21
voidsin50add183()
22
{
23
inti=0,j=0;
24
25
for(i=0;i<200;i++)
26
{
27
sine_val_50add183[i]=sine_val_50[i]+
28
sine_val_183[j];
29
if(i==54){j=0;}else{j++;}
30
if(i==109){j=0;}
31
if(i==164){j=0;}
32
}
33
}
in der Main wird dann nach erfolgter Initialisierung der HAL Komponenten
beides verrechnet und auf Knopfdruck der normale 50Hz oder der
modulierte Sinus dem DAC übergeben. Fehlerbild ist dann halt wie oben
beschrieben "starr" und noch fortlaufend.
Mein 2ter Ansatz war "on the Fly" berechnen, angelehnt an die AN5046 von
Freescale.
Hier wird im 1200Hz (833us) Takt ein 50Hz Sinus berechnet und mit 183Hz
moduliert.
Habe allerdings die Sinus Berechnungen nicht aus der math.h sondern aus
der CMSIS DSP Library genommen - sind deutlich schneller!
Hier der Auszug:
y ist float; wird dann in INT normiert für den DAC und ausgegeben.
Das geht auch halbwegs aber ich komme mit der Frequenz nicht höher als
ca. 40Hz - egal was ich an Takt Möglichkeiten so einstelle in CubeMx.
Wie stellt man sowas am besten an?
Könnt Ihr mir mal Ideen geben?
Zusammenfassung. Ich benötige den ständigen via DAC ausgegebenen 50Hz
Sinus und auf Knopfdruck soll dieser dann 183Hz moduliert sein. Wird der
Knopf losgelassen, entfällt die Modulation und es sind wieder nur die
reinen 50Hz da. Hinweis: Es wird nichts anderes im Programm gemacht als
diese Geschichte. Also jegliche Lösungsansätze sind willkommen. Es muss
auch unbedingt DMA Zugriff sein, hatte ich nur gewählt um das mal zu
lernen.
Mit der Bitte um Unterstützung.
...bleibt zuversichtlich in diesen Zeiten ;-)
Gruß..
Carsten
Matthias S. schrieb:> AN_1982 (die alte AVR314) Application Note beschreibt die Erzeugung von> DTMF Tönen mit kleinen MC, der STM32 macht das so nebenher.> https://www.microchip.com/wwwAppNotes/AppNotes.aspx?appnote=en591264
Ok, danke -> habe ich mir angesehen. Ich würde aber nicht den Umweg über
PWM und LC dahinter gehen wollen, sondern direkt den DAC nutzen. Habt
Ihr weitere Ansätze bevor ich sowas implementiere?
CL
C. L. schrieb:> Ich benötige vom DAC des STM32F446 (Nucleo & CubeIDE) einen Sinus von 50> Hz der auf Knopfdruck moduliert wird mit 183Hz.
Eher anders herum, ein 183Hz Sinus wird durch 50Hz moduliert.
> Habe Ansätze aber komme> nicht weiter. 1 Ansatz:> in einer Tabelle werden beide Signale einmal errechnet abgelegt. Auf> Knopfdruck wird dann der 50Hz Sinus mit 183Hz addiert und dann dem DAC> übergeben.
Das ist aber keine Modulation sondern Addition.
> Das geht, aber die Modulation der 183 auf den 50 Hz ist starr> und nicht fortlaufend.
Was meinst du mit starr?
> in der Main wird dann nach erfolgter Initialisierung der HAL Komponenten> beides verrechnet und auf Knopfdruck der normale 50Hz oder der> modulierte Sinus dem DAC übergeben. Fehlerbild ist dann halt wie oben> beschrieben "starr" und noch fortlaufend.
???
> Mein 2ter Ansatz war "on the Fly" berechnen, angelehnt an die AN5046 von> Freescale.> Hier wird im 1200Hz (833us) Takt ein 50Hz Sinus berechnet und mit 183Hz> moduliert.
Da muss man nix berechnen, man lies eine Tablle aus.
> Habe allerdings die Sinus Berechnungen nicht aus der math.h sondern aus> der CMSIS DSP Library genommen - sind deutlich schneller!
AUA!!!
> Hier der Auszug:// Takt dieser Rechnungen alle 833us> time = time+(1.0/CALCFREQ);> if (!HAL_GPIO_ReadPin(B1_GPIO_Port, B1_Pin)) {Rip=1;} else {Rip=0;}> x = arm_sin_f32((RIP_OMEGA*time+U_ANGLE)*RIP_AMPL);> x *= 0.06; // Abschwächung> if (Rip) {x=x;} else {x=0.0f;}> y = ((arm_sin_f32(LINE_OMEGA*time+U_ANGLE)*LINE_AMPL)+x);> y ist float; wird dann in INT normiert für den DAC und ausgegeben.> Das geht auch halbwegs aber ich komme mit der Frequenz nicht höher als> ca. 40Hz - egal was ich an Takt Möglichkeiten so einstelle in CubeMx.
Akademischer Unsinn. Das geht DEUTLICH einfacher und mit DEUTLICH
weniger CPU-Belastung.
> Wie stellt man sowas am besten an?> Könnt Ihr mir mal Ideen geben?
Mit DDS und Tabellen.
Beitrag "H-Bridge 50Hz Sinus - LC Filter dimensionieren"Beitrag "Re: SPWM auf Atmega8, bitte um Feedback hinsichtlich Optimierung"> Zusammenfassung. Ich benötige den ständigen via DAC ausgegebenen 50Hz> Sinus und auf Knopfdruck soll dieser dann 183Hz moduliert sein.
Das Modulationssignal ist bei AM in der Regel DEUTLICH niederfrequenzer
als der Träger.
> diese Geschichte. Also jegliche Lösungsansätze sind willkommen. Es muss> auch unbedingt DMA Zugriff sein, hatte ich nur gewählt um das mal zu> lernen.
Da feht ein "nicht"
Falk B. schrieb:> Da feht ein "nicht"
Ja stimmt, es sollte heißen "Es muss
auch nicht unbedingt DMA Zugriff sein"
Danke ;-)
Mit starr meine ich das die 183Hz den Grundsinus 50Hz nur verbiegen und
es nur eine verbogene statische Kurve auf dem Oscar ist. Eigentlich
müsste diese sich auf der Linie bewegen, da ja 183 schneller sind als
50. es muss also Bewegung erkennbar sein, es sind ja 2 ursprüngliche
Quellen.
Im Klartext geht es um die Nachbildung eines Rundsteuersignals und da
ist der Netzsinus, der taktweise mit den 183Hz verrechnet wird. In der
Praxis wird die höhere Frequenz eingekoppelt auf höheren
Spannungsebenen. Der Takt dieser Einkopplungen ist dann das eigentliche
Rundsteuertelegramm.
In einem anderen Projekt sollten diese 183Hz Impulse wieder
herausgefiltert werden. Wahrscheinlich trifft Addition das Ganze
wirklich besser statt Modulation. Aber ist das Ergebnis dann nicht
amplitudenmoduliert? Es verschiebt doch die Amplitude.
Habe noch ein Foto (Quelle: Internet) angehangen in dem man das erkennt.
Sind nicht 183Hz, aber das Prinzip ist erkennbar !
Bzgl. AN3126 -> da steht ja die DAC via DMA Verbindung
niedergeschrieben.
Läuft ja hier auch.
Warum "AUA" bei der CMSIS DSP Lib?
Falk B. schrieb:> Akademischer Unsinn. Das geht DEUTLICH einfacher und mit DEUTLICH> weniger CPU-Belastung.>>> Wie stellt man sowas am besten an?>> Könnt Ihr mir mal Ideen geben?>> Mit DDS und Tabellen.
Habe ich nur so übernommen aus der AN5064...
DDS werde ich mir anschauen.
Erstmal danke und schöne Weihnachten wünsche ich.
PS: habe das Bild versehentlich 2 mal angehängt - einmal nicht mehr raus
bekommen. Sry
Carsten
C. L. schrieb:> Mit starr meine ich das die 183Hz den Grundsinus 50Hz nur verbiegen und> es nur eine verbogene statische Kurve auf dem Oscar ist.
Die du uns eigentlich zeigen solltest.
> Im Klartext geht es um die Nachbildung eines Rundsteuersignals und da> ist der Netzsinus, der taktweise mit den 183Hz verrechnet wird.
Schon wieder eine total konfuse Wortwahl!
> In der> Praxis wird die höhere Frequenz eingekoppelt auf höheren> Spannungsebenen. Der Takt dieser Einkopplungen ist dann das eigentliche> Rundsteuertelegramm.
AHA!
Also wird das 183Hz Signal dem 50Hz Signal überlagert. Das macht eine
Addition.
> In einem anderen Projekt sollten diese 183Hz Impulse wieder> herausgefiltert werden. Wahrscheinlich trifft Addition das Ganze> wirklich besser statt Modulation.
In der Tat!
> Aber ist das Ergebnis dann nicht> amplitudenmoduliert?
Nein.
> Es verschiebt doch die Amplitude.> Habe noch ein Foto (Quelle: Internet) angehangen in dem man das erkennt.> Sind nicht 183Hz, aber das Prinzip ist erkennbar !
Das ist eine Überlagerung zweier Sinussignale. So schön sieht das aber
nur aus, wenn die Frequenzen deutlich auseinander liegen. Bei 50/183Hz
ist das nicht ganz so. Siehe Anhang.
grün: Multiplikation (Amplitudenmodulation)
rot: 50Hz
blau: 183Hz
gelb: Addition (Überlagerung)
Wenn man die 183Hz auf z.B.. 1kHz erhöht, sieht das dann so aus, siehe
Anhang.
> Warum "AUA" bei der CMSIS DSP Lib?
Technischer Overkill, das geht deutlich einfacher.
>> Akademischer Unsinn. Das geht DEUTLICH einfacher und mit DEUTLICH>> weniger CPU-Belastung.
>Nachbildung eines Rundsteuersignals
das dürfte eben keine Modulation sein, sondern ein simples Aufaddieren.
FM oder AM wäre komplizierter, das sind nichtlineare Vorgänge. Für AM
ein Multiplizierer, und FM wirds schwierig, da die Netzfrequenz vom
E-Werk stammt, dafür bräuchte man einen modulierbaren Frequenzumrichter.
Leute, ich bekomme das einfach nicht hin...
habe nun einen Sinus einmal erzeugt im Speicher liegen mit 360
Stützstellen als float. Könnte man auch anders machen; später.
1
// Sinus berechnen 360 Stützstellen und zwischen -2048...2048 Amplitude angepasst
2
for(i=0;i<360;i++)
3
sinus[i]=1800*arm_sin_f32(i*M_PI/180.);
je nach dem wie schnell ich dieses dann dem DAC übergebe hätte ich auch
die entsprechende Frequenz auf dem Oscar. Momentan habe ich das mit eine
qick&dirty for Schleife als Zeitverzögerung, später dann mit TMR2
Interrupt. Soweit so gut. Amplitude kann ich auch verändern. Wie muss
ich das nun anstellen, das diese Grundschwingung mit der höheren
Frequenz überlagert wird?
Da die 183Hz zu den 50Hz ja in ungeradem Verhältnis stehen (3,66) muss
die Überlagerung doch auf den 50Hz "wandern". Ich meine die 50Hz bleiben
aber die Überlagerung passiert doch immer an einer anderen Stelle an der
Kurve. Wenn ich das einmal fest berechne dann ist diese Überlagerung
doch immer an der gleichen Stelle, quasi wie ein Foto. @Falk... Du weißt
doch was ich meine. Helfe mir doch mal bitte um das irgendwie zu lösen.
Falk B. schrieb:> Da muss man nix berechnen, man lies eine Tablle aus.
Ziel soll es ja sein die Kurve im Speicher abzulegen und dann dem DAC
übergeben. Das ist nun der Fall, aber die stetige Addition und der Weg
das anzustellen im Programm; das ist der Knackpunkt.
Falk B. schrieb:> Die du uns eigentlich zeigen solltest.
...hängt an
MfG
Carsten
C. L. schrieb:> Wie muss> ich das nun anstellen, das diese Grundschwingung mit der höheren> Frequenz überlagert wird?
Genau das steht in AVR314. Addiere die beiden Werte.
Um auf die Werte zu kommen, klapperst du die Tabelle mit 2 Timern durch.
Da du nun 360 Punkte hast, läuft also der eine Timer mit Timerbreite x
360 x 50 Hz und der andere Timer mit Timerbreite x 360 x 183 Hz.
Daran kannst du mit dem Vorteiler und den Periodendauern wurschteln, bis
das genau passt.
Bei Überlauf wird der Tabellenwert geholt, gespeichert und mit dem
anderen Wert aus der zweiten Timerroutine (aus seinem Überlauf) addiert.
Das schreibste auf den DAC. Jeder Timer hat dabei seinen eigenen Zeiger
in die Sinustabelle.
Das ist nur einer von vielen Wegen.
C. L. schrieb:> habe nun einen Sinus einmal erzeugt im Speicher liegen mit 360> Stützstellen als float. Könnte man auch anders machen; später.> // Sinus berechnen 360 Stützstellen und zwischen -2048...2048 Amplitude> angepasst> for(i=0;i<360;i++)> sinus[i] = 1800 * arm_sin_f32(i * M_PI/180.);>> je nach dem wie schnell ich dieses dann dem DAC übergebe hätte ich auch> die entsprechende Frequenz auf dem Oscar. Momentan habe ich das mit eine> qick&dirty for Schleife als Zeitverzögerung, später dann mit TMR2> Interrupt. Soweit so gut. Amplitude kann ich auch verändern. Wie muss> ich das nun anstellen, das diese Grundschwingung mit der höheren> Frequenz überlagert wird?
Zuerst mal: wähle für die Anzahl der Stützstellen nicht 360, sondern
eine Zweierpotenz (z.B. 512). Das ist für die DDS-Implementierung etwas
praktischer.
C. L. schrieb:> Stützstellen als float. Könnte man auch anders machen; später.
Mache es doch gleich, dein DAC will sicher nicht mit float angesteuert
werden. Du darfst Einzelwerte der Sinustabelle ja meinetwegen mit float
ausrechnen. Aber das Array machst du vom Typ int16 und rundest dein
float-Ergebnis vor der Zuweisung zum integer array.
Als nächstes besorgst du dir eine vernünftige Zeitbasis. Keine
For-Schleife zur Verzögerung, sondern ein Timerinterrupt, z.B. im
Abstand von 500µs. Die ISR wird also im Takt von 2kHz aufgerufen.
Wenn du in jedem Interrupt einen Momentanwert für den 50Hz-Sinus aus der
Tabelle auslesen willst, müsstest du also die gesamte Wertetabelle in 40
Schritten durchlaufen. (1/50Hz=20ms, 20ms/50µs=40).
Also erzeuge dir in einem ersten Schritt einen 9 Bit Zähler akku50 (der
allgemeine Begriff dafür ist Phasenakkumulator, 9 Bit werden im ersten
Ansatz wegen der 512 Stützstellen gewählt). Zähle in jedem Interrupt
512/40=13 zu diesem Zähler dazu (dieser Wert von 13 heißt bei DDS-ICs
"Frequency Tuning word"). Und lies in der ISR dann sinus[akku50] aus dem
Array aus, um den 50Hz Sinus zu erzeugen.
Blöderweise lässt sich 512 nicht ohne Rest durch 40 teilen, das exakte
Ergebnis ist nicht 13 sondern 12,8. Wenn du tatsächlich jedesmal 13 zu
akku50 dazuzählst, bekommst du keine 50Hz sondern bist etwas schneller
(50,8Hz). Deswegen wird jetzt die Auflösung des Phasenakkumulators
erhöht. Statt eines 9Bit Werts für akku50 wählst du z.B. einen
uint16-Wert (also 128 mal mehr). In jeder ISR addierst du jetzt nicht
mehr 13 zu akku50, sondern 12,8*128=1638. Und du benutzt jeweils die
obersten 9 Bit von akku50 als Index auf dein Array.
Deine Tabelle der Stützstellenwerte gibt dir dann jeweils den
Momentanwert eines 49,99Hz Sinus, der zum jeweiligen Zeitpunkt der ISR
gehört - das ist hoffentlich nahe genug an den gewünschten 50Hz. Wenn
nicht, musst du die Auflösung des Phasenakkumulators halt weiter
erhöhen. 24Bit Phasenauflösung sind bei DDS-Anwendungen nicht unüblich
und für deinen STM32 auch kein Problem.
Dasselbe machst du mit einem zweiten Zähler akku183. Den erhöhst du in
jeder ISR um 5997 (183Hz/2kHz*2^16). Wenn du die obersten 9 Bit von
akku183 als Index auf deine Stützstellen benutzt, erhältst du bei jedem
ISR-Aufruf die Momentanwerte eines Sinus von 183,01Hz.
Du addierst die Momentanwerte des 50Hz-Sinus und des 183-Hz Sinus und
gibst die Summe auf deinen ADC aus. Das war's.
Wenn deine beiden Zähler (bzw. Phasenakkumulatoren) überlaufen ist das
nicht schlimm: wenn der Phasenwinkel des Sinus z.B. bei 362° steht,
kannst du ihn stattdessen ja auch wieder bei 2° weiterlaufen lassen -
genau das passiert beim Überlauf von akku50 und akku183.
Und wenn du diesen DDS-Ansatz überhaupt erst mal zum Laufen bekommen
hast, dann kannst du anfangen zu optimieren. Z.B. die
Symmetrieeigenschaften des Sinus nutzen, um die Tabelle der
Stützsstellen auf das wirklich notwendige Ausmaß zu reduzieren. Und die
Auflösungen (Anzahl der Stützstellen, Breite der Phasenakkumulatoren und
Taktung der Timer-ISR) so wählen, dass es für eine Anwendung gut passt.
Hey...
viiieeelen besonderen Dank erstmal für die Beiträge Achim und Matthias.
Diese sind ja extrem aufschlussreich.
Nun ist mir das Grundprinzip klarer geworden. Bei deinem Ansatz,
Matthias, hast Du nur einen Sinus frequenzunabhängig im Speicher liegen;
richtig?
Diesen ließt Du dann mit 2 verschieden Takten aus. Das habe ich in der
AVR314 nicht so verstanden.
Matthias S. schrieb:> Jeder Timer hat dabei seinen eigenen Zeiger> in die Sinustabelle
Das ist ein Stichwort.
Auch die Lösung von Achim werde ich mir mal reinziehen, viele wertvolle
Hinweise, kommt man alleine gar nicht drauf.
Ich war zwischenzeitlich auch tätig und gebe mal meine "unschöne" Lösung
her.
Unschön weil hingefummelt, finde da Eure Ansätze professioneller. Ist
aber hier auch nur für den Hobbytisch.
Ich berechne mir die Sinuswerte in der Main. Der IC macht sonst nix
anderes.
Auszug des wesentlichen:
Das könnte man auch schlanker machen aber erstmal funktioniert das.
Siehe Bild. Ich werde die anderen Lösungen demnächst mal implementieren.
Bisher viel gelernt in diesem Thread bzgl. Begriffe, und do´s & dont´s.
Danke an alle die hier geantwortet & geholfen haben.
LG Carsten
Der ganze Floating Point Krams ist dann überflüssig, wenn du einfach
eine fertige Tabelle nimmst.
Ich lasse mir die Online ausrechnen und hole sie mit Copy&Paste ins
Programm:
https://www.daycounter.com/Calculators/Sine-Generator-Calculator.phtml
Da der DAC im STM32 ein 12-Bitter ist und ich ihn nicht übersteuern
will, würde ich 11-Bit Werte benutzen (Werte bis 2047). Beim Addieren
der beiden Werte tritt dann kein Überlauf ein.
Mach die Tabelle nicht zu lang - die Timer müssen in der Lage sein, sie
183 mal in der Sekunde zu durchlaufen.