
Koizumi Junsaku's twin dragons - Kennin-ji Buddhist temple (Kyoto)
Seja o seguinte exemplo:
Vamos sintetizar uma onda formada por 3 senóides de diferentes frequências, defasadas entre si.
e vamos considerar que estamos amostrando este sinal usando a frequência de amostragem .
Então, período de amostragem seria:
Usando o Matlab, podemos sintetizar estas formas de onda:.
xxxxxxxxxx>> fs=1000;>> t=0: 1/fs: 1.5 - 1/fs; % até 1,5 segundos excluindo a última amostra>> % Note que 1/1000 = 1/fs = T = período de amostragem (== 1 ms)>> size(t) % confirmando tamanho do vetor criadoans = 1 1500>> f1=20;>> f2=30;>> f3=40;>> % Note que a eq. das ondas trabalha com frequência em rad/s e defasagem em radianos>> % Criando um vetor para cada onda que compôe o sinal y(t)>> y1=3*cos(2*pi*f1*t +0.2);>> y2=1*cos(2*pi*f2*t -0.3);>> y3=2*cos(2*pi*f3*t +2.4);>> % calculando a defasagem (angulo) de cada sinal em graus (e não radianos)>> 0.2*180/pians = 11.459>> -0.3*180/pians = -17.189>> 2.4*180/pians = 137.51>> % Criando o vetor do sinal y(t) ou y[kT]>> y=y1+y2+y3;>> % Verificando os primeiros 10 valores contidos nos vetores t e y's:>> [t(1:10)' y1(1:10)' y2(1:10)' y3(1:10)' y(1:10)']ans = 0 2.9402 0.95534 -1.4748 2.4207 0.001 2.8423 0.99379 -1.7644 2.0717 0.002 2.6996 0.99704 -1.9432 1.7535 0.003 2.5143 0.96496 -1.9998 1.4794 0.004 2.2894 0.89871 -1.9309 1.2572 0.005 2.0283 0.80061 -1.7405 1.0884 0.006 1.7353 0.67416 -1.4409 0.96861 0.007 1.4149 0.52382 -1.0507 0.88809 0.008 1.0722 0.35492 -0.59442 0.83271 0.009 0.71259 0.17345 -0.10084 0.7852>> % Podemos criar gráficos para entender melhor o que está sendo realizado:>> subplot(4,1,1) % cria e divide janela para 4 "linhas" x 1 "coluna" de gráficos>> plot(t,y1)>> axis([0 1.5 -3 3])>> ylabel('y_1(t)')>> subplot(4,1,2);>> plot(t,y2);>> axis([0 1.5 -3 3])>> ylabel('y_2(t)')>> subplot(4,1,3);>> plot(t,y3);>> axis([0 1.5 -3 3])>> ylabel('y_3(t)')>> subplot(4,1,4);>> plot(t,y)>> axis([0 1.5 -3 3]) % adequando "range" dos dados à ser mostrado>> axis([0 1.5 -4 4])>> axis([0 1.5 -5 5])>> ylabel('y(t)')>> xlabel('tempo (s)')Com isto acabamos obtendo uma figura (janela) com os seguintes gráficos:

Realizando a fft() sobre este sinal, resulta:
xxxxxxxxxx>> Y=fft(y); % apenas executando o algoritmo "FFT">> length(Y) % descobrindo tamanho do vetor criadoans = 1500>> size(y) % note que size(Y) == size(y)ans = 1 1500>> % os 2 vetores possuem o mesmo tamanhoAveriguando o conteúdo dos vetores:
xxxxxxxxxx>> y(1:5)ans = 2.4207 2.3613 2.2219 2.0045 1.7133>> y(1:5)'ans = 2.4207 2.3613 2.2219 2.0045 1.7133>> >> % O vetor com o resultado da FFT deve conter números complexos (como esperado):>> Y(1:5)'ans = -1.4619e-12 + 0i 4.9198e-13 + 4.5089e-13i 5.6033e-13 + 1.3287e-13i -1.9843e-12 - 1.3565e-13i 1.3518e-12 + 4.6719e-13i>> % mostrando uma outra faixa de valores:>> Y(30:34)'ans =ans = -1.3512e-12 + 4.7564e-12i 2205.1 - 447.01i 9.4282e-13 + 4.9381e-12i 5.111e-12 - 2.1211e-12i -3.011e-12 + 4.8694e-13i>>Note que alguns valores calculados correspondem praticamente à valores nulos (por exemplo: ). Mas nem todos os valores calculados são nulos (por exemplo: ).
O vetor (ou variável Y) é formado por números complexos porque representam amplitudes e fases das senóides presentes no sinal de entrada (vetor y).
Porém os dados brutos de são complicados para serem entendidos. É mais interessante calcular a amplitude (magnitude) dos valores envolvidos com o vetor :
xxxxxxxxxx>> Y_mag = abs(Y);Podemos verificar a magnitude de na mesma faixa de valores já explorada anteriormente:
xxxxxxxxxx>> Y_mag(30:34)'ans = 4.9446e-12 2250 5.0273e-12 5.5337e-12 3.0501e-12>> Obs.: Dependendo do formato adotado para mosrtrar dados, o Matlab pode parecer que gera outra resposta:
xxxxxxxxxx>> format short>> Y_mag(30:34)'ans = 1.0e+03 * 0.0000 2.2500 0.0000 0.0000 0.0000>> Neste documento, está sendo usando >> format shortg.
Podemos transformar o vetor y_mag num gráfico:
xxxxxxxxxx>> figure; plot(Y_mag)Com isto, será gerada uma figura como:

Note que aparecem alguns picos (correspondentes às frequências das senóides presentes no sinal) e há vales. O vetor é composto por 1500 pontos porque nosso vetor de entrada para a função fft possuia 1500 amostras.
O gráfico original do algortimo FFT é "refletido" entre seu lado esquerdo e seu lado direito (são simétricos). Para analisar o espectro resultante, basta então escolher um dos lados, normalmente o lado esquerdo. Podemos realizar um "zoom", separar o lado esquerdo na figura:
xxxxxxxxxx>> length(Y)ans = 1500>> length(Y)/2ans = 750>> axis([0 749 0 2500])O gráfico agora deve ter ficado como:

O detalhe é que o eixo X corresponde à frequência., mas não em Hz. Na realidade, o algoritmo FFT retorna a frequência na unidade de "bins", onde cada "bin" corresponde à ; onde: quantidade de amostras do sinal de entrada) e frequênica de amostragem adotada no vetor de entrada. O eixo Y corresponde à magnitude.
Podemos criar um vetor de frequências em Hz para o eixo X e melhorar um pouco o entendimento do gráfico anterior:
x
>> L=length(y)L = 1500>> eixo_freq=(fs/L)*(0:L-1);>> size(eixo_freq)ans = 1 1500>> figure; plot(eixo_freq, Y_mag);>> axis([0 749 0 2500])>> xlabel('Frequencia (Hz)')
No gráfico gerado anteriormente se aproveitou e foram acrescentados "Data Tips" para comprovar as frequências e aplitudes inicialmente calculadas para os picos da FFT executada sobre o sinal de entrada. Perceba que com exceção da amplitude, a frequência em que ocorrem os picos corresponde ao esperado.
Note que o intervalo de frequência onde termina a parte útil da FFT (lado esquerdo do gráfico) corresponde à metade do número de amostras multiplicado pelo fator bin. Podemos realizar um "zoom" na parte de baixas frequênicias e perceber que:
xxxxxxxxxxaxis([0 50 0 2500]) % mostra da freq 0 até 50 HzE o gráfico fica então:

Agora ficou fácil de perceber que o sinal usado para a FFT possui componente DC nula (na frequência de 0 Hz, a aplitude é nula) e que o sinal de entrada só possui componentes nas frequencias de 20, 30 e 40 Hz. O único "detalhe" é que a amplitude calculada pelo algoritmo de FTT não corresponde às amplitudes reais das senóides presentes no sinal (na realizada está relacionado com o número de amostras do sinal ingressado no algoritmo de FFT).
Ver também: Help Center da MathWorks: fft.
Para "corrigir" o eixo de magnitudes do espectro, devemos considerar que o algoritmo de FFT, escalona o vetor gerado, de um fator de (quantidade de amostras usadas). Então inicialmente temos que redimencionar o vetor fazendo a divisão por : . E depois temos que considerar o espectro "refletido" gerado pelo algoritmo FFT. Na realidade este espectro refletido é composto por pares conjugados complexos, e o espectro originalmente é bilateral (vetor abaixo). E ainda deve ser considerado que o primeiro elemento calculado no espectro, corresponde à frequência nula (0 Hz, nível DC do sinal).
Considerando os fatores anteriores, podemos gerar um novo gráfico do espectro do sinal de entrada , fazendo:
xxxxxxxxxx>> L=length(y);>> Y=fft(y);>> P2=abs(Y/L); % re-escalona magnitudes pelo fator L>> P1=P2(1:L/2+1); % estamos interessados apenas na primeira metade do espectro>> P1(2:end-1) = 2*P1(2:end-1); % convertendo magnitudes para espectro unilateral>> % Note que o primeiro valor, P1(1) não deve ser "duplicado" == nível DC do sinal>> f = fs/L*(0:(L/2)); % monta vetor das frequencias>> figure; plot(f,P1,"LineWidth",2) >> title('Espectro do sinal y[kT]')>> xlabel("Frequência (Hz)")>> ylabel('Magnitude, |FFT{y[kT]}|')>> grid
O cálculo anterior poderia ser simplificado para:
xxxxxxxxxx>> L/2ans = 750>> f2 = (fs/L)*(0:L-1); >> figure; plot(f2, Y_mag/(L/2));Que gera o mesmo gráfico anterior, mas com o gráfico ainda mostrando todo o espectro bilateral gerado originalmente pela função FFT:

Um zoom na frequencia até 50 Hz, usando o comando axis([0 50 0 3.5]), resulta em:

Podemos ainda separar a informação de fase espectral do sinal de entrada:
xxxxxxxxxx>> Y_phase = angle(Y); % calcula o ângulo (defasagem) em cada freq. mas em radianos% calculando angulo com graus e não radianos>> Y_phase_deg = Y_phase.*(180/pi);>> figure; plot(eixo_freq, Y_phase_deg);>> xlabel("Frequência (Hz)")>> ylabel('Fase (^o)')>> title('Fase do Espectro do sinal y[kT]')>> axis([0 749 -pi pi])E obtemos a seguinte figura:

Este diagrama não parece tão útil quanto o da magnitude do espectro do sinal. E note que os ângulos variam no intervalo: .
Podemos realizar um "zoom" na região de interesse:
x
>> axis([0 50 -200 200])

Mas provavelmente será melhor primeiro identificar os componentes frequênciaiss importantes (os "picos") no gráfico de magnitude do espectro do sinal e então, isolar na janela de comandos do Matlab, as fases que importam:
x
>> % Podemos descobrir as defasagens correspondendo aos picos encontrados no>> % espectro de magnitude do sinal>> index=find(eixo_freq>=20); % comando find localiza posições com resultado pesquisa>> index(1) % só nos interessa primeiro resultado da pesquisaans = 31>> eixo_freq(31)ans = 20>> Y_phase(31)ans = 0.2>> Y_phase_deg(31)ans = 11.459>> index=find(eixo_freq>=30);>> index(1)ans = 46>> % Agrupando alguns resultados>> [eixo_freq(46) Y_mag(46) Y_phase_deg(46)]ans = 30 750 -17.189>> [eixo_freq(46) Y_mag(46)/(L/2) Y_phase_deg(46)]ans = 30 1 -17.189>> [eixo_freq(31) Y_mag(31)/(L/2) Y_phase_deg(31)]ans = 20 3 11.459>> [eixo_freq(61) Y_mag(61)/(L/2) Y_phase_deg(61)]ans = 40 2 137.51>> % Comparando com a forma como geramos y[kT], coindide.>> % Outra forma de determinar alguns valores de fase:>> % Testando para a freq. de 30 Hz>> 30/(fs/L)ans = 45>> f(45)ans = 29.333>> f(46)ans = 30>> Y_phase(46)ans = -0.3O arquivo de dados refletindo os cálculos e variáveis criadas pode ser carregado aqui: fft_onda1.mat. E um arquivo de registros dos comandos usados, criado usando o comando
diary aula_23042024.txtpode ser obtido aqui: aula_23042024.txt.
A sequencia final de comandos que leva ao espectro de Magnitude do sinal de entrada pode ser feito da seguinte forma:
xxxxxxxxxx>> Y=fft(y);>> L=length(Y);>> P2 = abs(Y/L);>> P1 = P2(1:L/2+1);>> P1(2:end-1) = 2*P1(2:end-1);>> f = fs/L*(0:(L/2));>> figure;>> plot(f,P1,"LineWidth",3)>> title('Espectro do sinal y(t)')>> xlabel("freq. (Hz)")>> ylabel('|fft(y)|')>> % aplicando um "zoom" na região até 100 Hz:>> axis([0 100 0 3.5]) % mostra até freq de 100 Hz
Se for desejado mostrar uma espécie de tabela com os resultados obtidos:
x
>> [f(1:10)' P1(1:10)']ans = 0 1.4748 0.66667 9.8415e-16 1.3333 1.2844e-15 2 1.9895e-15 2.6667 1.2351e-15 3.3333 2.7656e-16 4 3.3826e-16 4.6667 1.6592e-16 5.3333 2.9896e-16 6 2.0694e-15>> [f(25:35)' P1(25:35)']ans = 16 4.9917e-16 16.667 2.2106e-15 17.333 2.3668e-15 18 4.0074e-15 18.667 5.6471e-15 19.333 7.2619e-15 20 3 20.667 6.7703e-15 21.333 6.9443e-15 22 4.434e-15 22.667 3.1823e-15>> Fim.
Sintetize um sinal oscilante usando a eq. abaixo:
onde amplitude (de pico) da onda, frequência da onda (em Hz) e defassagem do sinal (em radianos).
Plote as diferentes ondas para 1,5 ciclos da mesma quando:
a) ;
b)
Gráfico desta parte:

c)
d)
Gráfico destes últimos 2 itens (comparados com uma cosenoóide defasada de ):

Obs.: considere para os 3 casos, e Hz.
Perceba que:
-- ou seja, uma senóide = coseno atrasado de .
Possível solução:
xxxxxxxxxx>> A=1; f=200;>> T=1/f; t_fim=1.5*T;>> t=linspace(0,t_fim,500); % 500 pontos no intervalo >> phi=0;>> y=A*cos(2*pi*f*t+phi);>> figure; plot(t,y)>> t_fimt_fim = 0.0075>> axis([0 t_fim -1 1])>> title('cos(\omega t + 0^o)')>> % incluindo os outros casos à serem simulados>> phi_b=-90;>> yb=A*cos(2*pi*f*t+phi*pi/180);>> yb=A*cos(2*pi*f*t+phi_b*pi/180);>> phi_c=60;>> phi_d=-60;>> yc=A*cos(2*pi*f*t+phi_c*pi/180);>> yd=A*cos(2*pi*f*t+phi_d*pi/180);>> close all>> % 1o-gráfico>> figure; plot(t,y,'b-', t,yb,'m-')>> axis([0 t_fim -1 1])>> grid>> xlabel('tempo (segundos)')>> ylabel('Amplitude (Volts)')>> title('Sinais')>> legend('cos(\omega t+0^o)', 'cos(\omega t-90^o')>> % 2o-gráfico>> figure; plot(t,y,'b--', t,yc,'b-', t,yd,'m-')>> xlabel('tempo (segundos)')>> ylabel('Amplitude (Volts)')>> title('Sinais')>> legend('cos(\omega t+0^o)', 'cos(\omega t+60^o)', 'cos(\omega t-60^o)')>> axis([0 t_fim -1 1])Fim.
Fernando Passold, em 29/03/2024