Convolution Theorem via the fft in MATLAB - matlab

I'm in the process attempting to convolve and export an audio signal y(t) with a frequency response h(t) in different ways for a MATLAB project. It's been straightforward for the most part, however, I've run into difficulty when trying to convolve the signals using the Convolution Theorem.
I'm able to take the Fourier Transforms of both signals easily using the fft() function, but when I multiply those two results together then use the ifft() functionto find my final signal, the program always outputs garbage. I've tried playing around with padding the input with zeros, but it hasn't done much.
Here's the gist of the code I have at the moment (plot functions were removed for readability).
Y = fft(y);
H = fft(h);
F = Y*H;
f = ifft(F);
For those who are interested, the audio file is a 38 second long .wav file with a sample rate of 22050. The impulse response is the Cosine function between -pi/2 and pi/2.
Thanks in advance, any help is greatly appreciated.

I am a bit rusty with the Convolution Theorem, so I can say something wrong; but I will highlight two things:
The product in frequency should be an element-wise multiplication, i.e.
F=Y.*H.
The frequency response should be a cosine in frequency, not in time. I guess you want a frequency response that does low-pass filtering.
I played a bit with these ideas, and this is what I got:
clear all; close all; clc;
% Signal
load handel.mat;
%sound(y,Fs)
N = numel(y);
t = linspace(0,(N-1)/Fs,N);
% Response
H = abs(cos(linspace(0,pi,N))).';
% FFT product
Y = fft(y);
h = abs(ifft(H));
F = Y.*H;
f = abs(ifft(F));
% Plot
figure('Name','Time-domain');
subplot(3,1,1); plot(t,y); title('Signal');
subplot(3,1,2); plot(t,h); title('System');
subplot(3,1,3); plot(t,f); title('Output');
figure('Name','Frequency-domain');
subplot(3,1,1); plot(abs(Y)); title('Signal');
subplot(3,1,2); plot(abs(H)); title('System');
subplot(3,1,3); plot(abs(F)); title('Output');
% Play
sound(y,Fs);
sound(f,Fs);
In the frequency domain, it looks like the low-pass filtering is working. However, if you listen to the audio, the result for the Handel track is not amazing.
Don't forget to have a look at the good answer of Luis Mendo in here.

Related

Integration/differentiation through the FFT

I'm trying to understand how to perform an integration or differentiation of an FFT using MATLAB. However, I think I'm doing something wrong somewhere and would like to know what I'm missing...
Here's an example of an FFT integration that, to the best of my knowledge, should work but doesn't.
clc; clear all; close all;
Fs = 1000; % Sampling frequency
T = 1/Fs; % Sampling period
L = 1500; % Length of signal
t = (0:L-1)*T; % Time vector
f = Fs*(0:(L/2))/L;
omega = 2*pi.*f;
S is the time signal we are going to operate the FFT on, and dS is its derivative. We're going to apply an FFT to dS, and try to integrate that transform to get the same result as S.
S = 0.7*sin(2*pi*50*t) + sin(2*pi*120*t);
dS = 70*pi*cos(2*pi*50*t) + 140*pi*cos(2*pi*120*t);
P2 = fft(S);
Y = P2(1:L/2+1);
c = fft(dS);
dm = c(1:L/2+1);
From what I found online, to integrate an FFT, you need to multiply each FFT value by the corresponding omega*1i. I'm assuming each point on the FFT result correspond to the values of my frequency vector f.
for z = 1:length(f)
dm(z) = dm(z)./(1i*omega(z));
end
figure
semilogy(f,abs(Y),'b'); hold on
semilogy(f,abs(dm),'r');
We can see on the plot that both curves don't match: the FFT of the initial time signal S is different from the integral of the FFT of the differentiated time signal dS.
The main difference between your two plots is in the noise. Because you use a logarithmic y axis, the noise gets blown up and looks important. Pay attention to the magnitudes when comparing. Anything about 1015 times smaller than the peak value should be ignored. This is the precision of the floating-point numbers used.
The relevant part of these frequency spectra is the two peaks. And the difference there between the sine and cosine is the phase. But you are plotting the magnitude, so the function and its derivative will look the same. Plot the phase also! (but only where the magnitude is above the noise level).

How to remove noise in a sound with allpassfilter in matlab?

Hi all I have a sound with noise.I want to remove that noise how can I remove it?
Original Sound: Zamfir-EinsamerHirte
Noisy Sound: Zamfir-EinsamerHirte_noisy
[y4,Fs]=audioread('Zamfir-EinsamerHirte_noisy.ogg');
ffty4=fft(y4);
First I analysed the signal
shiftedffty4=fftshift(ffty4);
spectrumy41=abs(shiftedffty4);
phaseffty41 = angle(shiftedffty4);
N4=length(spectrumy41);
t4=-Fs/2:Fs/N4:Fs/2-Fs/N4;
spectrumy42=abs(fftshift(ffty4))/N4;
phaseffty42=angle(fftshift(ffty4));
Secondly I made a all pass filter with the same length of spectrum and product with fft of noisy sound and made inverse fft and removed imaginary parts and played the sound. The sound still with noise
allpassfilter=ones([N4,2]);
allpassfilter(spectrumy42>1e+06)=0;
filteredy4=allpassfilter.*ffty4;
filteredyeni4=ifft(filteredy4);
filteredyy4=real(filteredyeni4);
sound(filteredyy4,Fs);
But I couldn't remove noise.The problem is that I don't know how to make zero, the value of noise(location where has noise) in allpassfilter like below:
allpassfilter(spectrumy42>1e+06)=0;
How can I make it? !!!Any help will be appreciated!!!! Thanks in advance.
I downloaded the clean and noisy audio files.
First let's analyze a small portion of the audio.
n=1024*8; % a small portion of data
w1=1e5;
w2=w1+n-1;
sig_noisy=data_n(w1:w2,1); % noisy audio
sig_clean=data_c(w1:w2,1); % clean audio
figure; hold all
plot(sig_noisy,'b')
plot(sig_clean,'r','LineWidth',2)
ylim([-1.5 1.5])
legend('Noisy','Clean')
As it is seen here, the noisy audio is somehow saturated and
truncated version of clean signal. Truncating a signal cause harmonics
at larger frequencies. Let's look at the power spectrum
densities of the signals.
n=1024*1; % a smaller portion of data
w1=1e5;
w2=w1+n-1;
sig_noisy=data_n(w1:w2,1); % noisy
sig_clean=data_c(w1:w2,1); % clean
[psd_noisy, f] = pwelch(sig_noisy);
[psd_clean, ~] = pwelch(sig_clean);
figure; hold all
plot(f/pi,db(psd_noisy),'b')
plot(f/pi,db(psd_clean),'r')
xlabel('Normalized Freq.')
legend('Noisy','Clean')
You see that noisy audio has harmonics plus noise at high frequencies. Well, now if you assume that the characteristics of the noise is not changing through the end of the audio, then you can design a filter with looking at this small portion of the audio. Since you already have noisy and clean signal together, why not use deconvolution method.
For example, if you deconvolve the clean signal with the noisy one, then
you obtain the inverse response of your system (h_inv), which is also the filter coefficients which you can use to filter the noisy signal
(sig_noisy = sig_clean * h).
Here I use Wiener deconvolution method. Also note that this function is not meant to be used for images only, you can also use the deconvolution methods in Matlab with 1D signals.
h_inv=deconvwnr(sig_clean,sig_noisy);
figure,plot(h_inv)
legend('h^-^1')
As I said, this is the filter coefficients you need. For example if I filter the noisy signal with h_inv:
sig_filtered=conv(sig_noisy,h_inv,'same');
[psd_filtered, ~] = pwelch(sig_filtered);
figure; hold all
plot(f/pi,db(psd_noisy),'b')
plot(f/pi,db(psd_clean),'r')
plot(f/pi,db(psd_filtered),'k')
xlabel('Normalized Freq.')
legend('Noisy','Clean','Filtered')
The filtered signal spectrum is pretty close to the clean signal spectrum. Now that you have the filter coefficients, just filter the whole noisy audio with h_inv and listen to the result.
filtered_all=conv(data_n(:,1),h_inv,'same');
sound(filtered_all,48000)
You may try other deconvolution methods and see the results. You can also zero the unwanted spectrum in fourier domain and take inverse fourier for clean signal. However, since the signal is too long, you will have to do it in a sliding window. Alternatively, you can design cascaded notch filters to filter each harmonic separately.
I see that there are four stron harmonics. So design four notch filters for each and a low pass filter to filter high-frequency noise.
% First notch
fc1=0.0001; bw1=0.05; N=4;
f = fdesign.notch('N,F0,BW',N,fc1,bw1); h = design(f);
% Second notch
fc2=0.21; bw2=0.2;
f = fdesign.notch('N,F0,BW',N,fc2,bw2); h2 = design(f);
% Third notch
fc3=0.41; bw3=0.2;
f = fdesign.notch('N,F0,BW',N,fc3,bw3); h3 = design(f);
% Fourth notch
fc4=0.58; bw4=0.2;
f = fdesign.notch('N,F0,BW',N,fc4,bw4); h4 = design(f);
% A Final lowpass filter
f = fdesign.lowpass('Fp,Fst,Ap,Ast',0.6,0.65,1,30); h5 = design(f);
% Cascade the filters
hd = dfilt.cascade(h, h2, h3, h4, h5);
% See the filter characterisctic
ff=fvtool(hd,'Color','white');
% Now we can filter our
sig_filtered2 = filter(hd,sig_noisy);
[psd_filtered2,f] = pwelch(sig_filtered2);
figure; hold all
plot(f/pi,db(psd_noisy),'b');
plot(f/pi,db(psd_clean),'r');
plot(f/pi,db(psd_filtered2),'k');
xlabel('Normalized Freq.')
legend('Noisy','Clean','Filtered')
Now you can filter the whole audio
filtered_all2 = filter(hd,data_n(:,1));
sound(filtered_all2,48000)
Hope I helped.

Matlab: how to find fundamental frequency of a speech

I am new to Matlab and speech processing as well. I want to find the fundamental frequency of speech signal to determine the gender of the speaker. I removed the silence from the signal by analysing it within 10 msec periods.
After that I got the fft using this code :
abs(fft(input_signal_without_silences))
My plot of both the speech signal and the fft of it is below:
Now, I want to find the fundamental frequency but I could not understand which steps do I need to do this. Or do I misunderstand this concept?
As far as I have learnt, there are some methods like autocorrelation,
Since I am not familiar to both speech processing and matlab, any help and advice is very much appreciated.
The fft() help can solve most parts of your problem. I can give a brief overview of things based on the content of the help file.
At the moment what you are plotting is the two sided, unnormalized fft coefficients, which don't tell much. Use the following to get a more user informed spectral analysis of the voice signal. Using the single sided spectram you would be able to find the dominant frequency which might be the fundamental frequency of the speech signal.
y = []; %whatever your signal
T = 1e-2; % Sample time, 10 ms
Fs = 1/T; % Sampling frequency
L = length(y); % Length of signal
NFFT = 2^nextpow2(L); % Next power of 2 from length of y
Y = fft(y,NFFT)/L;
f = Fs/2*linspace(0,1,NFFT/2+1);
% Plot single-sided amplitude spectrum.
plot(f,2*abs(Y(1:NFFT/2+1)))
title('Single-Sided Amplitude Spectrum of y(t)')
xlabel('Frequency (Hz)')
ylabel('|Y(f)|')
The problem is that you have a plot of Amplitude vs Sample Number instead of a plot of Amplitude vs Frequency.In order to calculate the fundamental frequency you need to find the frequency that corresponds to the highest frequency.
Matlab returns frequencies from -fs/2 to fs/2 so the frequency at index n is
f = n * (fs/N) - (fs/2)
where f = frequency, fs = sampling frequency, N = number of points in FFT.
So basically all you need to do is get the index where the plot is highest and substitute it in the equation above to get an estimate of the fundamental frequency.Make sure n > N/2 so that your fundamental frequency is positive.

Frequency : Decibel plot using FFT in MATLAB

I am trying to use MATLAB to import a WAV file and create the type of diagram shown below. I am basically trying to pull frequency information and plot it according to decibels. Here is the code I am working with, but it doesn't seem to pull the frequency information correctly:
[x fs]=wavread('filename.wav');
dt=1/fs;%% time interval
X=fft(x);
df=1/(length(x)*dt); %% frequency interval
f=(1:length(X))*df;%% frequency vector
%% frequency domain plot, freq in hertz
figure
plot(f,abs(X))
Please help! Thank you!
In your code "X" contains the waveform information, not the frequency information. To get the frequency information of the soundfile you could use the FFT function. I use this (more elaborate, but still simple) code for what you want to do:
[FileName,PathName]=uigetfile('*.wav');
[y, Fs, nbits] = wavread(fullfile(PathName,FileName));
length_y=length(y);
NFFT = 2^nextpow2(length_y); % Next power of 2 from length of y
fft_y=fft(y,NFFT)/length_y;
f = Fs/2*linspace(0,1,NFFT/2+1);
semilogy(f,abs(fft_y(1:length(f))));
title('Single-Sided Amplitude Spectrum of y(t)')
xlabel('Frequency (Hz)')
ylabel('|Y(f)|')
I hope this is useful to you. The plot will not be in steps like the one you have shown, but that can also be achieved - using the "stairs" plot function.

Analyzing wav files in MATLAB

So I have this piano recording (in .wav format). I am able to do an FFT on the whole recording and identify frequencies.
However, according to some articles I read, its best if the wav file is broken down into windows, where each window would include one particular note.
For this I need to initially plot a "power envelope" of my time domain signal (considering the note average energy concept) therefore there'll be one increase and one decrease for each note and note onsets can be determined by checking the local minima.
This is where 'windows' are introduced, where each window consists of only one onset and then FFT is performed on each window.
Im having difficulty in plotting the power envelope and moving onto breaking it down into windows. Would appreciate some help with the Matlab coding for this.
The code I've used is pretty straightforward:
[wave,fs] = wavread ('c scale fast.wav'); % read file into memory */
%sound(wave,fs); % see what it sounds like */
wave = wave.*hamming(length(wave));
t = 0:1/fs:(length(wave)-1)/fs; % and get sampling frequency */
figure(2);
subplot(2,1,1);
plot(t,wave);
title('Wave File');
ylabel('Amplitude');
xlabel('Length (in seconds)');
L = length(wave);
NFFT = 2^nextpow2(L); % Next power of 2 from length of y
Y = fft(wave,NFFT)/L;
f = fs/2*linspace(0,1,NFFT/2+1);
% Plot single-sided amplitude spectrum.
subplot(2,1,2);
plot(f,2*abs(Y(1:NFFT/2+1)))
title('Single-Sided Amplitude Spectrum of y(t)')
xlabel('Frequency (Hz)')
ylabel('|Y(f)|')
After my signal (abs value of my wav file) is convolved with the Gaussian filter i try taking the 1st and 2nd derivatives, but i don't get an output when i try to plot it.
edges=fconv(abs(song),detect);
tedges=edges(P/2:N+P/2-1);
tedges=tedges/max(abs(tedges));
W= diff(tedge);
Z= diff(W);
It is when i try to plot W and Z that I don't get the output I need. My graph is empty in other words. I can't figure out what I'm doing wrong here...
Useful: http://blogs.mathworks.com/videos/2009/12/31/basics-finding-a-subset-of-a-matrix/
Basic flow:
for v=1:window_length:length(data)
data_subsection=data(v:v+window_length);
subsection_fft = fft(data_subsection);
plot(...);
end