Obtenir una imatge a partir d’un so

Fa pocs dies, un amic molt aficionat als concursos de programació, em va preguntar en què consistia la FFT. Li vaig explicar una mica per sobre i llavors em va ensenyar un problema que és el següent:

Tenim un fitxer d’àudio de dos canals amb tons de freqüència variant on la freqüència d’un correspon a un valor en l’eix X i la freqüencia de l’altre correspon a un valor de l’eix Y. L’imatge resultant ha de ser un text.

El problema està extret d’aquest zip i a la carpeta input es troben 10 fitxers .wav codificats d’aquesta manera: Challenge24h (problema Q)

El concepete és senzill però posar-lo a la pràctica no tant, sobretot si no has estudiat res de domini freqüencial ni Transformades de Fourier.

En aquest post veurem com vaig arribar a solucionar-lo i alguna curiositat que va sorgir al final

L’eina emprada ha estat Matlab però podeu utilitzar qualsevol llenguatge de programació en el que us sentiu còmodes per fer transformades i representar vectors

Degut a l’interès que tenia el meu amic en la FFT ho vaig abordar per aquí. La idea principal era agafar un tram de mostres suficient com por fer-li la FFT i trobar la frequència per guardar-la en un vector, i anar avançant per obtenir noves freqüències

data=wavread('1.wav'); %importem el fitxer 1.wav a la variable data
N=200; %el numero de mostres que agafem per fer la FFT
x=[];
y=[];

for i=1:N/5:length(data)-N

D=fft(data(i:N+i,1:2),2^13); %fem la fft i obtenim un D de 2^13 punts

%trobem quina freq és per a cada canal i ho guardem als vectors x i y
a=find(abs(D( :,1 ))==max(abs(D( :,1 ))));
b=find(abs(D( :,2 ))==max(abs(D( :,2 ))));
x=[x a(1)];
y=[y b(1)];

end %repetim mentre avançem de N/5 en N/5

%representem els dos vectors
scatter(x,y,'r','p')

La sortida d’aquest script és la següent:

Aquest programa només va funcionar amb els primer fitxers, tardava molt i no m’acaba d’agradar el mètode per obtenir la freqüència. La FFT no podia tenir menys punts perquè sino la freqüència no es detectava bé.

Així que per curiositat de què sortiria en els altres vaig intentar realitzar un pla B. Com es tracta de tons (sinusoides pures), si derivem la senyal tindrem la informació de la freqüència a l’amplitud.

Aquí es veu a l’esquerra la senyal sense derivar, i a la dreta la senyal derivada:

Un cop hem derivat només ens quedaria treure l’envolvent. Aquí us deixo l’script final:

[data,fm]=wavread('8.wav');
A=max(data( :,1 )); %amplitud de la senyal
d=zeros(length(data),2);    %sera la derivada

%derivem de manera cutre i obtenim una amplitud segons la freq
for i=1:length(data)-1
d(i,:)=(data(i+1,:)-data(i,:))*(fm/(2*pi*A));
end

%un cop derivat treiem l'envolvent
x=abs(hilbert(d( :,1 )));
y=abs(hilbert(d( :,2 )));

%dibuixem amb 1 punt de cada 30
m=1:30:length(x);
scatter(x(m),y(m),'.');

La forma de fer la derivada és molt tonta, simplement faig el pendent restant les dues mostres i dividint entre el que avances (1/fm), després divideixo per les constants per tal de que em quedin les coordenades en Hertz.

Us deixo com a repte poder fer això derivant i treient l’envolvent al vol i veure com es va dibuixant el text en temps real. Fins i tot es podria intentar crear nous audios amb imatges monocromàtiques.

La curiositat que vaig descobrir un cop solucionat el problema és que el que he ideat ha sigut un desmodulador digital de FM, de fet els dos canals dels WAVs són valors modulats en FM i jo sense caure-hi!! Espero que aquest quatrimestre de 2n de telecos m’ho expliquin millor, ja penjaré una actualització amb millores.

Anuncis

Deixa un comentari

Fill in your details below or click an icon to log in:

WordPress.com Logo

Esteu comentant fent servir el compte WordPress.com. Log Out / Canvia )

Twitter picture

Esteu comentant fent servir el compte Twitter. Log Out / Canvia )

Facebook photo

Esteu comentant fent servir el compte Facebook. Log Out / Canvia )

Google+ photo

Esteu comentant fent servir el compte Google+. Log Out / Canvia )

Connecting to %s