LED tavla 8x8 (spektrumsanalysator)

Planering och tankar kring eventuella framtida projekt.
KalleG
Inlägg: 16
Blev medlem: 14 januari 2010, 22:50:15

LED tavla 8x8 (spektrumsanalysator)

Inlägg av KalleG »

Tjenare!

Jag funderar på att bygga en LED tavla med 8x8 LED´s som skall styras av en PIC microcontroller.
Den skall bla. fungera som Equaliser och det är här som jag stöter på mitt första problem. Jag skall
visa output med hjälp av PIC´ens ADC, där alla frekvenser delas upp i olika omfång och visas på var sin LED stapel. Själva programmeringen är det inga problem med utan det är när ljudet skall delas upp i frekvenser som jag är lite lost, så är det någon som har något förslag om hur det kan lösas så är jag väldigt tacksam. :)

Mvh
Senast redigerad av KalleG 29 juni 2011, 02:26:26, redigerad totalt 2 gånger.
labmaster
Inlägg: 2919
Blev medlem: 5 april 2011, 01:10:25

Re: LED tavla 8x8

Inlägg av labmaster »

Detta löser man enkelt med en FFT (fast Fourier transform) men det är inte säkert att du har tillräckligt med krut i din PIC microcontroller. dspPIC kanske funkar men jag har inte koll på vad den klarar. Namnet ger dock en hint om att det skall gå att köra siganprocessing i den.
Användarvisningsbild
jesse
Inlägg: 9240
Blev medlem: 10 september 2007, 12:03:55
Ort: Alingsås

Re: LED tavla 8x8

Inlägg av jesse »

Hej.

Jag vet inte hur man bäst gör, men kanske det går att göra i mjukvara om PICen är tillräckligt snabb... i så fall kanske man kan använda en kombination av flera filter av den här typen (det står i tråden hur man gör högpassfilter.... om man kombinerar låg och högpassfilter borde man få bandpass, vilket du behöver.)

Om du skulle göra det i hårdvara blir det flera parallella bandpassfilter, antar jag... du ska ju ha åtta kanaler, så det kan bli en del pysslande om alla åtta ska trimmas rätt.

Kanske rubriken skulle vara något annat... det är ju inte LED-tavlan du frågar om...
KalleG
Inlägg: 16
Blev medlem: 14 januari 2010, 22:50:15

Re: LED tavla 8x8 (Equaliser)

Inlägg av KalleG »

Tack för svaren, jag har funderat på hög och lågpassfilter dock så känns det en aning bökigt. FFT var mycket intresant, hittade en snubbe som kunde mäta upp till 10khz.
labmaster
Inlägg: 2919
Blev medlem: 5 april 2011, 01:10:25

Re: LED tavla 8x8 (Equaliser)

Inlägg av labmaster »

Ja den snubben mätte inte särskilt högt i frekvens. Det finns andra snubbar som har klarat ännu högre frekvenser. Det hänger på vilken A/D man har eller om man sätter en blandare och LO framför A/D:n

Om du skall klara av att implementera en FFT behöver du kunskaper i matematik på högskolenivå. Eller så måste du hitta någon med denna kunskap som kan hjälpa dig med detta. Själv har jag inte tid men har byggt flera applikationer som använder FFT.
Användarvisningsbild
chille
Inlägg: 2469
Blev medlem: 25 juni 2003, 20:54:41
Ort: Stockholm
Kontakt:

Re: LED tavla 8x8 (Equaliser)

Inlägg av chille »

Om det bara är 8 band så tror jag nog att ett gäng bandpassfilter skulle vara snabbare än FFT. Efter bandpassfiltrena behöver du hänga på en så kallad "envelope follower", vilket i princip är ett lågpassfilter. Skillnaden är att man har olika koefficienter beroende på om värdet ökar eller minskar för att kunna ha en snabb "attack" och långsam "release". Jag skulle rekomentera omkring 5-10mS attack och 500-1500mS release. Om man tar för givet att högsta frekvensen du vill kunna mäta är på 16kHz kommer samplingsfrekvensen behöva ligga på minst 32kHz. Du kan du läsa varför Här.

Nu har jag inte stenkoll på PIC, men om man tar för givet att en PIC kan utföra 20M instruktioner per sekund så kommer man altså att ha cirka 78 instruktioner på sig per band för varje sample som skall beräknas. Om en PIC kan multiplicera heltal på en instruktion så borde det inte vara några problem.

Här har du ett bandpass-filter att börja labba med:

Kod: Markera allt

typedef struct {
  float in1, in2;
  float out1, out2;
  float a1a0, a2a0, b0a0, b1a0, b2a0;
} FILTER;


void filter_init(FILTER *f) {
  float bandwidth = 0.5f; // Bandbredd i oktaver
  float frequency = 440.0f; // Frekvens i Hz
  float samplerate = 32000.0f; // Samplingsfrekvens i Hz

  f->in1 = 0.0f;
  f->in2 = 0.0f;
  f->out1 = 0.0f;
  f->out2 = 0.0f;

  float w0 = 2.0f * PI * frequency / samplerate;
  float alpha = sinf(w0) * sinhf(logf(2.0f) / 2.0f * bandwidth * w0 / sinf(w0));
  float b0 =  alpha;
  float b1 =  0;
  float b2 = -alpha;
  float a0 =  1 + alpha;
  float a1 = -2 * cosf(w0);
  float a2 =  1 - alpha;

  f->a1a0 = a1 / a0;
  f->a2a0 = a2 / a0;
  f->b0a0 = b0 / a0;
  f->b1a0 = b1 / a0;
  f->b2a0 = b2 / a0;
}

float filter_process(float in) {
  return (f->b0a0) * in + (f->b1a0) * f->in1  + (f->b2a0) * f->in2 - (f->a1a0) * f->out1 - (f->a2a0) * f->out2;
}
Kör filter_init() en gång i början och peta in rätt variabler (de tre översta). Kör sedan filter_process() en gång för varje sample. Självklart blir det ju lite tungt med floating points på en PIC, så du får ju ändra koden till fixed point :)

Du kan få en envelope follower när vi ändå är igång...

Kod: Markera allt

float attack_in_ms = 10.0f, release_in_ms = 1000.0f;
float attack_coef, release_coef, level = 0.0f;
void env_init() {
  attack_coef  = pow(0.01, 1.0 / (attack_in_ms  * samplerate * 0.001));
  release_coef = pow(0.01, 1.0 / (release_in_ms * samplerate * 0.001));
}

float env_process(float input) {
  abs_in = fabs(input);
  if(abs_in > level) {
    level = attack_coef * (level - abs_in) + abs_in;
  } else {
    level = release_coef * (level - abs_in) + abs_in;
  }
  return level;
}
(Kan hända att koden inte kompilerar rakt av då jag cut 'n paste:ade en hel del och ändrade utan att testa den.)

Säg till om du behöver mer hjälp! :)

EDIT: Filtret kommer härifrån. Finns en hel del andra filter som kan vara värta att titta på. Till exempel kan man ju använda sig av ett gäng högpass + lågpass för att få ut de 8 banden.

EDIT2: För övrigt så heter det inte equalizer, det heter spektrumsanalysator (eng: spectrum analyzer).

EDIT3: filter_init() ska självklart inte köras på själva PIC:en. Räkna ut dessa värden på en dator och spara som statiska värden i minnet på din PIC.
Användarvisningsbild
chille
Inlägg: 2469
Blev medlem: 25 juni 2003, 20:54:41
Ort: Stockholm
Kontakt:

Re: LED tavla 8x8 (Equaliser)

Inlägg av chille »

Jag kände att jag behövde lite omväxling från det jag höll på med innan, så jag skrev ihop lite kod åt dig. 8)

Program för att beräkna koefficienter till bandpass-filter och envelope follower:

Kod: Markera allt

/*
 * Calculate envelope follower and bandpass filter coefficients for spectrum
 * analyzers
 *
 * Developed in 2011 by Christian Antila
 * Filter mathematics from Audio-EQ-Cookbook.txt from Robert Bristow-Johnson
 *
 * This application will calculate filter coefficients for NUM_BANDS bandpass
 * filters with the first filter center frequency set to FIRST_BAND and the
 * frequency multiplied by BAND_STEP for each band.
 *
 * It will also calculate coefficients for a simple envelope follower.
 *
 * This code comes with no warranty and is public domain. Feel free to use it
 * to whatever you want!
 *
 * Compile with: gcc -lm main.cpp
 */

#define SAMPLERATE 44100.0f // Samplerate in Hz
#define NUM_BANDS  8        // Number of bands
#define FIRST_BAND 125.0f   // Frequency in Hz of first band
#define BAND_STEP  2.0f     // Frequency multiplier (*2 = 1 octave, etc)
#define BANDWIDTH  0.1f     // Bandwidth (Q) in octaves for bandpass filters
#define ATTACK     20.0f    // Envelope follower attack in mS
#define RELEASE    1500.0f  // Envelope follower release in mS

// Do not edit anything below this line if you're not sure what you're doing! :-)

#include <stdio.h>
#include <math.h>

int main(void)
{
  float w0, alpha, b0, b2, a0, a1, a2;
  float frequency = FIRST_BAND;
  char frequencies[1024] = "";
  int i;

  // Calculate coefficients for envelope follower
  float attack_coef  = pow(0.01, 1.0 / (ATTACK  * SAMPLERATE * 0.001));
  float release_coef = pow(0.01, 1.0 / (RELEASE * SAMPLERATE * 0.001));

  printf("float attack_coef = %ff;\n", attack_coef);
  printf("float release_coef = %ff;\n", release_coef);

  // Calculate coefficients for bandpass filters
  printf("SPBAND spband[] {\n");
  for(i = 0; i < NUM_BANDS; i++)
  {
    sprintf(frequencies, "%s%.0f Hz, ", frequencies, frequency);
    w0 = 2.0f * M_PI * frequency / SAMPLERATE;
    alpha = sinf(w0) * sinhf(logf(2.0f) / 2.0f * BANDWIDTH * w0 / sinf(w0));
    b0 =  alpha;
    b2 = -alpha;
    a0 =  1 + alpha;
    a1 = -2 * cosf(w0);
    a2 =  1 - alpha;

    printf("                 {%ff, %ff, %ff, %ff},\n", (a1/a0), (a2/a0), (b0/a0), (b2/a0));

    frequency *= BAND_STEP;
  }
  printf("                };\n");
  printf("Filter frequencies: %s\n", frequencies);
}

Spektrumsanalysatorn:

Kod: Markera allt

typedef struct
{
  float a1a0, a2a0, b0a0, b2a0;
  float in1, in2;
  float out1, out2;
  float level;
} SPBAND;

float attack_coef = 0.994792;
float release_coef = 0.999930;
SPBAND spband[] {
                 {-1.998449, 0.998766, 0.000617, -0.000617},
                 {-1.996267, 0.997534, 0.001233, -0.001233},
                 {-1.990013, 0.995073, 0.002463, -0.002463},
                 {-1.970005, 0.990171, 0.004915, -0.004915},
                 {-1.900577, 0.980438, 0.009781, -0.009781},
                 {-1.651284, 0.961254, 0.019373, -0.019373},
                 {-0.803779, 0.923974, 0.038013, -0.038013},
                 { 1.206390, 0.853314, 0.073343, -0.073343},
                };

void sp_process(SPBAND *sp, float input)
{
  float bandpass = (sp->b0a0) * input + (sp->b2a0) * sp->in2 - (sp->a1a0) * sp->out1 - (sp->a2a0) * sp->out2;
  sp->in2  = sp->in1;
  sp->in1  = input;
  sp->out2 = sp->out1;
  sp->out1 = bandpass;

  float abs_in = fabs(bandpass);
  if(abs_in > sp->level)
  {
    sp->level = attack_coef * (sp->level - abs_in) + abs_in;
  }
  else
  {
    sp->level = release_coef * (sp->level - abs_in) + abs_in;
  }
}

void audio_process(float input) {
  for(int e = 0; e < 8; e++)
  {
    sp_process(&spband[e], input);
  }
}
audio_process() är funktionen/loopen som ska läsa in audio-data och skicka in i algoritmen. Kurvan för respektive band får man sedan i spband->level. Kurvan är linjär, men för endast 8 värden som det var snack om räcker det med några if-satser för att göra den logaritmisk och visa på LED-displayen.

Gäller bara att få matematiken att snurra på en MCU också. 8)

EDIT: Höll på glömma det enda som är viktigare än källkoden.... videoklippet!

EDIT2: Det verkar inte som om musiken kom med i videoklippet... orkar inte göra om nu.. :(
Du har inte behörighet att öppna de filer som bifogats till detta inlägg.
bos
Inlägg: 2311
Blev medlem: 24 februari 2007, 23:29:15
Kontakt:

Re: LED tavla 8x8 (Equaliser)

Inlägg av bos »

http://www.waitingforfriday.com/index.p ... m_Analyser

"This project implements a real-time audio spectrum analyser using a PIC18F4550 8-bit microcontroller. "
KalleG
Inlägg: 16
Blev medlem: 14 januari 2010, 22:50:15

Re: LED tavla 8x8 (spektrumsanalysator)

Inlägg av KalleG »

Så. Tack för alla svar! Efter att ha funderat en längre tid på hur jag skall gå tillväga så tror jag att jag kör på http://www.waitingforfriday.com/index.p ... m_Analyser och snor lite kod därifrån.
Jag förstår mig inte helt på FFT men jag tror jag kan lösa det genom att ta koden från hemsidan. Jag måste bara lära mig C något bättre :vissla: . Sedan så borde det komma upp en tråd i Projekt delen om inte allt för lång tid!.
Skriv svar