Go Down

Topic: Leggere la frequenza di un suono (Read 1 time) previous topic - next topic

Stupendoman

Ciao a tutti, ci sono molti post che trattano questo argomento ma nessuno che arrivi a una soluzione comprensibile dal mio povero cervello... ho provato a seguire un post che parlava della libreria  Freqmeasure e quell'altro di amanda sulla frequency detection ma da solo non ne vengo a capo. Vorrei riconoscere le note usando un piezo come fa qualsiasi stupido accordatore per chitarra. Avete qualche risorsa da consigliarmi?
Grazie in anticipo

Cippa149

Ciao,
Credo che se vuoi risposte precise devi spiegarci meglio cosa non ti è chiaro perchè nessuno qui ti fa il progetto!

Comunque non ne so nulla di musica e quindi non ho mai sviluppato nulla che nemmeno si avvicini a quello che ti serve.
Penso che dovrai comprare un microfono e collegarlo ad arduino, leggere i dati e riconoscere la frequenza letta.
La frequenza la potresti calcolare contando il tempo trascorso per una serie di HI e LOW e HI ma non ne sono sicuro.

Ps
Se il tuo scopo è quello di fare un accordatore come quelli in commercio mi sa che non ne vale la pena.


menniti

Distinguiamo la convenienza dal divertimento, di convenienza non se ne parla visto che ora esistono decine di APP gratuite per smartphone che funzionano anche benino; se parliamo di divertimento allora la cosa è diversa; un semplice microfono collegato ad Arduino credo sia poco efficace in quanto il microfono capta di tutto, quindi tra esso e l'Arduino, volendo fare una cosa seria, occorrerebbe mettere una serie di filtri passa-banda con elevato Q, in modo che sulle uscite ci siano solo segnali sicuramente provenienti dalle corde della chitarra; servirebbe poi una commutazione (elettronica o manuale) per evitare la sovrapposizione delle uscite dei filtri e a quel punto si potrebbe leggere la frequenza del segnale con la lib dell'Arduino; a quel punto il software si occuperebbe di indicare se la frequenza letta è minore o maggiore di quella attesa, permettendo l'accordatura della corda. Parte dell'hardware si potrebbe eliminare sopperendo con il firmware così come la commutazione dei filtri, tutto dipende se si è più softwaristi o hardwaristi.....
Manuale "Arduino e le tecniche di programmazione dei microcontrollori ATMEL"
http://www.michelemenniti.it/manuale_di_programmazione.html
http://www.michelemenniti.it/offerta.html
Articoli ElettronicaIN
http://www.michelemenniti.it/elettronica_in.html

Etemenanki

Per eliminare ancora piu elementi, invece che un microfono si puo usare un piezo o un captatore agganciato con una molletta al corpo della chitarra, in modo da eliminare il piu possibile il rumore ambiente ;)
"Sopravvivere" e' attualmente l'unico lusso che la maggior parte dei Cittadini italiani,
sia pure a costo di enormi sacrifici, riesce ancora a permettersi.

Stupendoman

grazie mille per le risposte, ho provato inizialmente con il microfono, sono riuscito a fargli leggere delle frequenze ma non era assolutamente utilizzabile per il mio progetto, troppa confusione.
Allora ho preso questo piezo:

utilizzando questo sketch, da modificare poi una volta ottenuti risultati decenti (non sono un programmatore, trovo qualcosa di già fatto, cerco di capirlo e lo modifico in base alle mie esigenze):
Code: [Select]
/*
* Modified Arduino Frequency Detection
* by Nicole Grimwood
*
* For more information please visit:
* https://www.instructables.com/id/Arduino-Guitar-Tuner/
*
*
* Slightly edited version of:
* Arduino Frequency Detection
* created October 7, 2012
* by Amanda Ghassaei
*
* This code is in the public domain.
*/

//clipping indicator variables
boolean clipping = 0;

//data storage variables
byte newData = 0;
byte prevData = 0;
unsigned int time = 0;//keeps time and sends vales to store in timer[] occasionally
int timer[10];//storage for timing of events
int slope[10];//storage for slope of events
unsigned int totalTimer;//used to calculate period
unsigned int period;//storage for period of wave
byte index = 0;//current storage index
float frequency;//storage for frequency calculations
int maxSlope = 0;//used to calculate max slope as trigger point
int newSlope;//storage for incoming slope data

//variables for decided whether you have a match
byte noMatch = 0;//counts how many non-matches you've received to reset variables if it's been too long
byte slopeTol = 3;//slope tolerance- adjust this if you need
int timerTol = 10;//timer tolerance- adjust this if you need

//variables for amp detection
unsigned int ampTimer = 0;
byte maxAmp = 0;
byte checkMaxAmp;
byte ampThreshold = 50;//raise if you have a very noisy signal

void setup(){
 
  Serial.begin(9600);
 
  pinMode(13,OUTPUT);//led indicator pin
  pinMode(12,OUTPUT);//output pin
 
  cli();//diable interrupts
 
  //set up continuous sampling of analog pin 0 at 38.5kHz
 
  //clear ADCSRA and ADCSRB registers
  ADCSRA = 0;
  ADCSRB = 0;
 
  ADMUX |= (1 << REFS0); //set reference voltage
  ADMUX |= (1 << ADLAR); //left align the ADC value- so we can read highest 8 bits from ADCH register only
 
  ADCSRA |= (1 << ADPS2) | (1 << ADPS0); //set ADC clock with 32 prescaler- 16mHz/32=500kHz
  ADCSRA |= (1 << ADATE); //enabble auto trigger
  ADCSRA |= (1 << ADIE); //enable interrupts when measurement complete
  ADCSRA |= (1 << ADEN); //enable ADC
  ADCSRA |= (1 << ADSC); //start ADC measurements
 
  sei();//enable interrupts
}

ISR(ADC_vect) {//when new ADC value ready
 
  PORTB &= B11101111;//set pin 12 low
  prevData = newData;//store previous value
  newData = ADCH;//get value from A0
  if (prevData < 127 && newData >=127){//if increasing and crossing midpoint
    newSlope = newData - prevData;//calculate slope
    if (abs(newSlope-maxSlope)<slopeTol){//if slopes are ==
      //record new data and reset time
      slope[index] = newSlope;
      timer[index] = time;
      time = 0;
      if (index == 0){//new max slope just reset
        PORTB |= B00010000;//set pin 12 high
        noMatch = 0;
        index++;//increment index
      }
      else if (abs(timer[0]-timer[index])<timerTol && abs(slope[0]-newSlope)<slopeTol){//if timer duration and slopes match
        //sum timer values
        totalTimer = 0;
        for (byte i=0;i<index;i++){
          totalTimer+=timer[i];
        }
        period = totalTimer;//set period
        //reset new zero index values to compare with
        timer[0] = timer[index];
        slope[0] = slope[index];
        index = 1;//set index to 1
        PORTB |= B00010000;//set pin 12 high
        noMatch = 0;
      }
      else{//crossing midpoint but not match
        index++;//increment index
        if (index > 9){
          reset();
        }
      }
    }
    else if (newSlope>maxSlope){//if new slope is much larger than max slope
      maxSlope = newSlope;
      time = 0;//reset clock
      noMatch = 0;
      index = 0;//reset index
    }
    else{//slope not steep enough
      noMatch++;//increment no match counter
      if (noMatch>9){
        reset();
      }
    }
  }
   
  if (newData == 0 || newData == 1023){//if clipping
    clipping = 1;//currently clipping
    Serial.println("clipping");
  }
 
  time++;//increment timer at rate of 38.5kHz
 
  ampTimer++;//increment amplitude timer
  if (abs(127-ADCH)>maxAmp){
    maxAmp = abs(127-ADCH);
  }
  if (ampTimer==1000){
    ampTimer = 0;
    checkMaxAmp = maxAmp;
    maxAmp = 0;
  }
 
}

void reset(){//clean out some variables
  index = 0;//reset index
  noMatch = 0;//reset match couner
  maxSlope = 0;//reset slope
}


void checkClipping(){//manage clipping indication
  if (clipping){//if currently clipping
    clipping = 0;
  }
}


void loop(){
 
  checkClipping();
 
 
  if (checkMaxAmp>ampThreshold){
    frequency = 38462/float(period);//calculate frequency timer rate/period
 
    //print results
    Serial.print(frequency);
    Serial.println(" hz");
  }
 
  delay(100);
 
}


però dal serial monitor ottengo il valore "clipping" oppure "inf hz" e non capisco se sbaglio dalla parte elettronica o da quella software...

Cippa149

Scusa la mia ignoranza? E' un sensore di pressione?


Per il tuo problema ti spiace fare un copia incolla di quello che vedi a serial monitor.

Comunque guardando il programma, a monitor dovrebbe stampare "clipping" e "(valore frequency) hz". Se non stampa alcun valore allora credo tu debba eseguire la "tara" di alcuni valori come:
      int maxSlope = 0;// utilizzato per calcolare pendenza max come punto di innesco
      byte ampThreshold = 50; // aumentare se si dispone di un segnale molto rumoroso

Go Up