Archiv verlassen und diese Seite im Standarddesign anzeigen : lichtorgel / FFT / fast fourier
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
ohne avr oder mit? ohne gehts so: http://b-kainka.de/bastel85.htm
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 :)
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:
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):
ISR(SIG_ADC)
{
if(position>=FFT_N)return;
capture[position]=ADC - 32768;
position++;
}
den ADC im free running mode laufen lassen:
// 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:
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
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?image=spektrumrightjl1.png
so sollte es aussehen
es sieht aber so aus
http://img134.imageshack.us/my.php?image=wrongspektrumwy7.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
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?!
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
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
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
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
hier steht einiges zu asm und c:
https://www.roboternetz.de/phpBB2/zeigebeitrag.php?t=36094&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
hallo!
ich versuche gerade auch eine lichtorgel mit der fft lib zu basteln. was die einkopplung des audiosignals betrifft, verwende ich dieselbe schaltung wie e.chan. http://elm-chan.org/works/akilcd/glcd.png ohne groß darüber nachzudenken, habe ich den line out des pcs an die schaltung angeschlossen. der pegel scheint jedoch viel zu gering zu sein, am adc ist nur eine absolut minimale schwankung zu erkennen, +/-3 (ist ja eigt auch logisch, der max293 ist schließlich kein verstärker sondern nur ein tiefpass) sehe ich das richtig, dass die schaltung an einen lautsprecherausgang angeschlossen werden muss? oder habe ich in der schaltung etwas übersehen bzw einen fehler beim nachbauen gemacht?
liebe grüße
maddin
hm. 3 Filter analog aufbauen:
Hochpass, Bandpass, Tiefpass und Analog integrieren. Danach die Amplitude am Ausgang des Integrators mit dem AVR messen. Wäre nen Versuch Wert.
Viele Grüße,
Tim
hallo,
die frage hat sich geklärt. es funktioniert mit einem normalen line out, ohne verstärkung, ich hatte wohl nur die referenzspannung falsch gewählt...
lg
maddin
Powered by vBulletin® Version 4.2.5 Copyright ©2024 Adduco Digital e.K. und vBulletin Solutions, Inc. Alle Rechte vorbehalten.