-         

Seite 1 von 2 12 LetzteLetzte
Ergebnis 1 bis 10 von 13

Thema: lichtorgel / FFT / fast fourier

  1. #1
    Erfahrener Benutzer Roboter Genie Avatar von robocat
    Registriert seit
    18.07.2006
    Beiträge
    935

    lichtorgel / FFT / fast fourier

    Anzeige

    hi ihr,
    für eine "stimmungs-lampe" betreibe ich eine RGB-Led an einem atmega8. farben und helligkeit sind einstellbar, man kann das ding mit einer fernbedienung steuern, schaltplan und programm werde ich demnächst hier veröffentlichen. soweit so schön.

    ein musikgesteuerter lichteffekt wäre nun noch das tüpfelchen auf dem i, deshalb habe ich ein transistorverstärktes audiosignal an einen ADC eingang gelegt, das ich auch mit (je nach auflösung) bis zu 18kHz gesampelt bekomme.

    nur was jetzt tun mit den schönen daten? ein im rhytmus der musik pulsierendes farbenspiel wäre ganz hübsch, also habe ich überlegt, das signal (softwareseitig) in bässe, mitten, höhen zu teilen, und damit die 3 farben anzusteuern. eine fourier-transformation (FFT) ist mit dem mega8 zwar machbar (http://elm-chan.org/works/akilcd/report_e.html), aber da ich noch andere funktionen (die RC5 dekodierung und eine RGB/HSL transformation) habe, reicht mir der platz nicht aus. ausserdem brauche ich eine so detailierte spektrum-analyse gar nicht und weiss auch nicht, ob es überhaupt gut aussehen würde.

    mit goertzel kann ich, soweit ich weiss, nur auf das vorkommen einer bestimmten frequenz testen.

    kurz gefragt, weiss jemand einen einfacheren weg (oder hat eine idee), die audiodaten für einen lichteffekt zu nutzen? wäre auch schön, wenn statt epilepsiegefährdendem geflacker ein pulsieren im takt der musik entsteht.

    gruesse & schonmal vielen dank für jede hilfe

  2. #2

  3. #3
    Erfahrener Benutzer Roboter Genie Avatar von robocat
    Registriert seit
    18.07.2006
    Beiträge
    935
    im notfall könnte ich das audiosignal analog splitten (wie in der von dir gezeigten schaltung) und danach an 3 ADC eingänge legen (wobei ich dann noch 3 spannungsteiler bräuchte, um einen DC anteil einzukoppeln).

    lieber wäre mir eine softwarelösung, die mit dem einen signal zurechtkommt. trotzdem danke

  4. #4
    Erfahrener Benutzer Roboter Genie Avatar von robocat
    Registriert seit
    18.07.2006
    Beiträge
    935
    der vollständigkeit halber wollte ich kurz erwähnen, dass ich nun doch die FFT von Chan (link siehe oben) verwende. kurze anleitung wie das geht:

    ffft.S und ffft.h in den projektordner kopieren
    ffft.h mit #include "ffft.h" einbinden
    im makefile ffft.S bei ASM quellen hinzufügen

    dann am besten erst mal testen, ob es kompliert werden kann. dann..

    in der ffft.h die anzahl der samples festlegen und arrays deklarieren:
    Code:
    int16_t capture[FFT_N];			/* Wave captureing buffer */
    complex_t bfly_buff[FFT_N];		/* FFT buffer */
    uint16_t spektrum[FFT_N/2];		/* Spectrum output buffer */
    eine interrupt service routine erstellen, ("position" habe ich global mit unsigned int position=0; deklariert):
    Code:
    ISR(SIG_ADC)
    {
      if(position>=FFT_N)return;
      capture[position]=ADC - 32768;
      position++;
    }
    den ADC im free running mode laufen lassen:
    Code:
      // free running ADC mode, f = ( 16MHz / prescaler 128 ) / 13 cycles per conversion = 9615Hz
      // 8bit result in ADCH (we adjust left) 
      ADMUX=(1<<REFS0)|(1<<ADLAR);
      ADCSRA=(1<<ADSC)|(1<<ADEN)|(1<<ADFR)|(1<<ADIE)|(1<<ADPS2)|(1<<ADPS1);
    warum ADLAR (left adjust result) gesetzt werden muss, verstehe ich selber nicht so ganz.. verwendet wird nämlich (wie man in der ISR sieht) ADC, also der 16/10 bit wert.

    nun kann man die FFT durchführen, dazu habe ich im main-loop folgenden code:
    Code:
    if(position==FFT_N)
    {
      fft_input(capture, bfly_buff);
      fft_execute(bfly_buff);
      fft_output(bfly_buff, spektrum);
      position=0;
    }
    im array spektrum hat man nun die frequenzanteile des signals. der sample-buffer wird wieder gefüllt, sobald position auf 0 gesetzt ist.

    vielleicht kann jemand mal was damit anfangen.

    gruesse von der katz

  5. #5
    Hey,

    ich kämpf nun seit fast zwei Tagen mit der Lib von elm-chan

    an sich funktioniert sie super!
    Ich lass mir dir Werte der zeit über den comport an ein java program übertragen, dass die werte dann in balken anzeigt..

    Program und weitere Infos hab ich hier gefunden :
    http://www.mikrocontroller.net/topic/27001

    Jetzt zu meinem eigentlichen Problem, wenn ich die assembler dateien von dem link auf mikrocontroller nehmen, dann hab ich ein wunderbares spektrum.
    Nehm ich nun aber die Lib und leg kein Signal an, dann ist der erste Wert schon gut über 0 und der zweite Wert immer maximal. Leg ich nun ein Signal an, so bleiben die Werte Hoch, nur wenn sie überschrieben werden, sieht man, dass sie einen anderen Wert bekommen sollen.

    Am ADC kann es nicht liegen, da die reine assembler datei mir alles richtig anzeigt.. jetzt hab ich schonmal versucht die routine und die Lib zu vergleichen, komm aber auf kein Ergebnis, wo der "Fehler" liegen kann.

    Verzweifel langsam...
    Würde ja gerne die reine Assembler datei verwenden, jedoch müsste des Ergebnis mit twi ausgelesen werden und ich hab keine Ahnung wie ich einen twislave transmitter in asm schreib, wohingegen ich im Wiki eine funktionierende C routine gefunden hab, die genau für meine Anwendung passt (Ein mega8 berechnet die FFT , das Ergebnis ist per twi von einem anderen AVR auslesbar ....)

    Wenn jemand eine Idee hat, wäre ich dankbar!

    @katz... ich lass den ADLAR Register wert weg, mit zeit mir die Routine ein seltsames Spektrum, ohne kann ich den Frequenzgang wunderbar nachvollziehen


    €dit:

    http://img337.imageshack.us/my.php?i...umrightjl1.png

    so sollte es aussehen

    es sieht aber so aus

    http://img134.imageshack.us/my.php?i...pektrumwy7.png
    (nicht wundern dass es 2 balken sind, hab mal zum testen von 128 auf 64 samples reduziert.. des program stellt das einfach dann 2mal dar)


    so greif ich derzeit auf den ADC zu, da ich das problem mit den Balken genauer auswerten wollte, hab ich von freerunning auf abfrage basierend umgestellt

    Das ich den channel wechsel hat folgendes ziel, dass 2 FFTS ausgeführt werden sollen, mit unterschiedlichen sample raten um bei 2 unterschiedlichen frequenzbereichen jeweils unterschiedliche auflösungen zu bekommen
    Code:
    void capture_wave (int16_t *buffer, uint16_t count, uint8_t channel)
    {
    	ADMUX = channel;	
    //	ADMUX = _BV(ADLAR);
    //	ADMUX |= _BV(REFS0);
    	do {
    		if (channel==1) {
    		ADCSRA = _BV(ADEN)|_BV(ADSC)|_BV(ADFR)|_BV(ADIF)|_BV(ADPS2)|_BV(ADPS1)|_BV(ADPS0) ;
    		} else 
    		{
    		ADCSRA = _BV(ADEN)|_BV(ADSC)|_BV(ADFR)|_BV(ADIF)|_BV(ADPS2)|_BV(ADPS0) ;
    		}
    		while(bit_is_clear(ADCSRA, ADIF));
    		*buffer++ = ADC - 32768;
    	} while(--count);
    
    	ADCSRA = 0;
    }
    
    
    
    
    
    
    void do_ffft (void) {
    uint16_t  n, s;
    	capture_wave(capture, FFT_N,0);
    	fft_input(capture, bfly_buff);
    	fft_execute(bfly_buff);
    	fft_output(bfly_buff, spektrum);
    	for (n = 0; n < FFT_N / 2; n++) {
    		s = spektrum[n];
    //		if (n>0 && n<=4) {
    //		uartSendByteAsClear16(s);
    //		}
    		UART_transmit(s);
    	}
    	capture_wave(capture, FFT_N,0);
    	fft_input(capture, bfly_buff);
    	fft_execute(bfly_buff);
    	fft_output(bfly_buff, spektrum2);
    	for (n = 0; n < FFT_N / 2; n++) {
    		s = spektrum2[n];
    //		if (n>0 && n<=4) {
    //		uartSendByteAsClear16(s);
    //		}
    		UART_transmit(s);
    	}
    UART_transmit(254);
    
    }

    Ich hab auchmal für mich die Werte per Termminal program in dem besagten Bereich angeschaut und der erste wert hat immer etwas im Bereich 14XXX ... was normal nicht sein sollte?!

  6. #6
    Erfahrener Benutzer Roboter Genie Avatar von robocat
    Registriert seit
    18.07.2006
    Beiträge
    935
    hm, das ist mir auch aufgefallen, hatte exakt den gleichen effekt. ich habe leider keine lösung parat, und habe mich nicht allzu lang damit aufgehalten, weil es für meine anwendung (rgb-lampe) nicht relevant war.

    könnte es sein, dass diese tiefen frequenzen mit 128 samples nicht bestimmbar sind? 9kHz / 128 = 70 Hz

    gruesse

  7. #7
    Hey,

    ich weiß es ganz ehrlich nicht

    Wenn ich es mit der Software aus dem Anhang und der ASM Datei teste, funktioniert es wunderbar .. alles wird ohne Probleme dargestellt

    Nehm ich jetzt die C Routine erscheinen der Balken links ...
    Bei der ASM Routine ist auch ganz links ein minimaler Balken zu sehen, da hab ich aber eher die Vermutung, dass es noch das 50hz brummen der Signalquelle ist... auch für mich nicht weiter tragisch, könnt ich ja noch rausfiltern ...

    Meine beiden Vermutungen:
    Es ist irgendwo ein Fehler in der ASM Lib, der aber unabhängig von den verwendeten samples auftritt
    Oder es stimm irgendwas nicht mit der Art, wie der ADC Puffer ausgelesen wird...

    Nur leider steig ich kein bischen hinter den ASM Code bei dem ADC Part, die FFT Berechnung ist mir auch ein Rätsel ..
    Naja zumindest weiß ich, wie der ErgebnisPuffer aussieht und wenn ich rausfinde wie ich einen TWI Slave in ASM hinbekomme, der einfach nur auf kommando den Puffer per twi sendet, dann bin ich auch zufrieden

    Ist nur ärgerlich, dass die schöne C Routine nicht so will, wie ich
    Angehängte Dateien Angehängte Dateien

  8. #8
    Erfahrener Benutzer Roboter Genie Avatar von robocat
    Registriert seit
    18.07.2006
    Beiträge
    935
    ach so, sry, da habe ich nicht aufmerksam gelesen. wenn es mit dem asm code funktioniert, muss der fehler woanders liegen.

    das hier habe ich noch gefunden:
    The spectrum bars are displayed in order of fundamental frequency x 0 (DC component), fundamental frequency x 1, x2, x3, ... from left to right. The sampling frequency is 9.6 kHz and the fundamental frequency (frequency resolution) becomes: 9.6k / 128 = 75Hz.
    also ist spektrum[0] der gleichspannungsanteil, der dürfte sich ja nicht verändern. allerdings bekomme ich auch bei spektrum[1] einen viel zu grossen wert.

    mir ist aber aufgefallen, dass auf deinem bild vom "richtigen spektrum" nur 62 balken sind (wenn ich mich nicht verzählt habe). vermutlich sind die ersten beiden "bösen werte" einfach nicht dargestellt.

    gruesse

  9. #9
    Hmm stimmt mit dem DC Anteil ...
    Hab nun auchmal die balken nachgezählt, sind tatsächlich nur 62

    Hab dann bei der funktionierenden FFT nen Frequenzgenerator drüberlaufen lassen, schon ab 0 Hz werden signale angezeigt...

    Wenn ich nun bei der FFT_Lib in C die ersten beiden Werte wegfallen lasse, krieg ich erst eine Anzeige ab 100hz
    Da ist irgendwo der Wurm drin....
    Würde doch ganz gerne ab 0 Hz darstellen lassen, da die ganze FFT als DisplayAuswertung für einen Vorverstärker sein soll.. Und bei Filmen und Musik ist oftmals für mich auch der untere Bereich ganz Interressant

    Ich hab nun 4 Stunden versucht hinter den ASM Code zu steigen oder besser heraus zu finden, wie ich per TWI Werte auslesen kann ....
    Da ich aber bisher nichts in ASM gemacht habe, scheitere ich daran...
    selbst die Forensuche hat mich nich wirklich weiter gebracht, dabei müsste ich einfach nur bei jedem READ_ACK einfach den nächsten Wert aus dem Puffer in das Data Transmit Register schreiben und Feddisch...

    Sagmal gibt es ne Möglichkeit C in ASM zu importieren? Oder die ASM Datei doch wie die LIB für C verwendbar zu machen, und dabei trotzdem die ADC Interrupt von der ASM datei handhaben zu lassen?

    grüße


    Edit:

    So langsam krieg ichs hin... hab jetzt mal die Referenzspannung nochmals verändert ... ADLAR wieder gesetzt und den Input mit nem Trimmer versehen...
    Das Signal das ankam war einfach zu übersteuert für die Anzeige die ich verwendet hab... jetzt klappt es soweit ganz gut, werds mal weiter testen und erweitern

  10. #10
    Erfahrener Benutzer Roboter Genie Avatar von robocat
    Registriert seit
    18.07.2006
    Beiträge
    935
    hier steht einiges zu asm und c:
    http://www.roboternetz.de/phpBB2/zei...&highlight=asm

    ich habe mal das makefile von E. Chan verwendet, damit scheint es etwas besser zu klappen (spektrum[1] geht zwar nicht auf 0 runter, aber man erkennt deutlich, wenn ein signal anliegt). es könnte also auch am makefile bzw. den compiler-einstellungen liegen.

    verwendest du auch winAVR-gcc zum kompilieren?
    wie koppelst du eigentlich dein audiosignal ein? (mit DC anteil vermutlich, weil der ADC ja negative spannungen nicht verträgt)?

    wäre sehr nett, wenn du mich auf dem laufenden hältst, bzw mir sagst, wenn (und wie) du es hinbekommen hast.

    gruesse

Seite 1 von 2 12 LetzteLetzte

Berechtigungen

  • Neue Themen erstellen: Nein
  • Themen beantworten: Nein
  • Anhänge hochladen: Nein
  • Beiträge bearbeiten: Nein
  •