Física Experimental
quinta-feira, 7 de junho de 2012
sábado, 2 de junho de 2012
Entendendo e Manipulando o Código
No penúltimo post, apresentamos os códigos usados no Arduíno e no Processing para a captação de frequências, sem contúdo uma explicação mais aprofundada dos códigos, isso por se tratar do nosso primeiro teste bem sucedido com ele.
Depois disso pudemos estudar melhor o código e manipulá-lo de acordo com nosso propósito. Um detalhe importante, e já falado no post anterior, é que para que o código funcione é preciso que se adicione a biblioteca ffft na pasta libraries do Arduíno, a qual existe um link no post anterior.
A primeira coisa que descobrimos é que o código do Arduíno não funciona com qualquer versão de software, mas sim com a versão Arduíno 0022, quanto ao Processing funciona bem a comunicação com a versão mais atual: Processing 1.5.1.
Depois descobrimos que o software tem duas opções para a divisão de frêquencias: a primeira divide o espectro de aproximadamente 19200Hz por 64 faixas de 300Hz e a segunda divide o espectro de aproximadamente 9600Hz por 64 faixas de 150Hz. Essas duas opções limitam nosso campo de ação, com elas não podemos captar frequências especificas de notas musicais, mas sim intervalos nos quais estas frequências estão inseridas, pela segunda opção apresentar um intervalo menor e portanto uma definição maior optamos por ela.
É importante observar que nosso projeto sofreu portanto uma modificação de objetivo, nosso experimento não reconhecerá mais frequências de notas musicais específicas, e sim intervalos de frequências, para cada intervalo o Arduíno acionará uma luz. Teremos nesse experimento sete intervalos de frequências e portanto usaremos apenas 7 das 64 barras ou intervalos de frequências geradas pela biblioteca, essas barras começarão a captar a frequência aproximadamente de 400Hz até 1000Hz.
Para que o Arduíno identifique a frequência predominante foi preciso criar uma função que acha o intervalo de frequência de maior intensidade dentre os 7 escolhidos. Código abaixo:
int Maior(uint16_t lista[]){
int maior = 7;
for(int i=7;i<14;i++){
if(lista[i]>lista[maior])maior=i;
}
if(lista[maior]<15)maior=0;
return maior;
}
Como ainda não compramos todos os Leds, utilizamos um LED RGB que utiliza a porta 3 para vermelho, 4 para negativo, 5 para verde e 6 para Azul. E para controlá-lo, criamos uma função que recebe os três paramêtros de intersidade 0-255 para cade um:
void RGB(int r, int g, int b){
digitalWrite(4, HIGH);
analogWrite(3,r);
analogWrite(5,g);
analogWrite(6,b);
}
E outra que a utilizará, esta recebe apenas um valor de 1-7 o qual acionara uma cor pre-definida para o RGB.
void Cor(int n){
switch(n){
case 1: RGB(255,0,0);break;
case 2: RGB(0,255,0);break;
case 3: RGB(0,0,255);break;
case 4: RGB(255,255,0);break;
case 5: RGB(255,0,255);break;
case 6: RGB(150,255,10);break;
case 7: RGB(255,255,255);break;
default: RGB(0,0,0);
}
}
Abaixo está o código comentado do Arduíno.
/*
This Example acquire analog signal from A0 of Arduino, and Serial out to Processing application to visualize.
Tested with preamplified audio data. Take a look at http://www.youtube.com/watch?v=drYWullBWcI
Analog signal is captured at 9.6 KHz, 64 spectrum bands each 150Hz which can be change from adcInit()
Load the this file to Arduio, run Processing application.
Original Fixed point FFT library is from ELM Chan, http://elm-chan.org/works/akilcd/report_e.html
Ported to the library and demo codes are from AMurchick http://arduino.cc/forum/index.php/topic,37751.0.html
Processing code is from boolscott http://boolscott.wordpress.com/2010/02/04/arduino-processing-analogue-bar-graph-2/
*/
#include <stdint.h>
#include <ffft.h>
#define IR_AUDIO 0 // ADC canal para capturar
volatile byte position = 0;
volatile long zero = 0;
int16_t capture[FFT_N]; /* buffer capturador de onde */
complex_t bfly_buff[FFT_N]; /* FFT buffer */
uint16_t spektrum[FFT_N/2]; /* saida do espectro do buffer */
int minimo = 10;
void RGB(int r, int g, int b){//Contralador RBG
digitalWrite(4, HIGH);
analogWrite(3,r);
analogWrite(5,g);
analogWrite(6,b);
}
void Cor(int n){//Função que define 7 cores para n de 1-7
switch(n){
case 1: RGB(255,0,0);break;
case 2: RGB(0,255,0);break;
case 3: RGB(0,0,255);break;
case 4: RGB(255,255,0);break;
case 5: RGB(255,0,255);break;
case 6: RGB(150,255,10);break;
case 7: RGB(255,255,255);break;
default: RGB(0,0,0);
}
}
int Maior(uint16_t lista[]){//Função que define intervalo de frequência de maior intensidade
int maior = 7;
for(int i=7;i<14;i++){
if(lista[i]>lista[maior])maior=i;
}
if(lista[maior]<15)maior=0;
return maior;
}
void setup()
{
Serial.begin(57600);
adcInit();
adcCalb();
establishContact(); // manda um byte para estabelecer contato até o processing responder
for(int i=4;i<11;i++)pinMode(i,OUTPUT);
}
void loop()
{
if (position == FFT_N)
{
fft_input(capture, bfly_buff);
fft_execute(bfly_buff);
fft_output(bfly_buff, spektrum);
for (byte i = 7; i < 14; i++){
Serial.print(spektrum[i],BYTE);
}//manda dados para o processing
position = 0;
int maior = Maior(spektrum);
Cor(maior-6);//pede a função Cor() acender a cor maior-6
}
}
void establishContact() {
while (Serial.available() <= 0) {
Serial.print('A', BYTE); // manda um A maiusculo
delay(300);
}
}
// free running ADC fills capture buffer
ISR(ADC_vect)
{
if (position >= FFT_N)
return;
capture[position] = ADC + zero;
if (capture[position] == -1 || capture[position] == 1)
capture[position] = 0;
position++;
}
void adcInit(){
/* REFS0 : VCC use as a ref, IR_AUDIO : channel selection, ADEN : ADC Enable, ADSC : ADC Start, ADATE : ADC Auto Trigger Enable, ADIE : ADC Interrupt Enable, ADPS : ADC Prescaler */
// free running ADC mode, f = ( 16MHz / prescaler ) / 13 cycles per conversion
ADMUX = _BV(REFS0) | IR_AUDIO; // | _BV(ADLAR);
//ADCSRA = _BV(ADSC) | _BV(ADEN) | _BV(ADATE) | _BV(ADIE) | _BV(ADPS2) | _BV(ADPS1); //pre-escala 64 : 19231 Hz - 300Hz por 64 divisões
ADCSRA = _BV(ADSC) | _BV(ADEN) | _BV(ADATE) | _BV(ADIE) | _BV(ADPS2) | _BV(ADPS1) | _BV(ADPS0); // pre-escala 128 : 9615 Hz - 150 Hz porr 64 divisões, melhor para maioria das músicas(mais definição)
sei();
}
void adcCalb(){
Serial.println("Start to calc zero");
long midl = 0;
// get 2 meashurment at 2 sec
// on ADC input must be NO SIGNAL!!!
for (byte i = 0; i < 2; i++)
{
position = 0;
delay(100);
midl += capture[0];
delay(900);
}
zero = -midl/2;
Serial.println("Done.");
}
Quanto ao código do processing modificamos o código de barras para 7, ao invés das 64 do post anterior, contúdo é preciso que você modifique o campo da porta, pois ela lê a porta que o arduíno está utilizando, para saber a porta que seu arduíno está utilizando vá em tools-> Serial Port. No nosso caso utilizamos a porta "COM5"
// Feel Free to edit these variables ///////////////////////////
String xLabel = "Frequency";
String yLabel = "Values";
String Heading = "Arduino FFT";
String URL = "01/02/2010";
float Vcc = 255.0; // the measured voltage of your usb
int NumOfVertDivisions=5; // dark gray
int NumOfVertSubDivisions=10; // light gray
int NumOfBars=7; // Numero de barras/ Deve ser o mesmo que o arduíno envia.
// since you should change what the arduino sends
// if these are changed, backgroung image has problems
// a plain background solves the problem
int ScreenWidth = 800, ScreenHeight=600;
/////////////////////////////////////////////////////////
// Serial port stuff ///////////////////////
import processing.serial.*;
Serial myPort;
boolean firstContact = false;
int[] serialInArray = new int[NumOfBars];
int serialCount = 0;
///////////////////////////////////////////////
int LeftMargin=100;
int RightMArgin=80;
int TextGap=50;
int GraphYposition=80;
float BarPercent = 0.4;
int value;
PFont font;
PImage bg;
int temp;
float yRatio = 0.58;
int BarGap, BarWidth, DivisounsWidth;
int[] bars = new int[NumOfBars];
void setup(){
bg = loadImage("BG.jpg");
/// NB SETTINGS ////////////////////////////////////////////////////////
myPort = new Serial(this,"COM5",57600);
////////////////////////////////////////////////////////////////////////
DivisounsWidth = (ScreenWidth-LeftMargin-RightMArgin)/(NumOfBars);
BarWidth = int(BarPercent*float(DivisounsWidth));
BarGap = DivisounsWidth - BarWidth;
size(ScreenWidth,ScreenHeight);
font = createFont("Arial",12);
textAlign(CENTER);
textFont(font);
}
void draw(){
//background(bg); // My one used a background image, I've
background(250); // commented it out and put a plain colour
// Headings(); // Displays bar width, Bar gap or any variable.
Axis();
Labels();
PrintBars();
// Line();
// Dots();
}
// Send Recieve data //
void serialEvent(Serial myPort) {
// read a byte from the serial port:
int inByte = myPort.read();
if (firstContact == false) {
if (inByte == 'A') {
myPort.clear(); // clear the serial port buffer
firstContact = true; // you've had first contact from the microcontroller
myPort.write('A'); // ask for more
}
}
else {
// Add the latest byte from the serial port to array:
serialInArray[serialCount] = inByte;
serialCount++;
// If we have 6 bytes:
if (serialCount > NumOfBars -1 ) {
for (int x=0;x<NumOfBars;x++){
bars[x] = int (yRatio*(ScreenHeight)*(serialInArray[x]/256.0));
}
// Send a capital A to request new sensor readings:
myPort.write('A');
// Reset serialCount:
serialCount = 0;
}
}
}
/////// Display any variables for testing here//////////////
void Headings(){
fill(0 );
text("BarWidth",50,TextGap );
text("BarGap",250,TextGap );
text("DivisounsWidth",450,TextGap );
text(BarWidth,100,TextGap );
text(BarGap,300,TextGap );
text(DivisounsWidth,520,TextGap );
}
void PrintBars(){
int c=0;
for (int i=0;i<NumOfBars;i++){
fill((0xe4+c),(255-bars[i]+c),(0x1a+c));
stroke(90);
rect(i*DivisounsWidth+LeftMargin, ScreenHeight-GraphYposition, BarWidth, -bars[i]);
fill(0x2e,0x2a,0x2a);
// text(float(bars[i])/(yRatio*(ScreenHeight))*Vcc, i*DivisounsWidth+LeftMargin+BarWidth/2, ScreenHeight-bars[i]-5-GraphYposition );
// text("A", i*DivisounsWidth+LeftMargin+BarWidth/2 -5, ScreenHeight-GraphYposition+20 );
// text(i, i*DivisounsWidth+LeftMargin+BarWidth/2 +5, ScreenHeight-GraphYposition+20 );
}
}
void Axis(){
strokeWeight(1);
stroke(220);
for(float x=0;x<=NumOfVertSubDivisions;x++){
int bars=(ScreenHeight-GraphYposition)-int(yRatio*(ScreenHeight)*(x/NumOfVertSubDivisions));
line(LeftMargin-15,bars,ScreenWidth-RightMArgin-DivisounsWidth+50,bars);
}
strokeWeight(1);
stroke(180);
for(float x=0;x<=NumOfVertDivisions;x++){
int bars=(ScreenHeight-GraphYposition)-int(yRatio*(ScreenHeight)*(x/NumOfVertDivisions));
line(LeftMargin-15,bars,ScreenWidth-RightMArgin-DivisounsWidth+50,bars);
}
strokeWeight(2);
stroke(90);
line(LeftMargin-15, ScreenHeight-GraphYposition+2, ScreenWidth-RightMArgin-DivisounsWidth+50, ScreenHeight-GraphYposition+2);
line(LeftMargin-15,ScreenHeight-GraphYposition+2,LeftMargin-15,GraphYposition+80);
strokeWeight(1);
}
void Labels(){
textFont(font,18);
fill(50);
rotate(radians(-90));
text(yLabel,-ScreenHeight/2,LeftMargin-45);
textFont(font,10);
for(float x=0;x<=NumOfVertDivisions;x++){
int bars=(ScreenHeight-GraphYposition)-int(yRatio*(ScreenHeight)*(x/NumOfVertDivisions));
text(round(x),-bars,LeftMargin-20);
}
textFont(font,18);
rotate(radians(90));
text(xLabel,LeftMargin+(ScreenWidth-LeftMargin-RightMArgin-50)/2,ScreenHeight-GraphYposition+40);
textFont(font,24);
fill(50);
text(Heading,LeftMargin+(ScreenWidth-LeftMargin-RightMArgin-50)/2,70);
textFont(font);
fill(150);
text(URL,ScreenWidth-RightMArgin-40,ScreenHeight-15);
textFont(font);
}
Abaixo estão os dois vídeos do teste:
quarta-feira, 9 de maio de 2012
Estudo de Timbre e Onda Sonora
Onda
Em física, uma onda
é uma perturbação oscilante de alguma grandeza física no espaço e periódica no
tempo. A oscilação espacial é caracterizada pelo comprimento de onda e o tempo decorrido para
uma oscilação é medido pelo período da onda, que é o inverso da sua frequência.
Ondas podem ser descritas usando um número de variáveis,
incluindo: frequência, comprimento de onda, amplitude
e período.
A amplitude de uma onda é a medida da magnitude de um
distúrbio em um meio durante um ciclo de onda. Por exemplo, ondas em uma corda
têm sua amplitude expressada como uma distância (metros), ondas de som como
pressão (pascals) e ondas eletromagnéticas como a amplitude de um campo
elétrico (volts por metro). A amplitude pode ser constante (neste caso a onda é
uma onda contínua), ou pode
variar com tempo e/ou posição. A forma desta variação é o envelope da onda.
O período é o tempo(T) de um ciclo completo de uma oscilação de uma onda. A
frequência (F) é período
dividido por uma unidade de tempo (exemplo: um segundo), e é expressa em hertz.
As frequências de vibração de uma corda de violino, por
exemplo, variam com o comprimento dela e com as suas características (material,
tensão, espessura), que determinam a velocidade de propagação das ondas.
(http://pt.wikipedia.org/wiki/Onda)
As ondas podem ser classificadas de
três modos. A seguir são descritas as classificações correspondentes às ondas
sonoras (http://ww2.unime.it/weblab/awardarchivio/ondulatoria/ondas.htm#Revendo
os conceitos iniciais).
1-Quanto à natureza
2-
Quanto à direção de propagação
3-
Quanto à direção de vibração
Ondas sonoras são:
1- Mecânicas, ou seja, precisam de um meio material para se
propagar (não se propagam no vácuo).
2-
Tridimensionais,
ou seja, se propagam em todas as direções.
3-
Longitudinais,
ou seja, suas vibrações coincidem com a direção de propagação.
Chamamos de som grave,
aquele que é emitido por uma fonte sonora que vibra com baixa freqüência e som agudo,
o que vibra com uma alta freqüência. Para entender melhor basta perceber a
diferença entre a voz masculina (grave) e a voz feminina (agudo). Essa
caracterização em relação à freqüência de um som é chamada de altura.
Quando um som possui uma
grande quantidade de energia por unidade de tempo e a onda sonora possui uma
grande amplitude, dizemos que o som possui uma grande intensidade. Falando de forma mais clara, a intensidade
está relacionada ao volume do som. Essa intensidade é medida em dB (decibéis),
onde se estabeleceu que ao som de menor intensidade que o ser humanos fosse
capaz de escutar seria atribuído o valor de 0 dB e o de maior intensidade, de
120 dB.
Timbre
Timbre
é a característica sonora que nos permite distinguir sons de uma mesma freqüência,
porém emitidos por fontes sonoras conhecidas, permitindo-nos identificar o
emissor do som (http://www.mundoeducacao.com.br/fisica/ondas-sonoras.htm).
Em música, chama-se timbre à característica
sonora que nos permite distinguir se sons de mesma frequência foram
produzidos por fontes sonoras conhecidas e que nos permite diferenciá-las. Quando
ouvimos, por exemplo uma nota tocada por um piano e a mesma nota (uma nota com a mesma altura) produzida por um violino, podemos imediatamente
identificar os dois sons como tendo a mesma freqüência, mas com características
sonoras muito distintas. O que nos permite diferenciar os dois sons é o timbre
instrumental. De forma simplificada podemos considerar que o timbre é como a impressão digital sonora de um instrumento ou a qualidade de vibração vocal.
O Lá central do piano
possui a freqüência de
440Hz. A nota equivalente produzida por um violino possui a mesma freqüência. O
que permite ao ouvido diferenciar os dois sons e identificar sua fonte é a
forma da onda e seu envelope sonoro (http://pt.wikipedia.org/wiki/Timbre).
Forma de
onda
Quando uma corda, uma
membrana, um tubo ou qualquer outro objeto capaz de produzir sons entra em
vibração, uma série de ondas senoidais é produzida. Além da frequência
fundamental, que define a nota, várias freqüências harmônicas também soam. O
primeiro harmônico de qualquer nota tem o dobro de sua freqüência; o segundo
harmônico tem o triplo de sua freqüência e assim por diante. Qualquer corpo em
vibração produz dezenas de freqüências harmônicas que soam simultaneamente à
nota fundamental. No entanto o ouvido humano não é capaz de ouvir os harmônicos
com freqüencia muito alta (maior que 20000Hz). Além disso, devido às
características de cada instrumento ou da forma como a nota foi obtida, alguns
dos harmônicos audíveis possuem amplitude diferente de um instrumento para
outro.
Se somarmos a amplitude
da freqüência fundamental às amplitudes dos harmônicos, a forma de onda resultante
não é mais senoidal, mas sim uma onda irregular cheia
de cristas e vales. Como a combinação exata de amplitudes depende das
características de cada instrumento, suas formas de onda também são muito
distintas entre si. Veja os exemplos abaixo:
Forma de onda produzida
por uma flauta
Forma de onda produzida
por um xilofone. Note que no início da nota (ataque), a onda possui muito mais
harmônicos, que se devem à batida pela baqueta. Depois disso, a forma de onda é
resultado somente da vibração da madeira
Envelope
sonoro
Não é só a forma de onda que define
que um som é produzido por determinado instrumento, mas também a forma como o
som se inicia, se mantém e termina ao longo do tempo. Esta característica é
chamada envelope sonoro ou envoltória sonora. Ainda que as formas
de onda de dois instrumentos sejam muito parecidas, ainda poderíamos
distingui-las pelo seu envelope. O envelope é composto basicamente de quatro
momentos: Ataque, decaimento, sustentação e relaxamento(http://pt.wikipedia.org/wiki/Timbre).
A imagem acima mostra o
envelope característico de três instrumentos. O primeiro é de uma tabla, espécie de tambor da Índia.
Veja como o som surge quase instantaneamente após a percussão da pele pelas
mãos do executante e como cada nota tem uma duração muito curta. A segunda onda
mostra três notas produzidas por uma trompa. Aqui a
nota se inicia com um aumento mais gradual de intensidade,
sofre um pequeno decaimento após o início da nota e dura todo o tempo em que o
trompista mantém o sopro, desaparecendo de forma bastante rápida ao final das
notas. O terceiro exemplo mostra uma longa nota produzida por uma flauta. O som
surge muito suavemente, mantém-se com amplitude quase constante e depois
desaparece lentamente. Vejamos com mais detalhes cada um dos momentos presentes
nestes exemplos.
Ataque: é o início de cada nota musical.
Em um instrumento de corda tocado com arco, o som surge e aumenta lentamente de
intensidade, assim como no exemplo da flauta. Se a mesma corda for percutida o
som surgirá muito rapidamente e com intensidade alta. Dependendo do
instrumento, o ataque pode durar de alguns centésimos de segundo até mais de um
segundo.
Decaimento: em alguns instrumentos, após o
ataque o som sofre um decaimento de intensidade antes de se estabilizar. Em um
instrumento de sopro, por exemplo, isso pode se dever à força inicial
necessária para colocar a palheta em
vibração, após o que a força para manter a nota soando é menor. Normalmente
dura apenas de alguns centésimos a menos de um décimo de segundo. Nos exemplos
mostrados, o decaimento é claramente perceptível nas notas da tabla.
Sustentação: corresponde ao tempo de duração da
nota musical. Na maior parte dos instrumentos este tempo pode ser controlado
pelo executante. Durante este tempo a intensidade é mantida no mesmo nível,
como as notas da trompa e da flauta na imagem. Alguns instrumentos
(principalmente os de percussão) não permitem controlar este tempo. Em alguns
casos o som nem chega a se sustentar e o decaimento inicial já leva o som
diretamente ao seu desaparecimento, como na tabla.
Relaxamento: final da nota, quando a
intensidade sonora diminui até desaparecer completamente. Pode ser muito
brusco, como em um instrumento de sopro, quando o instrumentista corta o fluxo
de ar, ou muito lento, como em um gongo ou um piano com o pedal de sustentação
acionado. Na imagem acima, a nota da flauta tem um final suave devido à reverberação da
sala onde a música foi executada, que fez o som permanecer ainda por um tempo,
mesmo após o término do sopro.
A combinação entre os tempos de
ataque, decaimento, sustentação e relaxamento é tão importante para permitir
reconhecer o timbre de um instrumento, que em alguns casos usa-se um sintetizador ou sampler para
alterar estes tempos e criar timbres totalmente novos a partir do som de
instrumentos conhecidos (http://pt.wikipedia.org/wiki/Timbre).
terça-feira, 8 de maio de 2012
Captação de Frequência
Para fazermos a captação de frequência, usamos um código já disponível no blog http://labduino.blogspot.com.br/search/label/FFT%20com%20o%20Arduino, lá você encontrará uma pasta zipada com dois códigos e uma biblioteca e um slide mostrando sua utilização.
Além do arduino, também foi usado o programa Processing para exibir as frequências captadas:
Além do arduino, também foi usado o programa Processing para exibir as frequências captadas:
Códigos usados para o experimento:
Processing:
// Feel Free to edit these variables ///////////////////////////
String xLabel = "Frequency";
String yLabel = "Values";
String Heading = "Arduino FFT";
String URL = "01/02/2010";
float Vcc = 255.0; // the measured voltage of your usb
int NumOfVertDivisions=5; // dark gray
int NumOfVertSubDivisions=10; // light gray
int NumOfBars=64; // you can choose the number of bars, but it can cause issues
// since you should change what the arduino sends
// if these are changed, backgroung image has problems
// a plain background solves the problem
int ScreenWidth = 800, ScreenHeight=600;
/////////////////////////////////////////////////////////
// Serial port stuff ///////////////////////
import processing.serial.*;
Serial myPort;
boolean firstContact = false;
int[] serialInArray = new int[NumOfBars];
int serialCount = 0;
///////////////////////////////////////////////
int LeftMargin=100;
int RightMArgin=80;
int TextGap=50;
int GraphYposition=80;
float BarPercent = 0.4;
int value;
PFont font;
PImage bg;
int temp;
float yRatio = 0.58;
int BarGap, BarWidth, DivisounsWidth;
int[] bars = new int[NumOfBars];
void setup(){
bg = loadImage("BG.jpg");
/// NB SETTINGS ////////////////////////////////////////////////////////
myPort = new Serial(this, "COM10", 57600);
////////////////////////////////////////////////////////////////////////
DivisounsWidth = (ScreenWidth-LeftMargin-RightMArgin)/(NumOfBars);
BarWidth = int(BarPercent*float(DivisounsWidth));
BarGap = DivisounsWidth - BarWidth;
size(ScreenWidth,ScreenHeight);
font = createFont("Arial",12);
textAlign(CENTER);
textFont(font);
}
void draw(){
// background(bg); // My one used a background image, I've
background(250); // commented it out and put a plain colour
// Headings(); // Displays bar width, Bar gap or any variable.
Axis();
Labels();
PrintBars();
// Line();
// Dots();
}
// Send Recieve data //
void serialEvent(Serial myPort) {
// read a byte from the serial port:
int inByte = myPort.read();
if (firstContact == false) {
if (inByte == 'A') {
myPort.clear(); // clear the serial port buffer
firstContact = true; // you've had first contact from the microcontroller
myPort.write('A'); // ask for more
}
}
else {
// Add the latest byte from the serial port to array:
serialInArray[serialCount] = inByte;
serialCount++;
// If we have 6 bytes:
if (serialCount > NumOfBars -1 ) {
for (int x=0;x<NumOfBars;x++){
bars[x] = int (yRatio*(ScreenHeight)*(serialInArray[x]/256.0));
}
// Send a capital A to request new sensor readings:
myPort.write('A');
// Reset serialCount:
serialCount = 0;
}
}
}
/////// Display any variables for testing here//////////////
void Headings(){
fill(0 );
text("BarWidth",50,TextGap );
text("BarGap",250,TextGap );
text("DivisounsWidth",450,TextGap );
text(BarWidth,100,TextGap );
text(BarGap,300,TextGap );
text(DivisounsWidth,520,TextGap );
}
void PrintBars(){
int c=0;
for (int i=0;i<NumOfBars;i++){
fill((0xe4+c),(255-bars[i]+c),(0x1a+c));
stroke(90);
rect(i*DivisounsWidth+LeftMargin, ScreenHeight-GraphYposition, BarWidth, -bars[i]);
fill(0x2e,0x2a,0x2a);
// text(float(bars[i])/(yRatio*(ScreenHeight))*Vcc, i*DivisounsWidth+LeftMargin+BarWidth/2, ScreenHeight-bars[i]-5-GraphYposition );
// text("A", i*DivisounsWidth+LeftMargin+BarWidth/2 -5, ScreenHeight-GraphYposition+20 );
// text(i, i*DivisounsWidth+LeftMargin+BarWidth/2 +5, ScreenHeight-GraphYposition+20 );
}
}
void Axis(){
strokeWeight(1);
stroke(220);
for(float x=0;x<=NumOfVertSubDivisions;x++){
int bars=(ScreenHeight-GraphYposition)-int(yRatio*(ScreenHeight)*(x/NumOfVertSubDivisions));
line(LeftMargin-15,bars,ScreenWidth-RightMArgin-DivisounsWidth+50,bars);
}
strokeWeight(1);
stroke(180);
for(float x=0;x<=NumOfVertDivisions;x++){
int bars=(ScreenHeight-GraphYposition)-int(yRatio*(ScreenHeight)*(x/NumOfVertDivisions));
line(LeftMargin-15,bars,ScreenWidth-RightMArgin-DivisounsWidth+50,bars);
}
strokeWeight(2);
stroke(90);
line(LeftMargin-15, ScreenHeight-GraphYposition+2, ScreenWidth-RightMArgin-DivisounsWidth+50, ScreenHeight-GraphYposition+2);
line(LeftMargin-15,ScreenHeight-GraphYposition+2,LeftMargin-15,GraphYposition+80);
strokeWeight(1);
}
void Labels(){
textFont(font,18);
fill(50);
rotate(radians(-90));
text(yLabel,-ScreenHeight/2,LeftMargin-45);
textFont(font,10);
for(float x=0;x<=NumOfVertDivisions;x++){
int bars=(ScreenHeight-GraphYposition)-int(yRatio*(ScreenHeight)*(x/NumOfVertDivisions));
text(round(x),-bars,LeftMargin-20);
}
textFont(font,18);
rotate(radians(90));
text(xLabel,LeftMargin+(ScreenWidth-LeftMargin-RightMArgin-50)/2,ScreenHeight-GraphYposition+40);
textFont(font,24);
fill(50);
text(Heading,LeftMargin+(ScreenWidth-LeftMargin-RightMArgin-50)/2,70);
textFont(font);
fill(150);
text(URL,ScreenWidth-RightMArgin-40,ScreenHeight-15);
textFont(font);
}
Arduino:
/*
This Example acquire analog signal from A0 of Arduino, and Serial out to Processing application to visualize.
Tested with preamplified audio data. Take a look at http://www.youtube.com/watch?v=drYWullBWcI
Analog signal is captured at 9.6 KHz, 64 spectrum bands each 150Hz which can be change from adcInit()
Load the this file to Arduio, run Processing application.
Original Fixed point FFT library is from ELM Chan, http://elm-chan.org/works/akilcd/report_e.html
Ported to the library and demo codes are from AMurchick http://arduino.cc/forum/index.php/topic,37751.0.html
Processing code is from boolscott http://boolscott.wordpress.com/2010/02/04/arduino-processing-analogue-bar-graph-2/
*/
#include <stdint.h>
#include <ffft.h>
#define IR_AUDIO 0 // ADC channel to capture
volatile byte position = 0;
volatile long zero = 0;
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 */
void setup()
{
Serial.begin(57600);
adcInit();
adcCalb();
establishContact(); // send a byte to establish contact until Processing respon
}
void loop()
{
if (position == FFT_N)
{
fft_input(capture, bfly_buff);
fft_execute(bfly_buff);
fft_output(bfly_buff, spektrum);
for (byte i = 0; i < 64; i++){
Serial.print(spektrum[i],BYTE);
}
position = 0;
}
}
void establishContact() {
while (Serial.available() <= 0) {
Serial.print('A', BYTE); // send a capital A
delay(300);
}
}
// free running ADC fills capture buffer
ISR(ADC_vect)
{
if (position >= FFT_N)
return;
capture[position] = ADC + zero;
if (capture[position] == -1 || capture[position] == 1)
capture[position] = 0;
position++;
}
void adcInit(){
/* REFS0 : VCC use as a ref, IR_AUDIO : channel selection, ADEN : ADC Enable, ADSC : ADC Start, ADATE : ADC Auto Trigger Enable, ADIE : ADC Interrupt Enable, ADPS : ADC Prescaler */
// free running ADC mode, f = ( 16MHz / prescaler ) / 13 cycles per conversion
ADMUX = _BV(REFS0) | IR_AUDIO; // | _BV(ADLAR);
// ADCSRA = _BV(ADSC) | _BV(ADEN) | _BV(ADATE) | _BV(ADIE) | _BV(ADPS2) | _BV(ADPS1) //prescaler 64 : 19231 Hz - 300Hz per 64 divisions
ADCSRA = _BV(ADSC) | _BV(ADEN) | _BV(ADATE) | _BV(ADIE) | _BV(ADPS2) | _BV(ADPS1) | _BV(ADPS0); // prescaler 128 : 9615 Hz - 150 Hz per 64 divisions, better for most music
sei();
}
void adcCalb(){
Serial.println("Start to calc zero");
long midl = 0;
// get 2 meashurment at 2 sec
// on ADC input must be NO SIGNAL!!!
for (byte i = 0; i < 2; i++)
{
position = 0;
delay(100);
midl += capture[0];
delay(900);
}
zero = -midl/2;
Serial.println("Done.");
}
sábado, 5 de maio de 2012
Teste de captação com microfone
Teste de captação com o microfone
Neste primeiro teste, captamos os dados lidos pelo microfone com o Arduíno, que representam na verdade a tensão, lida em um intervalo decimal de 0 à 1023. A foto acima mostra o esquema do circuito e a de baixo mostra os detalhes da ligação dos fios. Onde o fio vermelho está ligado ao 5V, o preto ao terra e azul a porta analógica A0.
Depois de montado o circuito, partimos para a implementação do código, abaixo está o código e sua imagem no software Arduíno e sua respectiva saída pelo serial monitor quando falamos ao microfone.
(Código Arduíno: Teste de captação de som)
(Saída no Serial Monitor)
Assinar:
Postagens (Atom)