How to do windowing, FFT and display result - matlab

I'm trying to input a .wav file by
filename = 'C:\Users\kiit\Desktop\New folder\file.wav';
[y, Fs, nbits] = wavread(filename)
after that I'm calculate the length by-
L=length(y)
I've performed hamming window by-
w=window(#hamming,L);
when I perform fft by
F=fft(y,w)
It's showing warning as
Warning: FFT length must be a non-negative integer scalar.
F =
Empty matrix: 0-by-1
Any help??

Your fft command is wrong. The second argument is the FFT length, not the window.
Y = fft(X,n) returns the n-point DFT. fft(X) is equivalent to fft(X, n) where n
is the size of X in the first nonsingleton dimension. If the length of X is less
than n, X is padded with trailing zeros to length n. If the length of X is
greater than n, the sequence X is truncated. When X is a matrix, the length of
the columns are adjusted in the same manner.
To window, you apply (elementwise multiply) in the time domain (i.e. y.*w).
And to understand the output of fft:
Why does FFT produce complex numbers instead of real numbers?
Converting Real and Imaginary FFT output to Frequency and Amplitude

Related

Difference between fft points and fft in vector

Given a vector X of length L, what is the difference between fft(X) and fft(X,L)?
Does it mean we are taking the fft on L points when using fft(X) and the fft of vector L when doing fft(X,L)?
As per the documentation on fft:
Y = fft(X) computes the discrete Fourier transform (DFT) of X using a fast Fourier transform (FFT) algorithm.
If X is a vector, then fft(X) returns the Fourier transform of the vector.
Y = fft(X,n) returns the n-point DFT. If no value is specified, Y is the same size as X.
If X is a vector and the length of X is less than n, then X is padded with trailing zeros to length n.
If X is a vector and the length of X is greater than n, then X is truncated to length n.
Meaning that in case you have a vector X of length L, fft(X) and fft(X,L) are equivalent.
The interesting bit comes when you call fft(X,n) with n~=L.
If n<L your input vector X will be trucated, i.e. you will use less measurements and get a shorted Fourier sequence.
If n=L; discussed above
If n>L your vector X is zero-padded: X = [X zeros(L-n,1)] (for a row vector X). What this will do is interpolation in the frequency domain. This is most easily seen from the formulae at the bottom of the documentation:
if we increase n, we get a longer vector Y. However, since you padded zeros, and not a continuation of the signal, its Fourier transform will be an interpolation between frequencies. Normally you'd have the frequencies as given by W(n) running from your sampling frequency, f_s all the way up to f_n = Nyquist/2 in L steps, i.e. as many data points as you have: linspace(F_s,f_n,L). What you are doing when zero padding is putting more points into the same space: linspace(F_s,f_n,n), without adding information.

Matlab signal implementation

I am trying to implement the following system in MATLAB.
I am reading an audio signal and want to perform the operation below.
so far I have done the following:
%read the audio file
[y,Fs] = audioread('input_original.wav');
syms k x
yx = symsum(k, k, -inf, y);
%write the output
audiowrite('signal_divbb.wav',yx,Fs,'BitsPerSample',64)
is there a way to implement this signal properly? I am not familiar with MATLAB
The output of audioread (your y variable) has m rows times n columns, where m is the signal length and n is the number of channels (2 for stereo). You can use cumsum as follows:
yx = cumsum(y, 1);
This computes the cumulative sum along the first dimension (i.e. time). So yx(k,c) equals y(1,c)+y(2,c)+...+y(k,c), where k ranges from from 1 to m, and c is the channel index from 1 to n.

Convolution of multiple 1D signals in a 2D matrix with multiple 1D kernels in a 2D matrix

I have a randomly defined H matrix of size 600 x 10. Each element in this matrix H can be represented as H(k,t). I obtained a speech spectrogram S which is 600 x 597. I obtained it using Mel features, so it should be 40 x 611 but then I used a frame stacking concept in which I stacked 15 frames together. Therefore it gave me (40x15) x (611-15+1) which is 600 x 597.
Now I want to obtain an output matrix Y which is given by the equation based on convolution Y(k,t) = ∑ H(k,τ)S(k,t-τ). The sum goes from τ=0 to τ=Lh-1. Lh in this case would be 597.
I don't know how to obtain Y. Also, my doubt is the indexing into both H and S when computing the convolution. Specifically, for Y(1,1), we have:
Y(1,1) = H(1,0)S(1,1) + H(1,1)S(1,0) + H(1,2)S(1,-1) + H(1,3)S(1,-2) + ...
Now, there is no such thing as negative indices in MATLAB - for example, S(1,-1) S(1,-2) and so on. So, what type of convolution should I use to obtain Y? I tried using conv2 or fftfilt but I think that will not give me Y because Y must also be the size of S.
That's very easy. That's a convolution on a 2D signal only being applied to 1 dimension. If we assume that the variable k is used to access the rows and t is used to access the columns, you can consider each row of H and S as separate signals where each row of S is a 1D signal and each row of H is a convolution kernel.
There are two ways you can approach this problem.
Time domain
If you want to stick with time domain, the easiest thing would be to loop over each row of the output, find the convolution of each pair of rows of S and H and store the output in the corresponding output row. From what I can tell, there is no utility that can convolve in one dimension only given an N-D signal.... unless you go into frequency domain stuff, but let's leave that for later.
Something like:
Y = zeros(size(S));
for idx = 1 : size(Y,1)
Y(idx,:) = conv(S(idx,:), H(idx,:), 'same');
end
For each row of the output, we perform a row-wise convolution with a row of S and a row of H. I use the 'same' flag because the output should be the same size as a row of S... which is the bigger row.
Frequency domain
You can also perform the same computation in frequency domain. If you know anything about the properties of convolution and the Fourier Transform, you know that convolution in time domain is multiplication in the frequency domain. You take the Fourier Transform of both signals, multiply them element-wise, then take the Inverse Fourier Transform back.
However, you need to keep the following intricacies in mind:
Performing a full convolution means that the final length of the output signal is length(A)+length(B)-1, assuming A and B are 1D signals. Therefore, you need to make sure that both A and B are zero-padded so that they both match the same size. The reason why you make sure that the signals are the same size is to allow for the multiplication operation to work.
Once you multiply the signals in the frequency domain then take the inverse, you will see that each row of Y is the full length of the convolution. To ensure that you get an output that is the same size as the input, you need to trim off some points at the beginning and at the end. Specifically, since each kernel / column length of H is 10, you would have to remove the first 5 and last 5 points of each signal in the output to match what you get in the for loop code.
Usually after the inverse Fourier Transform, there are some residual complex coefficients due to the nature of the FFT algorithm. It's good practice to use real to remove the complex valued parts of the results.
Putting all of this theory together, this is what the code would look like:
%// Define zero-padded H and S matrices
%// Rows are the same, but columns must be padded to match point #1
H2 = zeros(size(H,1), size(H,2)+size(S,2)-1);
S2 = zeros(size(S,1), size(H,2)+size(S,2)-1);
%// Place H and S at the beginning and leave the rest of the columns zero
H2(:,1:size(H,2)) = H;
S2(:,1:size(S,2)) = S;
%// Perform Fourier Transform on each row separately of padded matrices
Hfft = fft(H2, [], 2);
Sfft = fft(S2, [], 2);
%// Perform convolution
Yfft = Hfft .* Sfft;
%// Take inverse Fourier Transform and convert to real
Y2 = real(ifft(Yfft, [], 2));
%// Trim off unnecessary values
Y2 = Y2(:,size(H,2)/2 + 1 : end - size(H,2)/2 + 1);
Y2 should be the convolved result and should match Y in the previous for loop code.
Comparison between them both
If you actually want to compare them, we can. What we'll need to do first is define H and S. To reconstruct what I did, I generated random values with a known seed:
rng(123);
H = rand(600,10);
S = rand(600,597);
Once we run the above code for both the time domain version and frequency domain version, let's see how they match up in the command prompt. Let's show the first 5 rows and 5 columns:
>> format long g;
>> Y(1:5,1:5)
ans =
1.63740867892464 1.94924208172753 2.38365646354643 2.05455605619097 2.21772526557861
2.04478411247085 2.15915645246324 2.13672842742653 2.07661341840867 2.61567534623066
0.987777477630861 1.3969752201781 2.46239452105228 3.07699790208937 3.04588738611503
1.36555260994797 1.48506871890027 1.69896157726456 1.82433906982894 1.62526864072424
1.52085236885395 2.53506897420001 2.36780282057747 2.22335617436888 3.04025523335182
>> Y2(1:5,1:5)
ans =
1.63740867892464 1.94924208172753 2.38365646354643 2.05455605619097 2.21772526557861
2.04478411247085 2.15915645246324 2.13672842742653 2.07661341840867 2.61567534623066
0.987777477630861 1.3969752201781 2.46239452105228 3.07699790208937 3.04588738611503
1.36555260994797 1.48506871890027 1.69896157726456 1.82433906982894 1.62526864072424
1.52085236885395 2.53506897420001 2.36780282057747 2.22335617436888 3.04025523335182
Looks good to me! As another measure, let's figure out what the largest difference is between one value in Y and a corresponding value in Y2:
>> max(abs(Y(:) - Y2(:)))
ans =
5.32907051820075e-15
That's saying that the max error seen between both outputs is in the order of 10-15. I'd say that's pretty good.

Square wave function for Matlab

I'm new to programming in Matlab. I'm trying to figure out how to calculate the following function:
I know my code is off, I just wanted to start with some form of the function. I have attempted to write out the sum of the function in the program below.
function [g] = square_wave(n)
g = symsum(((sin((2k-1)*t))/(2k-1)), 1,n);
end
Any help would be much appreciated.
Update:
My code as of now:
function [yout] = square_wave(n)
syms n;
f = n^4;
df = diff(f);
syms t k;
f = 1; %//Define frequency here
funcSum = (sin(2*pi*(2*k - 1)*f*t) / (2*k - 1));
funcOut = symsum(func, v, start, finish);
xsquare = (4/pi) * symsum(funcSum, k, 1, Inf);
tVector = 0 : 0.01 : 4*pi; %// Choose a step size of 0.01
yout = subs(xsquare, t, tVector);
end
Note: This answer was partly inspired by a previous post I wrote here: How to have square wave in Matlab symbolic equation - However, it isn't quite the same, which is why I'm providing an answer here.
Alright, so it looks like you got the first bit of the question right. However, when you're multiplying things together, you need to use the * operator... and so 2k - 1 should be 2*k - 1. Ignoring this, you are symsuming correctly given that square wave equation. The input into this function is only one parameter only - n. What you see in the above equation is a Fourier Series representation of a square wave. A bastardized version of this theory is that you can represent a periodic function as an infinite summation of sinusoidal functions with each function weighted by a certain amount. What you see in the equation is in fact the Fourier Series of a square wave.
n controls the total number of sinusoids to add into the equation. The more sinusoids you have, the more the function is going to look like a square wave. In the question, they want you to play around with the value of n. If n becomes very large, it should start approaching what looks like to be a square wave.
The symsum will represent this Fourier Series as a function with respect to t. What you need to do now is you need to substitute values of t into this expression to get the output amplitude for each value t. They define that for you already where it's a vector from 0 to 4*pi with 1001 points in between.
Define this vector, then you'll need to use subs to substitute the time values into the symsum expression and when you're done, cast them back to double so that you actually get a numeric vector.
As such, your function should simply be this:
function [g] = square_wave(n)
syms t k; %// Define t and k
f = sin((2*k-1)*t)/(2*k-1); %// Define function
F = symsum(f, k, 1, n); %// Define Fourier Series
tVector = linspace(0, 4*pi, 1001); %// Define time points
g = double(subs(F, t, tVector)); %// Get numeric output
end
The first line defines t and k to be symbolic because t and k are symbolic in the expression. Next, I'll define f to be the term inside the summation with respect to t and k. The line after that defines the actual sum itself. We use f and sum with respect to k as that is what the summation calls for and we sum from 1 up to n. Last but not least, we define a time vector from 0 to 4*pi with 1001 points in between and we use subs to substitute the value of t in the Fourier Series with all values in this vector. The result should be a 1001 vector which I then cast to double to get a numerical result and we get your desired output.
To show you that this works, we can try this with n = 20. Do this in the command prompt now:
>> g = square_wave(20);
>> t = linspace(0, 4*pi, 1001);
>> plot(t, g);
We get:
Therefore, if you make n go higher... so 200 as they suggest, you'll see that the wave will eventually look like what you expect from a square wave.
If you don't have the Symbolic Math Toolbox, which symsum, syms and subs relies on, we can do it completely numerically. What you'll have to do is define a meshgrid of points for pairs of t and n, substitute each pair into the sequence equation for the Fourier Series and sum up all of the results.
As such, you'd do something like this:
function [g] = square_wave(n)
tVector = linspace(0, 4*pi, 1001); %// Define time points
[t,k] = meshgrid(tVector, 1:n); %// Define meshgrid
f = sin((2*k-1).*t)./(2*k-1); %// Define Fourier Series
g = sum(f, 1); %// Sum up for each time point
end
The first line of code defines our time points from 0 to 4*pi. The next line of code defines a meshgrid of points. How this works is that for t, each column defines a unique time point, so the first column is 200 zeroes, up to the last column which is a column of 200 4*pi values. Similarly for k, each row denotes a unique n value so the first row is 1001 1s, followed by 1001 2s, up to 1001 1s. The implications with this is now each column of t and k denotes the right (t,n) pairs to compute the output of the Fourier series for each time that is unique to that column.
As such, you'd simply use the sequence equation and do element-wise multiplication and division, then sum along each individual column to finally get the square wave output. With the above code, you will get the same result as above, and it'll be much faster than symsum because we're doing it numerically now and not doing it symbolically which has a lot more computational overhead.
Here's what we get when n = 200:
This code with n=200 ran in milliseconds whereas the symsum equivalent took almost 2 minutes on my machine - Mac OS X 10.10.3 Yosemite, 16 GB RAM, Intel Core i7 2.3 GHz.

Linear convolution and cross-correlation of two vectors in Matlab using fft and same length output

I'm implementing an algorithm where I need to compute the linear convolution and cross-correlation between two 1D vectors a and b using the FFT. If the length of a is m and the length of b is n, then the total length of the resulting convolution will be m + n - 1.
However, the algorithm requires the output of the convolution to be the same length as the inputs. Since m = n, the input vectors are the same length.
In Matlab, given that both vectors have been zero-padded to length m + n - 1, the convolution is computed as:
ifft(fft(a).*fft(b))
Alternately, the cross-correlation between the two vectors is computed as:
fftshift(ifft(fft(a).*conj(fft(b))))
The output is of length m + n - 1. I need to zero-pad the vectors to ensure that circular convolution does not occur when using the FFT.
However, I would like the output length to be the same as the length of the inputs. An associated question (also on stackoverflow) shows how the correlation of two images can be trimmed.
How do I trim the 1D output vector so that it is the same length as the input vectors?
In MATLAB, conv(a, b, 'same') returns the central part of the convolution that is the same size as a. For cross correlation, you can use xcorr, which will give you the cross correlation result. I guess you need to crop the result by yourself to get the same size as input.
there are formulas:
c = a conv b;
where, a, b and c are in time domain; After trans to frequency domain, the formula change to
C = A * B;
where, A, B and C are fft result of a, b, and c respectively, and all of them are in frequency domain; so c = ifft(C);