I'm using below codes to fo FFT first and then take the first 10 bigger amplitudes of FFT and corresponding frequency and phase informations.
At the end of te code, i'm trying to rebuild the original signal as much as possible but not using ifft because of the implementation that i'm trying.
Finally, i'm trying to write the .wav but getting "too many output arguments." error always.
Could you pls let me know about your feedbacks?
close all
clear all
clc
[audio,Fs]=audioread('C:\Users\xaol\Desktop\sound.wma');
audioinfo('C:\Users\xaol\Desktop\sound.wma')
player=audioplayer(audio,44100); play(player)
length_audio=length(audio);
%plot(audio);
audio1=audio(2^16:2^17); %taking a part of audio
audio_part=2^17-2^16; %the lenght of taken part
plot(audio1);
title('original partly signal');
player=audioplayer(audio1,44100); play(player)
%% FFT
NFFT = audio_part;
Y = fft(audio1,NFFT)/length(audio1);
fs=length(audio1)/length(audio1);
f = fs/2*linspace(0,1,NFFT/2+1);
[B,IX] = sort(abs(Y(1:NFFT/2+1))); %order the amplitudes
Amplitudes=B; %find all amplitudes
Frequencies=f(IX(1+end-numel(Amplitudes):end)); %frequency of the peaks
Phases=angle(abs(Y));
%% 10 bigger amplitudes and corresponding frequency and phase are being found
A=B((length(IX)-9):(length(IX)));
F=Frequencies((length(IX)-9):(length(IX)));
P=angle(Y(IX((length(IX)-9):length(IX))))*180/pi;
FAP=[F;A;P]
%FAP is 3x10 matrix which includes frequency, amplitude and phase info
%% REBUILD ORIGINAL SIGNAL
ii=length(FAP);
org_audio=0;
t=0:length(audio1);
for i=1:1:ii
org_audio=4*FAP(2,i)*exp(j*2*pi*FAP(1,i)*t+j*(pi/180)*FAP(3,i))+org_audio;
end
figure, plot(t,org_audio)
audio_r1=abs(org_audio);
audio_r(:,1)=(audio_r1)';
audio_r(:,2)=audio_r(:,1);
filename='C:\Users\xaol\Desktop\sound2.wav';
AU=audiowrite(filename,audio_r,44100);
Well, as the error suggests you have "too many output arguments". By looking at your code I believe that the problem is that audiowrite does not return any output arguments (have a look at http://www.mathworks.com/help/matlab/ref/audiowrite.html). You should use
audiowrite(filename,audio_r,44100);
instead.
In any case, you should learn how to use the MATLAB debugger (http://www.mathworks.com/help/matlab/debugging-code.html) in order to identify where your error is.
BTW, the line Phases = angle(abs(Y)) makes on sense as the absolute values do not have phase. Did you mean Phases = angle(Y)?
Related
I am writing a piece of code that figures out what frequencies(notes) are being played at any given time of a song (note currently I am testing it grabbing only the first second of the song). To do this I break the first second of the audio file into 8 different chunks. Then I perform an FFT on each chunk and plot it with the following code:
% Taking a second of an audio file and breaking it into n many chunks and
% figuring out what frequencies make up each of those chunks
clear all;
% Read Audio
fs = 44100; % sample frequency (Hz)
full = audioread('song.wav');
% Perform fft and get frequencies
chunks = 8; % How many chunks to break wave into
for i = 1:chunks
beginningChunk = (i-1)*fs/chunks+1
endChunk = i*fs/chunks
x = full(beginningChunk:endChunk);
y = fft(x);
n = length(x); % number of samples in chunk
amp = abs(y)/n; % amplitude of the DFT
%%%amp = amp(1:fs/2/chunks); % note this is my attempt that I think is wrong
f = (0:n-1)*(fs/n); % frequency range
%%%f = f(1:fs/2/chunks); % note this is my attempt that I think is wrong
figure(i);
plot(f,amp)
xlabel('Frequency')
ylabel('amplitude')
end
When I do that I get graphs that look like these:
It looks like I am plotting too many points because the frequencies go up in magnitude at the far right of graphs so I think I am using the double sided spectrum. I think I need to only use the samples from 1:fs/2, the problem is I don't have a big enough matrix to grab that many points. I tried going from 1:fs/2/chunks, but I am unconvinced those are the right values so I commented those out. How can I find the single sided spectrum when there are less than fs/2 samples?
As a side note when I plot all the graphs I notice the frequencies given are almost exactly the same. This is surprising to me because I thought I made the chunks small enough that only the frequency that's happening at the exact time should be grabbed -- and therefore I would be getting the current note being played. If anyone knows how I can single out what note is being played at each time better that information would be greatly appreciated.
For a single-sided FT simply take the first half of the output of the FFT algorithm. The other half (the nagative frequencies) is redundant given that your input is real-valued.
1/8 second is quite long. Note that relevant frequencies are around 160-1600 Hz, if I remeber correctly (music is not my specialty). Those will be in the left-most region of your FT. The highest frequency you compute (after dropping the right half of FFT) is half your sampling frequency, 44.1/2 kHz. The lowest frequency, and the distance between samples, is given by the length of your transform (44.1 kHz / number of samples).
I have a large pulse oxymetery signal. Some part of that is noisy and will corrupt my data if I use it. Do you have any strategy to automatically remove the noisy part? (Since the data is very long and there are many channels, I can't really do it manually).
Please find the picture attached to have a feeling of the signal.
You can filter it but you need to know the spectral characteristics of the signal so you can extract it or the spectral characteristics of the noise so you can suppress it. Do you have a signal that doesn't have noise or do you know where in the spectrum your signal of interest lies?
This might be the problem identical to removing outliers from time series.
This problem can be solved by fitting the time series with a given model as shown in the this link. For example, try the following simulation codes.
xdata = (0:0.1:2*pi)';
y0 = sin(xdata); % pure data
gnoise = y0.*randn(size(y0)); % noise component
ydata = y0 + gnoise;
f = fittype('a*sin(b*x)');
fit1 = fit(xdata,ydata,f,'StartPoint',[1 1]);
plot(fit1,'r-',xdata,ydata,'k.',outliers,'m*')
xlim([0 2*pi])
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
I was trying to plot STFT using plot3 in MATLAB but failed. Can somebody guide me how to do that? My MWE is given below:
%% STFT Computataion
clear; clc; clf;
%% Get input and calculate frame size and overlap/shift
[Y,Fs]=wavread('D_NEHU_F0001_MN_10001');
frame_size=round(20*Fs/1000); % calculate frame size for 20ms
frame_shift=round(10*Fs/1000); % calculate frame shift for 10ms
%% Plot the input signal in time domain
t=1/Fs:1/Fs:(length(Y)/Fs);
subplot(2,1,1)
plot(t,Y);
title('Speech signal in time domain');
ylabel('Magnitude of samples');
xlabel('time in seconds');
%% Calculation of STFT
%NoOfFrames=floor((length(Y)/frame_shift)-1);
NoOfFrames=length(Y)-frame_size;
j=1;
%for i=1:frame_shift:(length(Y)-frame_size)
for i=1:frame_shift:((length(Y)-frame_size))%+frame_shift)
sp_frame=Y(i:(i+frame_size)).*hamming(frame_size+1);
sp_frame_dft=abs(fft(sp_frame)); % Compute STFT
sp_frame_array(:,j)=sp_frame_dft;
j=j+1;
end
%% Plot the STFT in 3D
[rows,cols]=size(sp_frame_array);
F=linspace(1/Fs,Fs/2000,cols);
T=1/Fs:(frame_shift*Fs/1000):(cols*(frame_shift*Fs/1000));
Z=1:frame_size+1;
subplot(2,1,2)
%mesh(sp_frame_array);
%surf(sp_frame_array,'EdgeColor','none');
plot3(T,F,sp_frame_array);
I am not sure what your question exactly is about, but I guess the problem is, with the provided code, that you do not get a plot similar to the one you'd get, say, with surf.
Furthermore, I am also not quite sure why you would want to use plot3, maybe to get the labels on the time and frequency right ? you could do that all the same with surf:
surf(T, F, sp_frame_array,'EdgeColor','none');
As a matter of fact, the reason why your plot3 does not give the same figure is because the arguments of plot3 must be three matrices of the same size (check it on help plot3). Your code should actually be broken on Matlab, which it's not, according to my test. Well, once again Matlab allowing people to mess around without warnings (go Python! :D)... Anyway, try to set the matrices more like the following:
F=linspace(1/Fs,Fs/2000, rows); % note: has to be rows, not cols here!
Fmat = F(:) * ones(1,cols); % or use repmat
T=1/Fs:(frame_shift*Fs/1000):(cols*(frame_shift*Fs/1000));
Tmat = ones(rows,1) * T(:)';
plot3(Tmat,Fmat,sp_frame_array);
While this will normally produce something more in line with what I would expect in drawing a spectrogram, I'd still make some remarks:
your F vector should go up to Fs, because of the way you filled sp_frame_dft in. More specifically, it should go from 0Hz to Fs - Fs/rows:
F = linspace(0,Fs*(1-1/rows)/1000,rows); % in kHz
you would probably like to draw the amplitudes in dBs:
plot3(Tmat,Fmat,db(sp_frame_array));
plot3 draws one line per column of the provided matrices. That means potentially lots of lines to draw! As #atul-ingle asked, are you sure this is what you want? Maybe waterfall would provide a better rendering at a lower cost?
waterfall(T,F,db(sp_frame_array));
Well, you'll get the lines for the rows, instead of the columns, so you might need to transpose if the latter is what you want.
You might also prefer to visualise only the first half of the matrix (because the frequencies higher than Fs/2 are only mirrors of the other half of the matrix).
Hope that helps!
I want to ask some questions related to the last question of mine so I don't want to post in another thread. My question contains a code, I therefore can't post it as a comment. So I have to edit my old question into a new one. Please take a look and help. Thank you.
I'm new to FFT and DSP and I want to ask you some questions about calculating FFT in Matlab. The following code is from Matlab help, I just removed the noise.
Can I choose the length of signal L different from NFFT?
I'm not sure if I used window correctly. But when I use window (hanning in the following code), I can't get the exact values of amplitudes?
When L and NFFT get different values, then the values of amplitudes were different too. How can I get the exact value of amplitude of input signal? (in the following code, I used a already known signal to check if the code work correctly. But in case, I got the signal from a sensor and I dont know ahead its amplitude, how can I check?)
I thank you very much and look forward to hearing from you :)
Fs = 1000; % Sampling frequency
T = 1/Fs; % Sample time
L = 512; % Length of signal
NFFT=1024; % number of fft points
t = (0:L-1)*T; % Time vector
x = 0.7*sin(2*pi*50*t) + sin(2*pi*120*t); input signal
X = fft(hann(L).*x', NFFT)/L;
f = Fs/2*linspace(0,1,NFFT/2+1);
plot(f,2*abs(X(1:NFFT/2+1))) % Plot single-sided amplitude spectrum.
L is the number of samples in your input signal. If L < NFFT then the difference is zero-padded.
I would recommend you do some reading on the effect of zero-padding on FFTs. Typically it is best to use L = NFFT as this will give you the best representation of your data.
An excepted answer on the use of zero-padding and FFTs is given here:
https://dsp.stackexchange.com/questions/741/why-should-i-zero-pad-a-signal-before-taking-the-fourier-transform
In your experiment you are seeing different amplitudes because you will have different amount of spectral leakage with each different L.
You need to apply a window function prior to the FFT to get consistent results with frequency components that have non-integral number of periods within your sampling window.
You might also want to consider using periodogram instead of using the FFT directly - it takes care of window functions and a lot of the other housekeeping for you.