Infatti, una strada alternativa sono le reti neurali, ci avevo pensato.
Se fatto bene, sarebbe ancora meglio.
Prova ! Intanto io provo il metodo classico.
In python poi avrai librerie di NN gia' fatte e performanti.
Io un programma di reti retropropagate in C l'ho scritto.
Fa schifo a livello di leggibilita' ma per cose base funziona.
Prova Ele!!!
EDITSpiego come ho fatto a riconoscere un tono singolo (che per ora è già un successo)
* registro un file con audacity e lo salvo come wav.
* le caratteristiche sono 44100 hz sample rate, mono, 16 bit non compressi.
Una volta fatto il file, lancio il programma in C che lo apre in modalità binaria.
Cero la mia finestra di FFT da 8192 punti.
eseguo la FFT.
Inizialmente non funzionava, era perchè io la facevo solo sui primi 8192 campioni del file, quando invece devo ispezionare
tutto il file:
finestra_FFT=finestra_FFT+prossima finestra.
In questo modo ho la somma di tutti i pesi dei bit del file, che "intrinsecamente" contengono le frequenze.
Tutta questa somma la do alla fft, che fa il tutto a dovere, e quindi mi estrae i due picchi:
es tono 5:
1336 hz e 770 hz
C'era un problema però: io vado a cercare il picco (numero) più alto che mi rappresenta i 1336 hz, es 12800.
Ok, l'ho trovato facilmente. Ora devo trovare il picco del 770, cioè il secondo massimo.
In prossimità del 12800 (1336 hz) avrò sicuramente il secondo massimo, perchè il picco tende (se pur stretto) a scendere gradualmente.
E quindi non va bene.
Io ho ragionato così:
Registro a 44100 hz con una fft di 8182 punti.
Quindi la mia risoluzione in hz è: (44100/2)/(8182/2)=5.38 hz
Quindi nel mio array fatto di 8192 punti ogni posizione ha un step di 5. 38 hz.
Posizione 100 ? 5.38*100=538 hz
in posizione 100 leggerò l'intensità della frequenza 538 hz.
Abbiamo queste frequenze da analizzare:
1209,1336,1477,1633 (alte)
697,770,852,941. (basse)
Ora per ovviare al problema cosa faccio:
Vado a cercare il picco massimo, che è facile da trovare.
Ok, lo trovo.
Ora io so che la frequenza minima delle alte è:1209 hz, quindi 1209/5.38=224
Quindi dalla posizione dell'array fft 224-->FFT[224] in poi ci sono solo frequenze alte.
Quindi da li in poi azzero.
Riparto dall'inizio e trovo la minore.
Nel cercare i 2 picchi, mi conservo l'indice dell'array non il numero.
Di fatto a me serve l'indice per poter risalire alla frequenza:
indice*5.38=frequenza.
Una volta ottenuto, li mando a comparare, tenendo presente delle tolleranze dei 5.38 hz
Il 5 è : 1336 e 770
Ma io dalla mia fft potrei avere 1340 e 765, quindi do dei campi es:
CODICE
if (((F_max>1325) && (F_max<1345)) && ((f_max>755) && (f_max<780))) //1336 770
{puts("_5");return;}
Questo a grandi linee.
Per letture multiple...vediamo.
Intanto dovrei approfondire la FFT a livello teorico.
Qui una bozza del programma, non è il massimo, ma è davvero una prova:
CODICE
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include <fftw3.h>
#define N 8192
#define SAMPLE_R 22050
#define DATI_W 44
void cerca_max(double FFT[]);
void codifica (double F_max, double f_max);
void codifica (double F_max, double f_max)
{
if (((F_max>1200) && (F_max<1220)) && ((f_max>685) && (f_max<710))) //1209 697->1 (frequenze)
{puts("_1");return;}
if (((F_max>1325) && (F_max<1345)) && ((f_max>685) && (f_max<710))) //1336 697->2
{puts("_2");return;}
if (((F_max>1465) && (F_max<1485))&& ((f_max>685) && (f_max<710))) //1477 697->3
{puts("_3");return;}
if (((F_max>1200) && (F_max<1220)) && ((f_max>755) && (f_max<780))) //1209 770->4
{puts("_4");return;}
if (((F_max>1325) && (F_max<1345)) && ((f_max>755) && (f_max<780))) //1336 770->5
{puts("_5");return;}
if (((F_max>1465) && (F_max<1485)) && ((f_max>755) && (f_max<780))) //1477 770->6
{puts("_6");return;}
if (((F_max>1200) && (F_max<1220)) && ((f_max>840) && (f_max<865))) // 1209 852->7
{puts("_7");return;}
if (((F_max>1325) && (F_max<1345)) && ((f_max>840) && (f_max<865))) //1336 852->8
{puts("_8");return;}
if (((F_max>1465) && (F_max<1485)) && ((f_max>840) && (f_max<865))) //1477 852->9
{puts("_9");return;}
if (((F_max>1325) && (F_max<1345)) && ((f_max>930) && (f_max<955))) // 1336 941->0
{puts("_0");return;}
if (((F_max>1620) && (F_max<1645)) && ((f_max>685) && (f_max<710))) //1633 697->A
{puts("_A");return;}
if (((F_max>1620) && (F_max<1645)) && ((f_max>755) && (f_max<780))) //1633 770->B
{puts("_B");return;}
if (((F_max>1620) && (F_max<1645)) && ((f_max>840) && (f_max<865))) //1633 852->C
{puts("_C");return;}
if (((F_max>1620) && (F_max<1645)) && ((f_max>930)&& (f_max<955))) //1633 941->D
{puts("_D");return;}
if (((F_max>1465) && (F_max<1485)) && ((f_max>930) && (f_max<955))) // 1477 941->#
{puts("_#");return;}
if (((F_max>1200) && (F_max<1220)) && ((f_max>930) && (f_max<955))) //1209 941->*
{puts("_*");return;}
}
void cerca_max(double FFT[])
{
double step=SAMPLE_R/(N/2.0); //5.383
double F_max=0.0;
double f_max=0.0;
int index;
int i;
for (i=0; i<50; i++) // cancello primi dati
FFT[i]=0.0; // componente continua (???)
//*************************************
// cerco picco frequenza maggiore
for (i=0; i<N/2; i++)
{
if (FFT[i]>F_max)
{
F_max=FFT[i];
index=i;
}
}
printf ("HZ =%f\n", index*step);
F_max=index*step;
//************************************
for (i=200; i<N/2; i++) // azzero picchi frequenze maggiori
FFT[i]=0.0;
// cerco picchi frequenze minori
for (i=0; i<N/2; i++)
{
if (FFT[i]>f_max)
{
f_max=FFT[i];
index=i;
}
}
printf ("hz =%f\n", index*step);
f_max=index*step;
codifica (F_max,f_max);
}
int main(void) {
fftw_complex in[N], out[N]; /* double [2] */
fftw_plan p;
double FFT[N/2];
int i=0;
int ris=0;
short int w;
FILE *fd;
/* apre il file in lettura */
fd=fopen("d.wav", "rb");
if( fd==NULL )
{
perror("");
exit(1);
}
fseek(fd,DATI_W,SEEK_SET);// mi posiziono al byte 44. Nei files wav
// il 44° byte è dove partono i dati
/* ciclo di lettura */
/*********************************************************************/
/* converto i dati a 16 bits in dati numerici */
//*********************************************************************/
for (;;)
{
ris=fread(&w, sizeof(short int), 1, fd);
if( ris==0 )
break;
in[i%N][0]=in[i%N][0]+w;
in[i%N][1]=0;
i++;
}
fclose(fd);
/* forward Fourier transform, save the result in 'out' */
p = fftw_plan_dft_1d(N, in, out, FFTW_FORWARD, FFTW_ESTIMATE);
fftw_execute(p);
for (i = 0; i < N/2; i++) //memorizzo solo metà vettore
{
FFT[i]=(sqrt(out[i][0]*out[i][0])+ (out[i][1]*out[i][1]));
}
//printf ("%f\n", f);
fftw_destroy_plan(p); //praticante una free()
cerca_max (FFT);
return 0;
}
su ubuntu per compilare:
CODICE
gcc -Wall -g mio_file.c -o xx -lfftw3 -lm
Logicamente la fftw3 deve essere installata.
Edited by GILA75 - 3/5/2018, 21:15