Hallo zusammen, Ich arbeite momentan mit dem TMS320C6713 und möchte gerne mittels EMDA über die Serielle Schnittstelle einen, bzw. mehrere überlagerte Sinus Wellen ausgeben. Zur Erzeugung der Sinuswelle benutze ich eine abgewandelte Version der DDS mit Lanczos-Interpolation zwischen den Stützwerten meiner LUT. Die Funktion funktioniert soweit einwandfrei. Lediglich die Ausführungszeit lässt deutlich zu wünschen übrig! So benötige ich ohne Optimierung durchschnittlich 15ms und mit höchstem Optimierungsgrad 9ms für eine Welle. Die Zeit liegt jedoch deutlich über der Zeit die ich benötige um meinen Ping/Pong Puffer auszugeben! Kann vlt. jemand mal über den Code schauen und ggf. Laufzeitoptimierungs- Vorschläge geben? Ehrlich gesagt, kann ich mir nicht vorstellen, dass ich für (momentan) 960 Werte a 4 Lanczos Splines über 15ms benötige!!! Mit freundlichen Grüßen, Florian
Habe vor Jahren diese CPU in einem Projekt verwendet und dabei fällt mir zu deinen listings folgendes ein: Ich habe damals für meine DSP-Berechnungen nur float (nicht double) verwendet. Das ist glaube ich schneller als double und verbraucht auch weniger RAM. Du solltest einmal überlegen ob du wirklich diese hohe Genauigkeit überall brauchst. Eigene code-optimierung ist zwar möglich über diverse Optionen, aber wirklich nicht einfach. So richtig ging erst die Post ab mit den von TI hand-optimierten Routinen aus den DSP-Libraries. If's in Schleifen sind (so viel ich mich erinnere) für die Geschwindigkeit tödlich! Überlege dir ob du nicht statt deiner Interpolation eine Samplerateconversion mit Filter verwenden kannst und die entsprechenden DSP-Libs verwenden kannst. Mag beim ersten Blick langsamer ausschauen, muß es aber nicht sein.
DDS ist doch prädestiniert dafür mit table-lookup zu arbeiten. Ich verstehe gar nicht warum du außer add+accumulate viel rechnen musst. Der TMS6713 hat jede Menge internes RAM um eine große Sinus-Tabelle abzulegen.
@Fritz: Danke für den Hinweis mit float, ich werde es die Tage mal ausprobieren. Bezüglich der Schleifen, habe ich eine neue Funktion geschrieben die komplett ohne schleifen aber dafür mit einigen if's mehr auskommt. Die Ausführungszeit verringert sich um ca. 5ms! Aber für die Eigentliche Aufgabe ist es halt immer noch deutlich zu langsam. @Helmut: Ja da haben Sie durch aus recht, jedoch sollte hier extra die LUT klein gehalten und die Zwischenwerte interpoliert werden. Ich habe die Aufgabe bereits mittels IIR-Filter gelöst, dafür rufe ich aber einmal den cos für den Koeffizienten und den sin für die Amplitudenkorrektur. Und benötige lediglich 500us für 1000Werte. Nach meinem Verständnis müsste die DDS Methode, selbst mit Interpolation, schneller sein als der IIR-Filter. Ist aber >22mal langsamer. Gründe sind für mich als Anfänger jedoch nicht ersichtlich.
Florian A. schrieb: > Ich habe die Aufgabe bereits mittels IIR-Filter gelöst, dafür rufe ich > aber einmal den cos für den Koeffizienten und den sin für die > Amplitudenkorrektur. Und benötige lediglich 500us für 1000Werte. Habe ich leider nicht verstanden wie das funktioniert. Florian A. schrieb: > Nach meinem Verständnis müsste die DDS Methode, selbst mit > Interpolation, schneller sein als der IIR-Filter. Ist aber >22mal > langsamer. > > Gründe sind für mich als Anfänger jedoch nicht ersichtlich. Wenn du die Geschwindigkeit mehr ausreizen möchtest solltest du deine IDE so konfigurieren, dass die Assemblerlistings deines C-Programms erhalten bleiben. Dann solltest du ein paar einfache Test schreiben und du wirst wahrscheinlich erstaunliches vorfinden. Besonders die Paralellisierung von Schleifen ist eindrucksvoll. So kann es vorkommen, dass bei entsprechender Optimierung eine Schleife die 1000* durchlaufen wird der tatsächliche Code nue 500* oder gar nur 250* mal durchlaufen wird, weil die Rechnungen auf die mehrfach vorhandenen ALUs aufgeteilt wird. Jedes if in diesen Schleifen erschwert aber die Paralellisierung bzw. macht sie unmöglich! Weiters würde ich ganz simple erst einmal messen wie lang eine 1000er Schleife für den sinus alleine benötigt (glaube mich zu erinnern man muss dann y = fsin(x) verwenden). Als nächstes würde ich auch noch ausprobiere um zu testen wie weit die Optimierung erfolgreich war: loop: y[n] = fsin(x) y[n + 1] = fsin(x + dx) y[n + 2] = fsin(x + 2 * dx) y[n + 3] = fsin(x + 3 * dx) schleifenwiederholung zu loop PS: Ich denke, dass das direkte Berechnen der Sinuswerte ohne Tabellenlookup und Interpolation schnell genug sein sollte.
Fritz schrieb: > Florian A. schrieb: >> Ich habe die Aufgabe bereits mittels IIR-Filter gelöst, dafür rufe ich >> aber einmal den cos für den Koeffizienten und den sin für die >> Amplitudenkorrektur. Und benötige lediglich 500us für 1000Werte. > > Habe ich leider nicht verstanden wie das funktioniert. > Mit Hilfe eines Grenzstabilen IIR-Filter lässt sich ebenfalls eine Sinus Schwingung erzeugen. Der Koeffizient des Filters berechnet sich mithilfe eines Sinus. Der Amplitudengang wir mit Hilfe eines Cousins Terms korrigiert:
1 | void IIR(Int16 *buffer, double Amp, Int16 Freq) |
2 | {
|
3 | int ii; |
4 | coef = 2* cos(2* PI * Freq / F_CLK); |
5 | ampcorrect = sin( PI * Freq / F_CLK); |
6 | |
7 | for(ii=0; ii<OUT_SIZE; ii++) |
8 | {
|
9 | *(buffer+ii) = Amp * calculate_sample(); |
10 | }
|
11 | }
|
12 | double calculate_sample() |
13 | {
|
14 | y0 = coef * y1 - y2; |
15 | y2 = y1; |
16 | y1 = y0; |
17 | return ampcorrect * y0 * 32767; |
18 | }
|
Hierbei wird eine sin und cos Berechnung durchgeführt. Die möchte man ja eigentlich vermeiden. Bei dieser Variante der Signalerzeugung wird sie lediglich einmal verwendet. Wie auch immer, vielen Dank für den Hinweis mit dem float-Werten. Habe alle Einzelteile durch gemessen und verblüffende Erkenntnisse gezogen! Konnte jetzt die Variante ohne Schleifen, lediglich unter Verwendung von if-Anweisungen, der Lanczos-Interpolation mit float-Funktionskopf und interner Berechnung mit double, die Zeit ohne Optimierung auf 7.896us und mit Optimierung auf sagenhafte 449us drücken! Vielen Dank noch mal :) PS: Habe auch die Variante mit dem sin() getestet, fsin() konnte ich nicht finden. Resultat: ohne Opti: ~10180us; mit opti: ~4360us
Du solltest nochmal einen Blick hierauf werfen, wegen Symmetrie zur X-Achse und geschickter Spiegelung der Quartile, wenn du bei der Tabelle bleibst. http://www.mikrocontroller.net/articles/Digitale_Sinusfunktion Ferner kannst Du die Vielfachen einfach mehr Multiplikation errechnen.
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.