I have a mp3 file in the link below, where there is a man human voice and some humming noise in the background. I want the humming noise removed. Is there anyone who can tell me how to do it in MATLAB?
https://www.dropbox.com/s/h95y1oelbzvcgkc/allthatbass.mp3?dl=0
%% Read in the file
clearvars;
close all;
[f,fs] = audioread('allthatbass.mp3');
%% Play original file
pOrig = audioplayer(f,fs);
N = size(f,1);
%% Plot the spectrum
df = fs / N;
w = (-(N/2):(N/2)-1)*df;
y = fft(f(:,1), N) / N; % For normalizing, but not needed for our analysis
y2 = fftshift(y);
figure;
plot(w,abs(y2));
%% Design a bandpass filter that filters out between 700 to 12000 Hz
n = 7;
beginFreq = 700 / (fs/2);
endFreq = 12000 / (fs/2);
[b,a] = butter(n, [beginFreq, endFreq], 'bandpass');
%% Filter the signal
fOut = filter(b, a, f);
%% Construct audioplayer object and play
p = audioplayer(fOut, fs);
p.play;
I expect the humming noise removed, but the output sound like the original sound.
enter link description here
I have downloaded the original file you linked in your question and added the following line at the end:
audiowrite('filtered.wav', fOut, fs);
The resulting file 'filtered.wav' sounds very different to my ears (I used a headset to listen). If you open 'filtered.wav' for example in Audacity and take a look at the spectrum then it looks indeed different from the original (as expected, the frequencies below 700 Hz and above 12 kHz are removed).
Let's try to verify this in matlab. The following script reads both files and plots the dB value of both ffts. The lower plot represents the filtered signal and it is clearly visible that the bass frequencies are removed. The cut above 12 kHz is visible as well but it seems that these frequencies have already been attenuated in the original signal and the bandpass filter reinforces that.
%% Read in both files
clearvars;
close all;
[f,fs] = audioread('allthatbass.mp3');
[fflt, fsflt] = audioread('filtered.wav');
N = size(f,1);
%% Compute the ffts
df = fs / N;
n = N / 2; % plot only the second half of the spectrum
w = (0:(n)-1)*df;
y = fft(f(:,1), N) / N;
y2 = fftshift(y);
yflt = fft(fflt(:,1), N) / N;
y2flt = fftshift(yflt);
%% Plot the spectrum of both files (use the dB value, i.e. 10 * log(abs(x)) )
figure;
ax1 = subplot(2,1,1);
plot(w,10*log(abs(y2(n:end-1,1))));
ax2 = subplot(2,1,2);
plot(w, 10*log(abs(y2flt(n:end-1,1))));
linkaxes([ax1, ax2], 'y'); % link the axes (this makes it easier to visually compare the plots)
Try using a low pass filter in MATLAB. They're relatively easy to implement. You can find the documentation, along with examples, here.
Related
I'm trying to apply a bandpass around freq 0 without luck. I'd be happy to receive some help please
x=scan11(1,:)*1e-3/3e8; y=scan11(2,:);
plot(x,y) % my function
[XX,ff]=trans_fourier(y,mean(diff(x)));
plot(ff,abs(XX)) % gives the Fourier transform
I want to choose the freq around 0. let's suppose -1e13 till 1e13 and than to make ifft and to plot the signal after this filer.
How should I start doing this? the command
YY=bandpass(y,[-1e13 1e13],1/mean(diff(x)))
didn't help here unfortunately.
Since, i can't upload here files, here is also my question on matlab forum with all the files
matlab link
I am not sure what the contents of the trans_fourier function exactly are, but in 'plain matlab functions', you could attempt something along the lines of the following.
Nt = 1024; % Number of samples
Fs = 10; % Sampling frequency (samples / second)
t = (0:Nt-1)/Fs; % Time array
x = sin(t/10); % Low-frequency signal
x = x + 0.25*randn(1,Nt); % add some noise
X = fftshift(fft(x)); % FFT of signal with 0 Hz centered
fr = (-Nt/2 : Nt/2-1)/(Nt/Fs); % Frequency axis
% Filter: squared cosine (edit as desired)
fsl = 10; % Length of filter slope, in samples
filt = zeros(size(X));
filt(Nt/2+1+(-fsl:fsl)) = cos( linspace(-pi/2,pi/2,2*fsl+1) ).^2;
x_filt = real(ifft(ifftshift( filt.*X ))); % Filtered x
figure();
subplot(2,2,1); plot(t,x); ax=axis; title('original signal');
subplot(2,2,4); plot(t,x_filt); axis(ax); title('Low-pass filtered signal');
subplot(2,2,2); plot(fr,abs(X)); ax=axis; title('original amplitude spectrum');
subplot(2,2,3); plot(fr,abs(X).*filt); axis(ax); title('Filtered amplitude spectrum');
I am not sure what exactly you meant when you said
let's suppose -1e13 till 1e13
, but keep in mind that extracting a single fourier component (essentially setting all values of the spectrum to zero, except the one you are interested in) acts as a brick-wall filter, and you will get considerable artefacts if you take the inverse transform. Refer to this topic or this page if you're interested.
guys below are my code. I want to remove noise from audio signal which I added up by myself using random function.The following code removes somehow noise but it is still too noisy that I can't hear the sound. I also want to add the audio file for this code but i didn't find any option while posting my question so you can add any two channel .wav sound file . Any comment or hint will be helpful thanks.
close all
clear
clc
[x,fs] = audioread('cello.wav');
whos x;
pOrig = audioplayer(x,fs); %Signal Play
pOrig.play;
N = size(x,1);
figure;
subplot(2,1,1);
stem(1:N, x(:,1));
title('Left Channel of Origional signal');
subplot(2,1,2);
stem(1:N, x(:,2));
title('Right Channel of origional signal');
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
df = fs/N;
w = (-(N/2):(N/2)-1)*df;
y1= fft(x(:,1),N)/N;
y2 = fftshift(y1);
figure;
plot(w,abs(y2));
title('Fast Fourier Transform of Origional Signal')
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
pause
y=x;
y = y + randn(size(y));
pOrig = audioplayer(y,fs);
pOrig.play;
figure;
subplot(2,1,1);
stem(1:N, y(:,1));
title('Left Channel with Noise');
subplot(2,1,2);
stem(1:N, y(:,2));
title('Right Channel with Noise');
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
df = fs/N;
w = (-(N/2):(N/2)-1)*df;
y1= fft(y(:,1),N)/N;
y2 = fftshift(y1);
figure;
plot(w,abs(y2));
title('Fast Fourier Transform of Noisy Signal')
pause
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% filter design
n = 10;
beginFreq = 100 / (fs/2);
endFreq = 2000 / (fs/2);
%[b,a] = butter(n, endFreq, 'low');
%fout = filter(b,a,y); % input y(noisy signal)
[b,a] = butter(n, endFreq, 'low');
fout = filter(b,a,y); % input y(noisy signal)
figure;
subplot(2,1,1);
stem(1:N, fout(:,1));
title('Left channel after filtering');
subplot(2,1,2);
stem(1:N, fout(:,2));
title(' Right channel after filtering');
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%plot(fout);
df = fs/N;
w = (-(N/2):(N/2)-1)*df;
y1= fft(fout(:,1),N)/N;
y2 = fftshift(y1);
figure;
plot(w,abs(y2));
title('Fast Fourier Transform after filtering');
pOrig = audioplayer(fout,fs);
pOrig.play;
You are adding noise using randn() function, which generatares Gaussian noise, i.e. white noise. The white noise has constant power over the spectrum, that means you are adding noise from 0 to 20kHz (only considering the audio spectrum).
Your filter is a bandpass filter between 0.1-2 kHz, so according to what I pointed out above, you still have noise components in these frequency bands. Theoritecally, it is impossible to filter all of the noise components, however you may want to check out Wiener filters to get better results. Actually, it is the optimal filter if you know about the Gaussian noise parameters, which is only the variance of the noise in your case.
If you want to see an example that removes all the noise, you can add out-of-band noise on to your original signal. That is possible by generating a random sequence by rand() and using a filter to make it bandlimited. For example, filter the generated noise sequence with a 3-10kHz bandpass filter then add to the original audio sequence. Finally, apply the same butter filter in your script to see all the noise is removed.
I am trying to remove noise from a wav file. But I keep getting the following error after run the script.
The wav file I use is https://drive.google.com/file/d/0BzIyOj_KUKufTTNWMFlRMW9fT2c/view?usp=sharing
I use the code from Remove noise from wav file, MATLAB.
>> run sample3
Index exceeds matrix dimensions.
Error in sample3 (line 17)
stem(1:N, f(:,2));
Error in run (line 96)
evalin('caller', [script ';']);
Here is the code:
%% Read in the file
clearvars;
close all;
[f,fs] = audioread('noise.wav');
%% Play original file
pOrig = audioplayer(f,fs);
pOrig.play;
%% Plot both audio channels
N = size(f,1); % Determine total number of samples in audio file
figure;
subplot(2,1,1);
stem(1:N, f(:,1));
title('Left Channel');
subplot(2,1,2);
stem(1:N, f(:,2));
title('Right Channel');
%% Plot the spectrum
df = fs / N;
w = (-(N/2):(N/2)-1)*df;
y = fft(f(:,1), N) / N; % For normalizing, but not needed for our analysis
y2 = fftshift(y);
figure;
plot(w,abs(y2));
[B,A] = butter(n, [beginFreq, endFreq], 'bandpass');
%% Design a bandpass filter that filters out between 700 to 12000 Hz
n = 7;
beginFreq = 700 / (fs/2);
endFreq = 12000 / (fs/2);
[B,A] = butter(n, [beginFreq, endFreq], 'bandpass');
%% Filter the signal
fOut = filter(b, a, f);
%% Construct audioplayer object and play
p = audioplayer(fOut, fs);
p.play;
The code assumes that the signal is stereo (a.k.a. two channels). Your sound file most likely is mono (judging from the way it sounds... a.k.a. one channel), so any references in the code that uses the right channel should be removed.
Simply put, the only part of the code that is affected is displaying the right channel in time-domain. The rest of the code should work as it accesses the left channel in stereo, which is coincidentally the first column of the sound file and the only column in a mono file.
Replace this code:
N = size(f,1); % Determine total number of samples in audio file
figure;
subplot(2,1,1);
stem(1:N, f(:,1));
title('Left Channel');
subplot(2,1,2);
stem(1:N, f(:,2));
title('Right Channel');
with:
N = size(f,1); % Determine total number of samples in audio file
figure;
stem(1:N, f(:,1));
title('Mono Channel');
In the future, try and read the MATLAB errors more carefully. They're very verbose and descriptive on what the problem in your code is. In this case, it's complaining that you are trying to access a column in the sound file f that doesn't exist.
Note: I am the original author of the answer you have linked.
I studies on Digital Signal Filtering and I have a file includes some signal data. I wrote Matlab Program to get 23 to 27 Hz from original signal. but filtered signal is different. my desire filter is bandpass but my code work like low pass filter.
this is my code :
clc;
clear all;
load('SignalFile.mat');
%number of sample
SampleNumber = 60000;
%create hamming window
hamm = hamming((SampleNumber))'; %'
% there is 4 data in SignalFile.mat
for pl=1:4
% get name of data in signalFile.mat
data = eval(['mydata' num2str(pl)]);
[n,c] = size(data);
nk=SampleNumber;
% there is 2 signal in each data. but main signal exists on data(1:nk,1);
% nk is Sample Number.
mydata = data(1:nk,1) ;
encodedata = data(1:nk,2);
% Sample Rate my this file equal to data length / 4 ->> ~ 39000 sample
% per second.
fs = floor(n/4); % Sampling rate [Hz]
noSamples = nk; % Number of samples
f = 0 : fs/noSamples : fs - fs/noSamples; % Frequency vector
figure;
subplot(2,2,1);
plot(mydata);
x_fft = abs(fft(mydata));
subplot(2,2,2);
plot(f,x_fft);
xlim([1 100]);
centerf = 25; % 25 Hz Center
bw=2; %Bandwisth
fc=pi*centerf; %Center Frequency
L = nk; %sample number;
%Compute Filter
hsuup=(-(L-1)/2:(L-1)/2);
hideal1=hamm.*(2*(fc+bw)*(sin(2*(fc+bw)*hsuup/fs)./(2*(2*fc+bw)*hsuup/fs)));
hideal2=hamm.*(2*(fc-bw)*(sin(2*(fc-bw)*hsuup/fs)./(2*(2*fc+bw)*hsuup/fs)));
h_bpf=(hideal1-hideal2);
% transform mydata to Ferequency Domain
comp_sig_fft=fft(mydata)'; %'
% transform Filter Windows to Ferequency Domain
h_bpf_fft=fft(h_bpf);
% Filter Signal
s_fft=comp_sig_fft.*h_bpf_fft;
%
band_passed_signal=real(ifft(s_fft));
subplot(2,2,3);
plot(band_passed_signal);
x_fft = abs(fft(band_passed_signal));
subplot(2,2,4);
plot(f,x_fft);
xlim([1 100]);
end
is there any idea?
best regards.
my datafile uploaded here :
http://wikisend.com/download/574638/SignalFile.mat
result Images :
https://www.imageupload.co.uk/image/ZLzM
if you look at image, you can find under 20hz signal exists in filtered signal yet.
Im writing a MATLAB code to detect frequencies in piano recording.
I used a C scale audio file that i recorded using my keyboard (C4 D4 E4 F4 G4 A4 B4 C5)
When i simply perform an FFT (without breaking into windows) then the fundamental frequencies have a higher amplitude which is perfectly fine.
However to be more accurate i did the following steps
1. Did a fast convolution of my audio signal with a Gaussian edge detection filter to obtain the envelope.
2. Implemented a peak detecting algorithm to find the note onsets.
3. Taking each Onset, i performed an FFT on each, so as to get the FFT of each note.
However, when i do this for the above mentioned audio file, i get wrong results, at times the harmonics have a higher amplitude than the 1st.
clear all;
clear max;
clc;
%% create 5s sample at 10kHz with tone from 1s to 2s
FS = 10000; % 10kHz
N=5*FS;
song = randn(N,2)/10;
song(FS:2*FS,:)=10*repmat(sin(261*pi*2*(0:FS)/FS)',1,2)+song(FS:2*FS,:);
P = 2000;
t=0:1/FS:(N-1)/FS; % define time period
song = sum(song,2);
song=abs(song);
%----------------------Finding the envelope of the signal-----------------%
% Gaussian Filter
x = linspace( -1, 1, P); % create a vector of P values between -1 and 1 inclusive
sigma = 0.335; % standard deviation used in Gaussian formula
myFilter = -x .* exp( -(x.^2)/(2*sigma.^2)); % compute first derivative, but leave constants out
myFilter = myFilter / sum( abs( myFilter ) ); % normalize
% fft convolution
myFilter = myFilter(:); % create a column vector
song(length(song)+length(myFilter)-1) = 0; %zero pad song
myFilter(length(song)) = 0; %zero pad myFilter
edges =ifft(fft(song).*fft(myFilter));
tedges=edges(P:N+P-1); % shift by P/2 so peaks line up w/ edges
tedges=tedges/max(abs(tedges)); % normalize
%---------------------------Onset Detection-------------------------------%
% This section does the peak picking algorithm
max_col = maxtab(:,1);
peaks_det = max_col/FS;
No_of_peaks = length(peaks_det);
%---------------------------Performing FFT--------------------------------
song_seg = song(max_col(1):max_col(2)-1);
L = length(song_seg);
NFFT = 2^nextpow2(L); % Next power of 2 from length of y
seg_fft = fft(song_seg,NFFT);%/L;
f = FS/2*linspace(0,1,NFFT/2+1);
seg_fft2 = 2*abs(seg_fft(1:NFFT/2+1));
L5 = length(song_seg);
fmin = 60;
fmax = 1000;
region_of_interest = fmax>f & f>fmin;
froi = f(region_of_interest);
[p_max,loc] = max(seg_fft2(region_of_interest));
% index into froi to find the frequency of the peaks
p_max;
f_p_max = froi(loc);
[points, locatn] = findpeaks(seg_fft2(region_of_interest));
aboveMax = points > 0.4*p_max;
if any(aboveMax)
peak_points = points(aboveMax)
f_peak = froi(locatn(aboveMax))
end
end
What am I doing wrong here??? Really REALLY in need of some help here......
It can be seen that the f0 of D4 hasn't been detected at all, while the f0 of C4 and E4 have less amplitudes compared to their harmonics
Using the FFT, i found out the peak in the Frequency Domain. This may correspond to the fundamental note, if we are very lucky. Else, this may be the 1st harmonic generally.
I do not know whether the peak is at the fundamental or at the 1st harmonic.
My job is to find this out.
What i did was...
I have the "max_user_freq" variable that corresponds to the frequency at which the peak occurs in the FFT.
Note: "Spectrum[]" is the magnitude spec variable.
I calculate the maximum of the spectrum[m] where m ranges from frequency
Note : frequencies must be scaled to m. In my case : m=freq*length(fraw)/22050;
Complete Code:
f1=(max_freq/2)-0.05*max_freq;
f1=round(f1);
f2=(max_freq/2)+0.05*max_freq;
f2=round(f2);
m=[];
spec_index_fund_note=m;
spec_fund_max=spectrum(f1*length(fraw)/22050;
for m=f1:f2
spec_index_fund_note(m)=m*length(fraw)/22050;
if(spectrum(spec_index_fund_note(m))>spec_fund_max)
spec_fund_max=spectrum(spec_index_fund_note(m));
end
end
if((spectrum(max_freq_index)-specval_fund_note)/spectrum(max_freq_index)>)
display('1st Harmonic exceeds the fundamental, Retry');
end
Filtering abs(song) is fine for finding the envelope, but when it comes to finding the peaks you need to compute the fft the original signal (without the "abs").
To see the difference, try:
clear;
FS = 10000;
s=sin(261*pi*2*(0:FS)/FS);
NFFT = 2^nextpow2(length(s));
S1=fft(s,NFFT);
S2=fft(abs(s),NFFT);
f = FS/2*linspace(0,1,NFFT/2+1);
plot(f,abs(S1(1:NFFT/2+1))); % peak near 261
plot(f,abs(S2(1:NFFT/2+1))); % peak near 522
I code in matlab and develop applications that are useful for a Musician. I myself am a musician. So, i know the music theory t hat runs my algorithms.
I developed and algorithm in matlab that tells u the exact scale in which u are playing the piano. Have a Look
MATLAB MUSICIAN's BLOG