Forum: Mikrocontroller und Digitale Elektronik Modulierter Sinus geht nicht - brauche Hilfe


von C. L. (calle)


Lesenswert?

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:
1
uint32_t sine_val_50[200];
2
uint32_t sine_val_183[55];
3
uint32_t sine_val_50add183[200];
4
.
5
.
6
.
7
void sin50()
8
{
9
  for (int i=0; i<200; i++){
10
             sine_val_50[i] = ((sin(i*2*PI/200) + 1)*4095/4)); //etwa 100%
11
  }
12
}
13
14
void sin183()
15
{
16
  for (int i=0; i<55; i++){
17
    sine_val_183[i] = ((sin(i*2*PI/55) + 1)*(4095/26)); // ca. 5%
18
  }
19
}
20
21
void sin50add183()
22
{
23
    int i=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:
1
// Takt dieser Rechnungen alle 833us
2
time = time+(1.0/CALCFREQ);
3
if (!HAL_GPIO_ReadPin(B1_GPIO_Port, B1_Pin)) {Rip=1;} else {Rip=0;}
4
x = arm_sin_f32((RIP_OMEGA*time+U_ANGLE)*RIP_AMPL);
5
x *= 0.06; // Abschwächung
6
if (Rip) {x=x;} else {x=0.0f;}
7
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.

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

von Matthias S. (Firma: matzetronics) (mschoeldgen)


Lesenswert?

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

: Bearbeitet durch User
von C. L. (calle)


Lesenswert?

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

von Benedikt S. (Gast)


Lesenswert?


von Falk B. (falk)


Lesenswert?

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"

: Bearbeitet durch User
von Sebastian S. (amateur)


Lesenswert?

Frage an Radio Eriwan: Frequenz- oder Amplitudenmodulation?

Sollte man schon wissen.

von C. L. (calle)


Angehängte Dateien:

Lesenswert?

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

von Falk B. (falk)


Angehängte Dateien:

Lesenswert?

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.

von Christoph db1uq K. (christoph_kessler)


Lesenswert?

>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.

von C. L. (calle)


Angehängte Dateien:

Lesenswert?

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

von Matthias S. (Firma: matzetronics) (mschoeldgen)


Lesenswert?

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.

: Bearbeitet durch User
von Achim S. (Gast)


Lesenswert?

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.

von C. L. (calle)


Angehängte Dateien:

Lesenswert?

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:
1
//50Hz mit Offset für DAC - nur positiver Bereich
2
erg50 = (uint32_t) (1500 * arm_sin_f32(i * M_PI/1151.707)+2030);
3
//183Hz
4
erg183 = (uint32_t) (50 * arm_sin_f32(i * M_PI/314.159)); 
5
// Stufung
6
i = i+2;
7
// Auf Knopfdurch addieren, abfangen und ausgeben
8
if (!HAL_GPIO_ReadPin(B1_GPIO_Port, B1_Pin)) {erg=erg183+erg50;} else {erg=erg50;}
9
if (erg > 4095) {erg = 4095;} if (erg < 0) {erg = 0;}
10
HAL_DAC_SetValue(&hdac, DAC_CHANNEL_1, DAC_ALIGN_12B_R, erg);
11
// delay zum anpassen der Frequenz

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

von Matthias S. (Firma: matzetronics) (mschoeldgen)


Lesenswert?

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.

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.