Forum: Digitale Signalverarbeitung / DSP / Machine Learning problem mit tms320c6713


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 Andre R. (ltisystem)


Lesenswert?

liebes forum,
ich bin gerade dabei meine ersten filterfunktionen zu implementieren. 
dabei habe ich folgende designkriterien:

16kHz abtastfrequenz, LP, HP, BP, Echo, sowie eine Impulsantwort, die 2 
sekunden lang ist, mit 16kHz abgetastet wurde (also 32k Koeffizienten 
besitzt) und die nachhallzeit 2sek. betragen soll.

die koeffizenten für LP, HP und BP habe ich mir per fdatool von matlab 
berechnen lassen.

Nachdem ich die ersten drei Filter geschafft habe, treten folgenden 
Probleme auf:

1. bei allen Filtern klirrt der Ausgang (könnte das eventuell daran 
liegen, dass ich meine Eingangsignale nicht mit einem analogen LP 
vorfiltere (aliasing-effekt?))

2. ab einer koeffizientenanzahl von |bi|>60 fängt das filter an zu 
spinnen, es hört sich schrecklich an bis es wird fast vollständig 
unterdrückt.

das board schafft bis zu 1,6 GFLOPS/sek., daran sollte es also nciht 
scheitern.

ein codeauszug ist der folgende (einigermaßen kommentiert, benutze einen 
ringbuffer, der so groß ist, wie es koeffizienten gibt). das gesamte 
projekt hängt als zip hinten dran:
1
/*main-Funktion*/
2
void main()
3
{
4
  DSK6713_AIC23_CodecHandle hCodec; //Erstellen eines Codecobjektes
5
  DSK6713_AIC23_Config config = DSK6713_AIC23_DEFAULTCONFIG; //Erstellen einer Conifgurationsdatei
6
  hCodec=DSK6713_AIC23_openCodec(0, &config); //Codec starten
7
  DSK6713_AIC23_setFreq(hCodec, fs); // Set codec frequency to 16KHz
8
  DSK6713_init(); //DSP initialisieren
9
  DSK6713_DIP_init(); //Schalter initialisieren
10
  //
11
  for(k=0;k<test_i;k++){
12
    circ_buffer[k]=0;
13
  }
14
//
15
  while(1)
16
  {
17
    if (DSK6713_DIP_get(0) == 0)
18
    {
19
      float samples[41]; //sample-array
20
      float result = 0.0; //Ergebnisvariable zur Summation
21
      while(!DSK6713_AIC23_read(hCodec, &data)); //lesen des Eingabestreams
22
      /*Anfang Algorithmus für FIR-Filter*/
23
      for (a = low-1; a>=1; a--)
24
      samples[a] = samples[a-1]; //Verzögerungselement
25
      temp.combo = data;
26
      samples[0] = (float) temp.channel[0];
27
      for(a = 0; a<low; a++) //Koeffizientenmulitplikation
28
      result += lowpass[a]*samples[a]; //Multiplikation & Aufsummierung
29
      /*Ende Algorithmus*/
30
      while(!DSK6713_AIC23_write(hCodec, (short)result));  //schreiben des Ausgabestreams            
31
    }
32
//...
33
//analog dazu die anderen beiden Filter, nur mit einem anderem filterarray
34
//...
35
    else
36
    {
37
      /*Durchlass wenn kein Schalter gedrückt wird*/
38
      while(!DSK6713_AIC23_read(hCodec, &data));
39
      while(!DSK6713_AIC23_write(hCodec, data));
40
    }
41
  }
42
}

Es scheint ja ein grundlegendes Problem vor zu liegen, aber ich weiß, 
als Anfänger, einfach nicht wo ich ansetzen soll.

Noch eine Frage zum Board:
Ist es prinizpiell möglich, die Eumlatorpins dafür zu verwenden um dort 
Schalter anzulöten und diese dann iwie verwenden zu können? Das könnte 
man eventuell mit Interrupts lösen, wenn der Schalter gedrückt (also ein 
Kanal frei geschalten ist), dann Interrupt der jeweiligen Filterroutine.

Zu Interrupts habe ich bezüglich meines Boards und Filtern auch schon 
etwas gelesen, aber ist das zwingend notwenidg? Läuft das ganze dann 
besser, also ist das auch mein obiges Problem mit dem Klirren und den 
hohen Koeff.anzahlen?

Bin dankbar für jede Antwort!!!

Grüße
Andre

: Bearbeitet durch Admin
von Andre R. (ltisystem)


Angehängte Dateien:

Lesenswert?

sry den anhang und ein paar infos vergessen.

ich benutze das code composer studi 3.1 und matlab r2013a.

Beim dsp-board verwende ich den eingang line-in und den ausgang 
line-out, jweils mit stereo 3,5mm klinke steckern.

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


Lesenswert?

Andre Richter schrieb:
> 1. bei allen Filtern klirrt der Ausgang (könnte das eventuell daran
> liegen, dass ich meine Eingangsignale nicht mit einem analogen LP
> vorfiltere (aliasing-effekt?))

Probier erstmal mit einer einfachen Loop-Through Funktion vom Eingang 
zum Ausgang, wie hoch die Aussteuerbarkeit ist und der Frequenzgang. 
Wenn die Samplerate wirklich nur 16kHz beträgt, ist ein AA-Filter am 
Eingang unvermeidbar, um alles über 8kHz abzuschneiden.
Dann implementiere ein Filter (das kannst du immer noch auf Multi-Tap 
erweitern) und teste dieses.

von Andre R. (ltisystem)


Lesenswert?

danke für die antwort!

ich habe jetzt das ganze mal mit einer samplerate vn 48khz versucht, 
womit der AA-effekt ja eigentlich behoben sein sollte, da mein 
beispielsample von einer CD stammt, welche ja dann keine höheren 
frequenzen als 22khz enthalten dürfte. trotzdem besteht weiterhin das 
problem

grüße

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


Lesenswert?

Andre Richter schrieb:
> result += lowpass[a]*samples[a]; //Multiplikation & Aufsummierung

Dir fehlt hier eine Skalierung. Wenn du bspw. 2 Samples mit je 48 bit 
multiplizierst, kann da ein Ergebnis mit 96 bit Breite herauskommen, was 
dann am Ausgang clippt bzw. übersteuert.
Die Abtastrate lass ruhig gleich bei 48kHz, damit bist du auf der 
sicheren Seite.
Wie klingts denn (und wie ist der Pegel), wenn du per DIP Schalter den 
unteren Teil des Programmes, also die Loop-Through Funktion, benutzt? 
Solange du den AD/DA Wandler nicht überfährst, sollte das nämlich gut 
klingen.

von Andre R. (ltisystem)


Lesenswert?

ja also bei nem tiefpass mit 41 koeffizienten und fstop von 1000khz, 
filter er sauber bzw lässt durch...klingt auch sehr sauber, selbst bei 
der musik, da klirrt nix. aber wehe dem ich man erhöht die koeff-anzahl, 
dann geht es los. das mit dem konvertieren probiere ich mal. danke schon 
mal
grüße :)

von Andre R. (ltisystem)


Lesenswert?

ich habe noch eine frage...

ich habe hier eine 6 sekunden lange wav, die die impulsantwort einer 
kirche enthält...unter matlab nutze ich einfach den befehl conv und 
schon ist mein aufgenommenes stücken ton mit dem kirchenhall belegt...
meine frage:

geht das überhaupt unter echtzeit mit einer zeitbereichsfaltung???

von Fitzebutze (Gast)


Lesenswert?

Hi Andre,

6 Sekunden Impuls in Echtzeit falten ist etwas zuviel und bei einer 
Kirche auch etwas "überdosiert". Ich würde die Echos mit Delays 
nachmodellieren und nur den ersten Sekundenbruchteil bis die 
Koeffizienten gegen Null gehen mit einem FIR realisieren. Kannst du auch 
stückweise machen.
Der Fehler, der dabei entsteht, dürfte nicht hörbar sein, gegenüber dem 
sicher auch nicht perfekten Impuls.

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


Lesenswert?

Andre Richter schrieb:
> geht das überhaupt unter echtzeit mit einer zeitbereichsfaltung???

Fitzebutze hats auch schon gesagt, du brauchst auf deinem System dann 
Speicher für 6 Sekunden Samples und viele Outputpointer, um die Echos zu 
simulieren. Beim Addieren der Pointer ist dann die Wichtung der Delays 
entscheidend und natürlich das Feedback zum Original Signal.
Pionier in der Raumsimulation war eigentlich immer Quantec:
http://www.quantec.com/index.php?id=room_simulation&L=1

Nicht uninteressant.
An deiner Stelle würde ich jetzt mich erstmal auf 2 oder 3 Echopointer 
beschränken und die Skalierung in den Griff bekommen.
Es hilft auch, das 'Clipping Overflow' Bit für Multiplikation zu setzen, 
falls dein TMS320 das hat (mein alter TMS320C25 hats mit dem Mnemonic 
'sovm'). Das sorgt dafür das Überläufe 'graceful' behandelt werden und 
nicht zum kompletten Umschlagen des Resultates führen. Evtl. macht dein 
Kompiler das schon, schau mal in den Projektoptionen.
Der Trick beim Multiplizieren oder Addieren besteht darin, es nicht zu 
Überläufen kommen zu lassen. Das kann man z.B. so machen :
1
result = (wert1+wert2) >> 1; ( Addieren und teilen durch 2)

von Andre R. (ltisystem)


Lesenswert?

Hallo,
das Skalieren probiere ich morgen direkt aus!

Danke noch einmal für die hilfreichen Ansätze.

Ich hab den Code ja weitesgehend aus einem video-tutorial, aber auch in 
anderen codequellen kommt es vor, dass result zum short gecastet wird, 
obwohl die funktion AIC23_write als zweiten parameter ein unsigned in 
erwartet?!?!

Und dann noch einaml zu den Echpointern? Google spuckt mir dazu nicht 
viel brauchbares aus. Ich war der Meingung gelesene zu haben, dass sich 
ein Hall auch mittels eines FIR-Filters realisieren lässt? Ich kann mir 
aber auch grade gar nicht vorstellen, wie das Bodediagramm oder der 
Frequenzgang dazu aussehen soll?

Habe die wave mal mit MATLAB downgesampled auf 16kHz, da ergeben sich 
aber immernoch 96000 koeffizienten, viel zu groß alles -.-

grüße andre

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


Angehängte Dateien:

Lesenswert?

Andre Richter schrieb:
> Ich war der Meingung gelesene zu haben, dass sich
> ein Hall auch mittels eines FIR-Filters realisieren lässt? Ich kann mir
> aber auch grade gar nicht vorstellen, wie das Bodediagramm oder der
> Frequenzgang dazu aussehen soll?

Ich denke, da verwechselst du was. Mit einem FIR kannst Filter basteln 
aber für Echos musst du deine Samples im RAM speichern und nach einem 
(justierbaren) Delay auslesen und mit dem Original (Dry) Signal mischen 
und an den Ausgang legen.
Ich hab dir mal ein simples Echo in TMS Assembler angehängt. AR0 ist der 
Outputpointer, AR1 der Input Pointer und AR2 der Outputpointer.
Andre Richter schrieb:
> Ich war der Meingung gelesene zu haben, dass sich
> ein Hall auch mittels eines FIR-Filters realisieren lässt?

Echo ist zwar auch eine Klangbeeinflussung, aber vor allen Dingen ein 
Delay - du speichert das Orginalsignal und gibst es nach einer Delayzeit 
wieder aus. Für regeneratives Echo speicherst du des Ausgangsignal 
gemischt mit dem Original (DRY) als gewichtete Addition wieder in den 
Samplepuffer.  Wieviele Echos kommen, stellt du dabei vorher wieder über 
eine Multiplikation mit einem 'Knob', also einem Skalierungsfaktor ein.

Wenn du am Ausgang auch noch das DRY Signal hören willst, mischt du ganz 
am Anfang noch dein verzögertes Signal (WET) mit dem DRY.

Hier noch ein Tipp für viele Algorithmen:
http://www.musicdsp.org/showmany.php

: Bearbeitet durch User
von Andre R. (ltisystem)


Lesenswert?

Also in Assembler kenn ich mich nicht so gut aus.

Wenn man es anders begründen kann, könnte es ein FIR sein, nur dass die 
Impulsantwort halt ein aufgenommener Teil von sich selbst ist (und der 
Ausgang NICHT direkt zurück geleitet wird --> IIR) und dann einfach das 
eingangsisgnal mit den aufgenommen schnipseln zeitlich versetzt 
dazugefaltet wird, oder?

also wäre folglich mein erster schritt mir das eingangssignal auf dem 
ram des tms320c6713 dsk für eine bestimmte länge zu speichern (hat da 
vllt schon jemand erfahrung, wie ich den ram beschreiben kann?) und dann 
muss ich das eingangssignal mit dem aufgenommenden und in der amplitude 
verringerten signal aus dem ram falten und wieder auf den ausgang 
schreiben. sind diese überlegungenr ichtig?

Zu dem Skalieren nochmal:

kann ich das skalieren weg lassen, wenn ich floats benutze? (darunter 
stelle ich mir vor, dass ich float x = 3.234254353453E-05 schreibe)

ist es möglich beim skalieren a la >> 1 (also divison durch 2) einen 
geeigneten paramter zu finden, der faustregelmäßig gut passt? vllt sowas 
wie die filterlänge?

Grüße

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


Lesenswert?

Andre Richter schrieb:
> also wäre folglich mein erster schritt mir das eingangssignal auf dem
> ram des tms320c6713 dsk für eine bestimmte länge zu speichern (hat da
> vllt schon jemand erfahrung, wie ich den ram beschreiben kann?)

Das machst du mit einem Ringpuffer, indem der Adresszeiger von RAMSTART 
bis RAMEND läuft. Ist RAMEND erreicht, springt er wieder auf RAMSTART.

> und dann
> muss ich das eingangssignal mit dem aufgenommenden und in der amplitude
> verringerten signal aus dem ram falten und wieder auf den ausgang
> schreiben. sind diese überlegungenr ichtig?

Halb richtig. Ein vom Eingangszeiger unabhängiger Ausgangzeiger 
durchläuft ebenso RAMSTART bis RAMEND und liest den Wert und schickt ihn 
auf den DAC. Gleichzeitig addierst du diesen Wert auf den Eingangswert - 
Der Anteil dieses addierten Wertes bestimmt die Regeneration (Feedback).
Filter kommen hier erstmal nicht vor - das Echo hat den gleichen 
Frequenzgang wie das Original. Der Abstand zwischen Eingangs- und 
Ausgangzeiger bestimmt die Verzögerung des Echos (= Raumgrösse).
Hier hast du die längste Verzögerung, wenn der Ausgangszeiger immer 
direkt vor dem Eingangszeiger läuft und den Wert des letzten Durchlaufs 
ausgibt.

Im nächsten Schritt kannst du dann auf das Signal des Ausgangszeigers 
ein Filter legen (FIR, IIR oder Biquad), bevor du das Signal auf den 
Eingang addierst.
Arbeite dich aber erstmal durch den Echoalgorithmus, Filter kommt dann 
später.

> Also in Assembler kenn ich mich nicht so gut aus.
Das ist hier auch nicht so wichtig, es geht nur um den grundlegenden 
Ablauf.

: Bearbeitet durch User
von Andre R. (ltisystem)


Lesenswert?

Danke Matthias, ich werd mich durch arbeiten!

Das primäre Problem liegt jetzt allerdings noch in der stand-alone 
Lösung, also dass ich den DSP mit Strom versorge und er mein Programm 
automatisch lädt. Da bin ich aber grade noch am recherchieren auf den 
TI-Wikis. Es sei denn jmd kennt eine schnell erklärte Lösung dafür oder 
hat sogar schon ein Tutorial dafür.

Habe jetzt etwas bessere Ergebnisse für den FIR_Filter mit der Ordnung 
100. Das Problem war die Modulorechnung, hab jetzt meinen Buffer mit 
einer Größe einer Zweier-potenz und realisiere das ganze jetzt mit einer 
UND-Verknüpfung.

[edit]: ich würde noch ganz gerne wissen, ob man für eine für das board 
optimierte mac-operation (also addieren und multipolizieren in einem 
takt) eine extra operation wählen muss oder es automatisch optimiert 
abläuft oder es gar nur mit assembler zu realisieren ist?

Grüße und vielen vielen Dank noch einmal für die bisherigen Antworten.

Grüße

: Bearbeitet durch User
von Andre R. (ltisystem)


Lesenswert?

hallo, es gibt neuigkeiten...

ich habe jetzt komplett umgestellt...es kam die empfehlung, das ganze 
mit einem pin-pong-buffer zu realiseren...das hab ich auch gemacht und 
siehe da, tiefpassfilter mit 300 coeffs sind kein problem mehr!acuh das 
echo funktioniert jetzt, mit der schleife:
1
for(i = 0; i < SIZE; i++)
2
{
3
   OUTPUT_POINTER_FIR[i] = INPUT_POINTER_FULL[i]+(OUTPUT_POINTER_FIR[i]*0.55);
4
}
nun würde ich gern noch ein etwas satteres echo haben wollen, also eines 
was vllt einer faltung mit einer impulsantwort aus neiner kirche 
entspricht, hat da jmd einen tip?

grüße

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


Lesenswert?

Andre Richter schrieb:
> nun würde ich gern noch ein etwas satteres echo haben wollen, also eines
> was vllt einer faltung mit einer impulsantwort aus neiner kirche
> entspricht, hat da jmd einen tip?

Durch die vielen Wände in unterschiedlichen Abständen zur Quelle enthält 
das Kirchenecho auch einen grossen Anteil Hall, je nach Kathedrale von 
beträchtlicher Länge, plus natürlich einem nichtlinearen Frequenzgang. 
(Klatsch mal im Kölner Dom in die Hände - gut ist vllt. nicht 
angemessen, hehehe)
Meine Empfehlung mit
http://www.musicdsp.org/showmany.php
gilt aber immer noch.

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.