Sabemos que, em geral, a função de transferência de um filtro é dada por:
H(z)=∑Mk=0bkz−k∑Nk=0akz−k
Agora substitua z=ejω para avaliar a função de transferência no círculo unitário:
H(ejω)=∑Mk=0bke−jωk∑Nk=0ake−jωk
Assim, isso se torna apenas um problema de avaliação polinomial em um dado ω . Aqui estão os passos:
- Crie um vetor de frequências angulares ω=[0,…,π] para a primeira metade do espectro (não é necessário ir até 2π ) e salve-o
w
.
- Pré-cálculo do expoente e−jω em todos eles e armazene-o em variável
ze
.
- Use a
polyval
função para calcular os valores do numerador e denominador chamando polyval(b, ze)
:, divida-os e armazene-os H
. Porque estamos interessados em amplitude, então pegue o valor absoluto do resultado.
- Converta para a escala dB usando: HdB=20log10H - neste caso 1 é o valor de referência.
Colocando tudo isso no código:
%% Filter definition
a = [1 -0.5 -0.25]; % Some filter with lot's of static gain
b = [1 3 2];
%% My freqz calculation
N = 1024; % Number of points to evaluate at
upp = pi; % Evaluate only up to fs/2
% Create the vector of angular frequencies at one more point.
% After that remove the last element (Nyquist frequency)
w = linspace(0, pi, N+1);
w(end) = [];
ze = exp(-1j*w); % Pre-compute exponent
H = polyval(b, ze)./polyval(a, ze); % Evaluate transfer function and take the amplitude
Ha = abs(H);
Hdb = 20*log10(Ha); % Convert to dB scale
wn = w/pi;
% Plot and set axis limits
xlim = ([0 1]);
plot(wn, Hdb)
grid on
%% MATLAB freqz
figure
freqz(b,a)
Saída original de freqz
:
E a saída do meu script:
E comparação rápida em escala linear - parece ótimo!
[h_f, w_f] = freqz(b,a);
figure
xlim = ([0 1]);
plot(w, Ha) % mine
grid on
hold on
plot(w_f, abs(h_f), '--r') % MATLAB
legend({'my freqz','MATLAB freqz'})
Agora você pode reescrevê-lo em alguma função e adicionar poucas condições para torná-lo mais útil.
Outra maneira (proposta anteriormente é mais confiável) seria usar a propriedade fundamental, que a resposta de frequência de um filtro é uma Transformada de Fourier de sua resposta de impulso:
H(ω)=F{h(t)}
Portanto, você deve alimentar o sinal δ(t) , calcular a resposta do seu filtro e obter a FFT dele:
d = [zeros(1,length(w_f)) 1 zeros(1,length(w_f)-1)];
h = filter(b, a, d);
HH = abs(fft(h));
HH = HH(1:length(w_f));
Em comparação, isso produzirá o seguinte:
a = [1 -0.5 -0.25]; % Some filter with lot's of static gain
. Você pode me explicar a seleção desses parâmetros aqui, por favor. Estou lendo o manual do meu Matlab e ele diz[h,w] = freqz(hfilt,n)
em uma parte da sinapse. Você está dando dois filtros (a, b) parafreqz
. Os dois filtros estão dentrohfilt
? Ou um emn
?este é apenas um adendo à resposta de jojek, que é mais geral e perfeitamente boa quando se usa matemática de dupla precisão. quando há menos precisão, ocorre um "problema de cosseno" que surge quando a frequência na resposta de frequência é muito baixa (muito menor que Nyquist) e também quando as frequências ressonantes do filtro são muito baixas.
considere esta identidade trigonométrica:
que tem resposta de frequência complexa
que tem magnitude ao quadrado:
so, one can see that the magnitude frequency response|H(ejω)| is an even symmetry function and depends only on the cosines cos(ω) and cos(2ω) . for very low ω , the values of those cosines are so close to 1 that, with single-precision fixed or floating point, there are few bits remaining that differentiate those values from 1 . that is the "cosine problem".
using the trig identity above, you get for magnitude squared:
whereϕ≜sin2(ω2)
if your gear is intending to plot this as dB, it comes out as
so your division turns into subtraction, but you have to be able to compute logarithms to some base or another. numerically, you will have much less trouble with this for low frequencies than doing it the apparent way.
fonte