Matlab - Plotting filtered audio - matlab

I'm trying to plot a filtered audio, but I'm doing something wrong because the second plot shows nothing.
[wave,fs]=wavread('my-audio.wav');
t=0:1/fs:(length(wave)-1)/fs;
figure(1);plot(t,wave);
b = [1.1 1];
a = [-0.1 0 1];
FIR = filter(b,a,wave);
figure(2);plot(t,FIR);
The function I'm using is: H(z)=(z + 1.1)/(z^2 - 0.1)
What am I missing?
Thanks!

It looks like you've inverted the order of the coefficients in the a and b vectors. Inverting the order of coefficients is particularly dramatic for the feedback coefficients a which define the poles of the transfer function (and hence determine the stability of the filter). The resulting filtered output FIR thus likely exceeds numerical float capacity, which plot has trouble with.
According to filter's documentation, the a and b coefficients are defined using a transfer function of the form:
Since your transfer function is
you should be using the coefficients
b = [0 1 1.1]
a = [1 0 -0.1]

Related

Downsampling in MATLAB - why scaling filter coefficients?

Trying to undertsand how MATLAB does resampling, looking at toolbox/signal/resample.m.
This is the part where low-pass FIR filter coefficients are calculated:
fc = 1/2/pqmax;
L = 2*N*pqmax + 1;
h = firls( L-1, [0 2*fc 2*fc 1], [1 1 0 0]).*kaiser(L,bta)' ;
h = p*h/sum(h);
(In this case pqmax and p both represent downsampling ratio.)
Not sure what is the purpose of last line where all filter coefficients are scaled by downsampling ratio over coeffs sum, p/sum(h)? Does anyone know the theory behind?
MATLAB firls
MATLAB kaiser
firls theory: Least Squared Error Design of FIR Filters
In most filters, you want the output magnitude to remain equal after filtering, not scaled up or down.
Mathematically this is generally properly done in the filter equation, but in discrete numbers this doesnt generally doesn't apply.
If you divide the filer by its sum, you make sure that for any input data p, the filter will always have a general scale factor of 1, as its normalized. For a p=ones(1:1000,1), if sum(h) is not 1, the result after filtering will be scaled, i.e. the values of p_filtered will not be 1.

How do I plot the frequency response of a digital filter in MATLAB?

I am trying to graph the frequency response. I was asked to use filter in MATLAB, but since I've read the manual, I still don't get how it performs a Z transform.
I have the impulse response of the digital filter written below:
for i=1:22;
y(i)= 0;
end
x(22) = 1;
for k=23:2523
x(k) = 0;
end
for n = 22:2522;
y(n) = ((1/21)*x(n))+((20/21)*y(n-21));
end
plot(y);
It's just a feedback system of y[n] = 1/21*x[n] + 20/21*y[n-21]
Below are my calculations to compute the Z transform of the above system, which ultimately determines the impulse response:
Z(y) = Z((1/21)*x(n)+(20/21)*y(n-21))
Y(Z) = (1/21)X(Z)+(20/21)*Z.^-21Y(Z)
Z(Z)-(20/21)*Z.^-21Y(Z) = (1/21)X(Z)
Y(Z)(1-(20/21)*Z.^-21) = (1/21)X(Z) // divide by X(Z)*(1-(20/21)*Z.^-21)
Y(Z)/X(Z) = (1/21)/(1-(20/21)*Z.^-21)
H(Z) = (1/21)/(1-(20/21)*Z.^-21) // B = 1/21, A = 20/21
H(Z) = (B*Z.^21)/(Z.^21-A)
How can I plot the frequency response of H(Z)? Should I use filter?
If you just need to plot the impulse response it's easy. The impulse response is the response of the digital filter to a Dirac pulse. You already have the difference equation, so you're already in 'z' and you don't care about the 's', you don't have to perform the 's' to 'z' transform (which is a topic in itself!).
So just generate a signal x(n) consisting of zeros everywhere except the first sample x(1) being 1. Pass it through the filter (yes, your difference equation). The y(n) you get is your impulse response h(n). That's basically what you did.
And of course if you FFT this h(n) you get the phase and magnitude response.
Use freqz from the signal processing toolbox (hope you have it). You first need to find the Z-transform, which you have already done here:
Y(Z)/X(Z) = (1/21)/(1-(20/21)*Z.^-21)
freqz takes in a vector of coefficients which correspond to the numerator and denominator of your transfer function. It's called like so:
freqz(b, a);
b and a are the numerator and denominator coefficients of your transfer function. This will produce a figure that shows the magnitude and phase response (hence frequency response) of the above system.
Therefore, all you need is to do this:
b = 1/21;
a = [1 zeros(1,20) -(20/21)];
freqz(b, a)
Take special note of the a vector. It has 1, followed by 20 zeros, then followed by -(20/21). Because you have a coefficient to the power of -21 and nothing else other than the 1 before it, that means that those coefficients between -1 to -20 are zero, and there are 20 of these coefficients that are zero in total, which is why we need to fill in the vector with zeroes between the 1 and -(20/21) term.
We get:
If you want to plot the poles and zeroes of your filter, use a combination of tf and pzmap:
sys = tf(b, a, -1);
pzmap(sys);
tf creates a transfer function by specifying the numerator and denominator coefficients of your filter, and -1 implies it's a discrete-time filter, but we don't know what the sampling time is. pzmap plots the poles and zeroes in the z-domain with the unit-circle overlaid.
We get this:
This makes sense as you have no zeroes in your system, and 21 poles, as you have 21 delay elements when examining the discrete-time sequence in your example.
From Matlab's filter documentation:
filters the input data, x, using a rational transfer function defined by the numerator and denominator coefficients b and a, respectively.
As you might know, filtering an impulse input would give you the impulse response. It then remains to obtain those b and a coefficients.
You could either obtain those directly from the difference equation
y[n] = 1/21*x[n] + 20/21*y[n-21];
(as indicated in the rational transfer function link above) or equivalently from the rational transfer function you have derived:
%H(Z) = (B*Z.^21)/(Z.^21-A)
In either case, you should get the following a and b coefficients:
a = [1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -20/21];
% or equivalently: a=zeros(22,1); a(1)=1; a(22)=-20/21;
b = [1/21];
Thus,
% setup the impulse input
x = zeros(2500,1);
x(1) = 1;
% compute the impulse response
y = filter(b, a, x);
This impulse response can be plotted as you have done:
plot(y);
As far as how this related to the transform H(Z), the closed form expression you obtained can be evaluated in terms of a Laurent series expansion, which then has the coefficients of the time-domain y (impulse response) series.
However, H(z) is an analytic function defined in the |z| > R (where R=power(20/21,1/21) in your case) region of convergence in the complex plane. It is more typical to plot the frequency response, which corresponds to the H(z) evaluated on the unit-circle (i.e. for complex number satisfying |z|=1 or equivalently z = exp(j * theta) with theta in the [0-2pi] range). An efficient method to compute values of H(z) at regularly spaced points on that unit-circle is to take the FFT of the impulse response:
FrequencyResponse = fft(y);
figure(1);
plot(abs(FrequencyResponse));
figure(2);
plot(phase(FrequencyResponse));
P.S.: the computation of filter and fft can be done in the single call freqz if you have the signal processing toolbox (although you were specifically asked to use filter).

Derivative of Gaussian filter in Matlab

Is there a derivative of Gaussian filter function in Matlab? Would it be proper to convolve the Gaussian filter with [1 0 -1] to obtain the result?
As far as I know there is no built in derivative of Gaussian filter. You can very easily create one for yourself as follow:
For 2D
G1=fspecial('gauss',[round(k*sigma), round(k*sigma)], sigma);
[Gx,Gy] = gradient(G1);
[Gxx,Gxy] = gradient(Gx);
[Gyx,Gyy] = gradient(Gy);
Where k determine the size of it (depends to which extent you want support).
For 1D is the same, but you don't have two gradient directions, just one. Also you would create the gaussian filter in another way and I assume you already have your preferred method.
Here I gave you up to second order, but you can see the pattern here to proceed to further orders.
The convolving filter you posted ( [1 0 -1] ) looks like finite difference. Although yours I believe is conceptually right, the most correct and common way to do it is with [1 -1] or [-1 1], with that 0 in the middle you skip the central sample in approximating the derivative. This may work as well (but bare in mind that is an approximation that for higher orders diverge from true result), but I usually prefer the method I posted above.
Note: If you are indeed interested in 2D filters, Derivative of Gaussian family has the steerability property, meaning that you can easily create a filter for a Derivative of Gaussian in any direction from the one I gave you up. Supposing the direction you want is defined as
cos(theta), sin(theta)
Then the derivative of Gaussian in that direction is
Gtheta = cos(theta)*Gx + sin(theta)*Gy
If you reapply this recursively you can go to any order you like.
Of just use the derivative of a gaussian which is not more difficult then computing the gaussian itself.
G(x,y) = exp(-(x^2+y^2)/(2*s^2))
d/dx G(x, y) = -x/s^2 G(x,y)
d/dy G(x, y) = -y/s^2 G(x,y)
function [ y ] = dgaus( x,n )
%DGAUS nth derivative of exp(-x.^2)
odd=0*x;
even=exp(-x.^2);
for order=0:(floor(n/2)-1)
odd=-4*order*odd-2*x.*even;
even=-(4*order+2)*even-2*x.*odd;
end
if mod(n,2)==0
y=even;
else
y=-2*(n-1)*odd-2*x.*even;
end
end

Matlab - Signal Noise Removal

I have a vector of data, which contains integers in the range -20 20.
Bellow is a plot with the values:
This is a sample of 96 elements from the vector data. The majority of the elements are situated in the interval -2, 2, as can be seen from the above plot.
I want to eliminate the noise from the data. I want to eliminate the low amplitude peaks, and keep the high amplitude peak, namely, peaks like the one at index 74.
Basically, I just want to increase the contrast between the high amplitude peaks and low amplitude peaks, and if it would be possible to eliminate the low amplitude peaks.
Could you please suggest me a way of doing this?
I have tried mapstd function, but the problem is that it also normalizes that high amplitude peak.
I was thinking at using the wavelet transform toolbox, but I don't know exact how to reconstruct the data from the wavelet decomposition coefficients.
Can you recommend me a way of doing this?
One approach to detect outliers is to use the three standard deviation rule. An example:
%# some random data resembling yours
x = randn(100,1);
x(75) = -14;
subplot(211), plot(x)
%# tone down the noisy points
mu = mean(x); sd = std(x); Z = 3;
idx = ( abs(x-mu) > Z*sd ); %# outliers
x(idx) = Z*sd .* sign(x(idx)); %# cap values at 3*STD(X)
subplot(212), plot(x)
EDIT:
It seems I misunderstood the goal here. If you want to do the opposite, maybe something like this instead:
%# some random data resembling yours
x = randn(100,1);
x(75) = -14; x(25) = 20;
subplot(211), plot(x)
%# zero out everything but the high peaks
mu = mean(x); sd = std(x); Z = 3;
x( abs(x-mu) < Z*sd ) = 0;
subplot(212), plot(x)
If it's for demonstrative purposes only, and you're not actually going to be using these scaled values for anything, I sometimes like to increase contrast in the following way:
% your data is in variable 'a'
plot(a.*abs(a)/max(abs(a)))
edit: since we're posting images, here's mine (before/after):
You might try a split window filter. If x is your current sample, the filter would look something like:
k = [L L L L L L 0 0 0 x 0 0 0 R R R R R R]
For each sample x, you average a band of surrounding samples on the left (L) and a band of surrounding samples on the right. If your samples are positive and negative (as yours are) you should take the abs. value first. You then divide the sample x by the average value of these surrounding samples.
y[n] = x[n] / mean(abs(x([L R])))
Each time you do this the peaks are accentuated and the noise is flattened. You can do more than one pass to increase the effect. It is somewhat sensitive to the selection of the widths of these bands, but can work. For example:
Two passes:
What you actually need is some kind of compression to scale your data, that is: values between -2 and 2 are scale by a certain factor and everything else is scaled by another factor. A crude way to accomplish such a thing, is by putting all small values to zero, i.e.
x = randn(1,100)/2; x(50) = 20; x(25) = -15; % just generating some data
threshold = 2;
smallValues = (abs(x) <= threshold);
y = x;
y(smallValues) = 0;
figure;
plot(x,'DisplayName','x'); hold on;
plot(y,'r','DisplayName','y');
legend show;
Please do not that this is a very nonlinear operation (e.g. when you have wanted peaks valued at 2.1 and 1.9, they will produce very different behavior: one will be removed, the other will be kept). So for displaying, this might be all you need, for further processing it might depend on what you are trying to do.
To eliminate the low amplitude peaks, you're going to equate all the low amplitude signal to noise and ignore.
If you have any apriori knowledge, just use it.
if your signal is a, then
a(abs(a)<X) = 0
where X is the max expected size of your noise.
If you want to get fancy, and find this "on the fly" then, use kmeans of 3. It's in the statistics toolbox, here:
http://www.mathworks.com/help/toolbox/stats/kmeans.html
Alternatively, you can use Otsu's method on the absolute values of the data, and use the sign back.
Note, these and every other technique I've seen on this thread is assuming you are doing post processing. If you are doing this processing in real time, things will have to change.

How to make a Simple FIR Filter using Matlab?

How can I make a simple low-pass FIR filter using Matlab (without using the built-in function) ?
Problem example:
Implement a FIR LPF with cut-off frequency 250Hz
it may also be necessary that, sampling freq is given...
Solution attempt or what I already know:
x = [...] -> input signal
A = 1; -> Since this is FIR
B = [?????]
y = filter(B, A, x) -> Output signal
Afaik, B should contain the coefficients for the FIR filter. But; how do I calculate these coefficients given that I only have the cut-off frequency?
The simplest thing is a "windowed sinc" filter:
fs = 44100;
cutoff = 250;
t = -256:256; % This will be a 513-tap filter
r = 2*cutoff/fs;
B = sinc(r*t).*r .* blackman(length(t))';
freqz(B);
The length of the filter (see t=...) controls the width of the transition band. cutoff is in this case the -6 dB point. blackman is the name of a popular window. You can check out this Wikipedia page for more infos on window functions. They basically have different trade-offs between transition band width and stopband rejection.
If you wan't a different shape of the amplitude spectrum, do exactly as sellibitze suggested, only replace the sinc function with the real part of the inverse Fourier-transform of the desired amplitude response (delayed to get causal symmetrical impulse response).
Since the Coefficients to a LTI filter are the time domain impulse response, you could create the frequency response in matlab by specifying an Amplitude vector, and and Phase Vector, then Inverse FFT them to get your coefficients, for example, soemthing like A = [ 1 .9 .8 .5 .2 .1 0], theta=[0 0 0 0 0 0 0], then H=A.*exp(j*theta) then coefs = ifft(H)