Processamento Digital de Sinais Engenharia Biomédica 2º Semestre 2009/2010 Análise Espectral 13 de Março de 2010 Grupo 10 Joana Nunes Nº 58497 João Marques Nº 58513 1. Construção da função dtmfdial() Este trabalho experimental baseia-se na utilização do sistema telefónico de marcação por tons designado por Dual Tone Multi-Frequency (DTMF). Neste sistema, cada tecla do telefone produz um som que resulta do somatório de duas ondas sinusoidais com frequências 𝑓𝑎 e 𝑓𝑏 . A correspondência entre estas frequências e o número marcado que foi utilizada na elaboração da função é a apresentada na Tabela 1. 𝒇𝒂 (𝑯𝒛) Tabela 1. Correspondência entre as frequências 𝒇𝒂 e 𝒇𝒃 e os números do telefone. 𝟏𝟐𝟎𝟗 1 4 7 * 𝟔𝟗𝟕 𝟕𝟕𝟎 𝟖𝟓𝟐 𝟗𝟒𝟏 𝒇𝒃 (𝑯𝒛) 𝟏𝟑𝟑𝟔 2 5 8 0 𝟏𝟒𝟒𝟕 3 6 9 # Na realização deste trabalho a frequência de amostragem utilizada do sinal é 8000𝐻𝑧. A função dtmfdial(), dado um número sob a forma de string, recorre à informação contida na Tabela 1 para identificar as frequências 𝑓𝑎 e 𝑓𝑏 , após esta identificação é calculado o sinal correspondente, através de 2𝜋𝑓𝑎 𝑛 sin ( 𝑓𝑠 ) + sin ( 2𝜋𝑓𝑏 𝑛 𝑓𝑠 ) (1) onde 𝑛 é o vector que indica a duração do impulso, neste caso 200𝑚𝑠. Entre cada impulso é ainda adicionada uma pausa, que corresponde a um vector de zeros com uma duração de 50𝑚𝑠. Código MATLAB function [ x ] = dtmfdial( number ) %DTMFDIAL Esta funcao serve para converter um número num tom com duas %frequencias. % O input number deve vir sob a forma de string e apenas conter % caracteres admissiveis. Exemplo: '218412345' %array de frequencias que correspondem a cada numero. %Exemplo: Ao numero 3 correspondem fa(3) e fb(3) fa=[697 697 697 770 770 770 852 852 852 941 941 941]; fb=[1209 1336 1447 1209 1336 1447 1209 1336 1447 1209 1336 1447]; %array com todos os digitos admissiveis 1 Trabalho 2 Análise Espectral Processamento Digital de Sinais tabdigitos='123456789*0#'; %frequencia de amostragem fs=8000; %inicializacao do vector de resposta x=[]; %vector pausa: corresponde a 50ms pausa = zeros(1,50*10^-3*8000); %vector sobre o qual se aplicarão os senos: duracao de 200ms n=1:200*10^-3*8000; for i=1:length(number) %encontrar o digito no array correspondente digito = findstr(number(i),tabdigitos); %calculo da parcela a acrescentar ao vector de resposta x=[x sin(2*pi*fa(digito)*n/fs)+sin(2*pi*fb(digito)*n/fs) pausa]; end %reproducao do som soundsc(x,fs); 2. Construção da função que detecta o número através de um ficheiro de som. A construção desta função foi também baseada nas informações contidas na Tabela 1 sobre as frequências do sinal. É também utilizado o espectrograma do sinal, para obter a informação sobre as frequências que o constituem. A função utilizada para este fim foi a inverso.m. Em primeiro lugar, é calculado o espectrograma do sinal, de onde se tira não só os valores deste (neste caso foram usados os valores absolutos de 0 até 1), mas também os vectores de frequência e de tempo. De seguida, o espectrograma é percorrido em dois ciclos numa tentativa de obter os instantes de tempo em que existem picos, e as respectivas frequências. Naturalmente tem-se o cuidado de a duração destes picos ser pelo menos 40𝑚𝑠. Sabendo depois as frequências, utiliza-se uma função auxiliar, detectadigito.m para fazer a correspondência entre as frequências encontradas e o respectivo dígito, recorrendo aos valores da Tabela 1. Por fim, o número encontrado é acrescentado à resposta e continua-se a análise. Para testar este algoritmo, fizeram-se testes com o ficheiro de som fornecido, através do comando inverso(wavread(‘touchtone.wav’)) e o resultado obtido foi ‘218418296’. Testou-se ainda inverso(dtmfdial(‘218411234’)) e o resultado obtido foi exactamente ‘218411234’. Código MATLAB function [ numero ] = inverso( x ) [B,F,T]=spectrogram(x,300,150,[],8000); %leitura do espectrograma B = abs(B); %calculo do valor absoluto %Spectrogram binarization Y = 1.0*(B > max(max(B)) * 0.9); %mesh(T, F, Y ); %plot 3D do espectrograma %calculo do tamanho minimo de um impulso, que equivale a 40ms nmin=round(40*10^-3*length(T)/max(T)); %resposta que começa como string vazia 2 Trabalho 2 Análise Espectral Processamento Digital de Sinais numero=''; i=1; %iteracao no vector de tempos while i<=length(T) j=1; f1=0; %primeira frequencia f2=0; %segunda frequencia %iteracao na frequencia while j<=length(F) if Y(j,i) == 1 %condicao de detecçao de pico if f1==0 %se ainda nao se tiver atribuido nenhuma frequencia f1=j; j=j+10; %garantir que nao se apanha 2 vezes a mesma frequencia elseif f2==0 %se ainda so se tiver apanhado 1 frequencia f2=j; j=length(F)+1; %saida da fronteira, ja temos 2 frequencias end else j=j+1; end end n=0;%comprimento do impulso detectado if (f1~=0 && f2~=0) %se houverem duas frequencias nao estamos numa pausa, mas num pico while ((Y(f1,i)==1 && Y(f2,i)==1)) %enquanto houver pico n=n+1; %incremento do comprimento do impulso i=i+1; %avanço no tempo end if n>=nmin %se o comprimento do impulso for maior que o minimo digito = detectadigito(f1*4000/length(F),f2*4000/length(F)); %encontrar o digito numero = [numero digito]; %acrescentar a resposta end else i=i+1; end end function [ digito ] = detectadigito( f1, f2 ) %DETECTADIGITO Função que dadas duas frequências devolve o digito %correspondente % Esta função faz a correspondência entre a tabela dada e as frequências % encontradas. Esta correspondencia e feita por proximidade, ou seja, se % as frequencias dadas nao forem um match exacto, sao localizadas as % frequencias da tabela que mais se aproximam. fa = [697 770 852 941]; fb = [1209 1336 1477]; dif = inf; fk1=0; 3 Trabalho 2 Análise Espectral Processamento Digital de Sinais fk2=0; for i=1:length(fa) if abs(fa(i)-f1)<dif fk1=fa(i); dif=abs(fa(i)-f1); end end dif=inf; for j=1:length(fb) if abs(fb(j)-f2)<dif fk2=fb(j); dif=abs(fb(j)-f2); end end if fk1 == 697 if fk2 == 1209 digito = '1'; elseif fk2 == 1336 digito = '2'; elseif fk2 == 1477 digito = '3'; end elseif fk1 == 770 if fk2 == 1209 digito = '4'; elseif fk2 == 1336 digito = '5'; elseif fk2 == 1477 digito = '6'; end elseif fk1 == 852 if fk2 == 1209 digito = '7'; elseif fk2 == 1336 digito = '8'; elseif fk2 == 1477 digito = '9'; end elseif fk1 == 941 if fk2 == 1209 digito = '*'; elseif fk2 == 1336 digito = '0'; elseif fk2 == 1477 digito = '#'; end end end 3. Ajuste do tamanho da janela temporal de detecção dos dígitos. O tamanho da janela utilizado para a detecção de dígitos é de grande importância, já que uma janela temporal demasiado curta apresenta uma boa resolução temporal e uma má resolução no domínio da frequência, enquanto que uma janela demasiado grande apresenta uma boa resolução na frequência, mas uma má resolução temporal. Assim, é necessário encontrar um compromisso entre tempo e frequência que 4 Trabalho 2 Análise Espectral Processamento Digital de Sinais seja propício à detecção dos dígitos correctamente. Neste caso, e utilizando sempre um overlap de metade do tamanho da janela, e para um número ‘123456789*0#’ que engloba todos os dígitos, verificou-se que janelas com um número de amostras inferior a 90 conduz a uma má detecção dos dígitos. Por outro lado, também se deixa de ter uma boa detecção com janelas superiores a 1200 amostras. Analisando estes valores, e tendo em conta que a duração dos impulsos é de 200𝑚𝑠 e a duração das pausas é de 50𝑚𝑠, estes resultados são bastante satisfatórios, já que 90 amostras corresponde (a uma frequência de amostragem de 8000 amostras/s) a cerca de 11𝑚𝑠, e 1200 amostras correspondem a 150𝑚𝑠, ou seja, o triplo da duração das pausas, levando à conclusão de que é possível obter bons resultados mesmo com uma janela demasiado grande, ou seja, com mais de o dobro da duração das pausas. 4. Introdução de uma componente aleatória na função implementada em 1. Com o objectivo de testar a robustez do algoritmo desenvolvido em 1., introduziu-se uma componente aleatória no sinal produzido. Esta alteração tem de ser feita com algum cuidado, já que demasiado ruído torna a reconstrução inversa impossível. Assim, introduziu-se uma componente aleatória de (no máximo) 3% da frequência normal. Estes 3% garantem que uma dada frequência não é, na altura da reconstrução, confundida com uma das frequências adjacentes. O código referente a esta alteração encontra-se na função dtmfdial_random.m. O único comentário feito no código refere-se exactamente a esta componente introduzida. Para testar esta introdução de uma componente aleatória no sinal, testou-se com o seguinte comando: inverso(dtmfdial_rand(‘218411234’)), obtendo como resultado ‘218411234’, tal como era esperado. Código MATLAB function [ x ] = dtmfdial_rand( number ) %DTMFDIAL_RAND funcao semelhante a dtmfdial_rand com componente aleatoria % A componente aleatoria introduzida depende da frequencia do tom, já que % é feita da forma f*(1+aleatorio()*3/100). Assim, o peso máximo que esta % componente tem é de 3%. Desta forma garante-se que não há overlap dumas % frequências para as outras, já que a detecção é feita por proximidade. fa=[697 697 697 770 770 770 852 852 852 941 941 941]; fb=[1209 1336 1447 1209 1336 1447 1209 1336 1447 1209 1336 1447]; tabdigitos='123456789*0#'; fs=8000; x=[]; pausa = zeros(1,50*10^-3*8000); n=1:200*10^-3*8000; for i=1:length(number) digito = findstr(number(i),tabdigitos); 5 Trabalho 2 Análise Espectral Processamento Digital de Sinais %calculo da parcela a acrescentar ao vector de resposta, com a %respectiva componente aleatoria x=[x sin(2*pi*fa(digito)*(1+3*aleatorio()/100)*n/fs)+sin(2*pi*fb(digito) *(1+3*aleatorio()/100)*n/fs) pausa]; end soundsc(x,fs); function [ n ] = aleatorio() % ALEATORIO: Funcao que devolve um número aleatório entre -1 e 1 % A função tem distribuicao de probabilidade uniforme. É obtido através % da funcao rand, que devolve um numero aleatorio uniforme entre 0 e 1. O % sinal é escolhido recorrendo a outro numero aleatorio com distribuicao % normal de valor medio 0 n=rand(); %numero entre 0 e 1 k=randn(); %numero com distribuicao normal if k<0 %condicao de troca de sinal n=-n; end end 5. Estabelecimento de uma chamada telefónica com a marcação do número feita através do algoritmo implementado Neste último ponto, experimentou-se marcar um número num telefone (fixo) encostando o microfone do telefone às colunas do PC. Para que funcione, é necessário abrir a linha do telefone (em telefones antigos isso não é necessário). Depois, correu-se a função dtmfdial(‘927564302’) com a linha do telefone aberta, e verificou-se que de facto a ligação é estabelecida como pretendido. 6