Removing elements from plot (MATLAB) - matlab

folks. I have been working on an application with MFCC for voice recognition. At first, having recorded my voice signal (with 24000 samples), it goes through this high pass filter:
for n=2:length(x)
y(n) = x(n) - 0.95*x(n-1);
end
After that, I must resample this signal with a period of 20ms, meaning that I should eliminate the unused samples and retrieve the ones with index 160, 320, 480 and so on. Thus, I have used the following piece of code:
for n=1:length(y)
if (rem(n,160)) == 0
y(n) = y(n);
else
y(n) = [];
end
end
However, I did not have any success with this last part (MATLAB says Matrix index is out of range for deletion). What should I do?

The problem of the code is you remove the elements of y inside the loop and loop on the length of the old y.
You can do the whole of the second part using the following code:
y = y(160:160:length(y));
This code get the all index of y which are dividable by 160.
However, you should be aware of changing the size of the y after this operation.

Related

Moving maximum and LTI in MATLAB

I've implement a moving maximum filter in matlab and now I have to determine if it's LTI or not. I've already prove it's linear but I can't prove if it's time ivnariant. To prove this I have to give as an input a signal x[n] and get the output X[n]. After that I'm giving the same signal but this time it have to delay it that is x[n-a] and the output must be X[n-a] the same as the X[n] but delayed. My problem is that I don't know what input to give. Also, the moving maximum is a LTI system or not?
Thanks in advance.
Max-Filter Using For-Loop and Testing System for Linear and Time-Invariance
Filter Construction:
To filter an array/matrix/signal a for-loop can be applied. Within this for-loop, portions of the signal that overlaps the window must be stored in this case called Window_Sample. To apply the maximum filter the max() of the Window_Sample must be taken upon each iteration of the loop. Upon each iteration of the loop the window moves. Here I push all the code that calculates the maximum filtered signal into a function called Max_Filter().
Time-Invariant or Not-Time Invariant:
With proper padding, I think the maximum filter is time-invariant/shift-invariant. Concatenating zeros to the start and ends of the signal is a good way to combat this. The amount of padding I used on each end is the size of the window, the requirement would be half the window but there's no harm in having a little bit of buffer. Unfortunately, without proper padding, this may appear to break down in MATLAB since the max filter will be introduced to points early. In this case without padding the ramp the max filter will take the 5th point as the max right away. Here you can apply a scaling factor to test if the system is linear. You'll see that the system is not linear since the output is not a scaled version of the input.
clf;
%**********************************************************%
%ADJUSTABLE PARAMETERS%
%**********************************************************%
Window_Size = 3; %Window size for filter%
Delay_Size = 5; %Delay for the second test signal%
Scaling_Factor = 1; %Scaling factor for the second test signal%
n = (0:10);
%Ramp function with padding%
Signal = n; %Function for test signal%
%**********************************************************%
Signal = [zeros(1,Window_Size) Signal zeros(1,Window_Size)];
Filtered_Result_1 = Max_Filter(Signal,Window_Size);
%Ramp function with additional delay%
Delayed_Signal = Scaling_Factor.*[zeros(1,Delay_Size) Signal];
Filtered_Result_2 = Max_Filter(Delayed_Signal,Window_Size);
plot(Filtered_Result_1);
hold on
plot(Filtered_Result_2);
xlabel("Samples [n]"); ylabel("Amplitude");
title("Moving Maximum Filtering Signal");
legend("Original Signal","Delayed Signal");
xticks([0: 1: length(Filtered_Result_2)]);
xlim([0 length(Filtered_Result_2)]);
grid;
function [Filtered_Signal] = Max_Filter(Signal,Filter_Size)
%Initilizing an array to store filtered signal%
Filtered_Signal = zeros(1,length(Signal));
%Filtering array using for-loop and acccesing chunks%
for Sample_Index = 1: length(Signal)
Start_Of_Window = Sample_Index - floor(Filter_Size/2);
End_Of_Window = Sample_Index + floor(Filter_Size/2);
if Start_Of_Window < 1
Start_Of_Window = 1;
end
if End_Of_Window > length(Signal)
End_Of_Window = length(Signal);
end
Window_Sample = Signal(Start_Of_Window:End_Of_Window);
Filtered_Signal(1,Sample_Index) = max(Window_Sample);
end
end
Alternatively Using Built-In Functions:
To test the results of the created filter it is a good idea to compare this to the output results of MATLAB's built-in function movmax(). Here the results appear to be the same as the for-loop implementation.
clf;
Window_Size = 3;
n = (0:10);
%Ramp function with padding%
Signal = n;
Signal = [zeros(1,Window_Size) Signal zeros(1,Window_Size)];
Filtered_Result_1 = movmax(Signal,Window_Size);
%Ramp function with additional delay%
Delay_Size = 5;
Delayed_Signal = [zeros(1,Delay_Size) Signal];
Filtered_Result_2 = movmax(Delayed_Signal,Window_Size);
plot(Filtered_Result_1);
hold on
plot(Filtered_Result_2);
xlabel("Samples [n]"); ylabel("Amplitude");
title("Moving Maximum Filtering Signal");
legend("Original Signal","Delayed Signal");
xticks([0: 1: length(Filtered_Result_2)]);
xlim([0 length(Filtered_Result_2)]);
grid;
Ran using MATLAB R2019b

Find sum distance to horizontal line for all points in Matlab

I have a scatter plot of approximately 30,000 pts, all of which lie above a horizontal line which I've visually defined in my plot. My goal now is to sum the vertical distance of all of these points to this horizontal line.
The data was read in from a .csv file and is already saved to the workspace, but I also need to check whether a value is NaN, and ignore these.
This is where I'm at right now:
vert_deviation = 0;
idx = 1;
while idx <= numel(my_data(:,5)) && isnan(idx) == 0
vert_deviation = vert_deviation + ((my_data(idx,5) - horiz_line_y_val));
idx = idx + 1;
end
I know that a prerequisite of using the && operator is having two logical statements I believe, but I'm not sure how to rewrite this loop in this way at the moment. I also don't understant why vert_deviation returns NaN at the moment, but I assume this might have to do with the first mistake I described...
I would really appreciate some guidance here - thank you in advance!
EDIT: The 'horizontal line' is a slight oversimplification - in reality the lower limit I need to find the distance to consists of 6 different line segments
I should have specified that the lower limit to which I need to calculate the distance for all scatterplot points varies for different x values (the horizontal line snippet was meant to be a simplification but may have been misleading... apologies for that)
I first modified the data I had already read into the workspace by replacing all NaNvalues with 0. Next, I wrote a while loop which defines the number if indexes to loop through, and defined an && condition to filter out any zeroes. I then wrote a nested if loop which checks what range of x values the given index falls into, and subsequently takes the delta between the y values of a linear line lower limit for that section of the plot and the given point. I repeated this for all points.
while idx <= numel(my_data(:,3)) && not(my_data(idx,3) == 0)
...
if my_data(idx,3) < upper_x_lim && my_data(idx,5) > lower_x_lim
vert_deviation = vert_deviation + (my_data(idx,4) - (m6 * (my_data(idx,5)) + b6))
end
...
m6 and b6 in this case are the slope and y intercept calculated for one section of the plot. The if loop is repeated six times for each section of the lower limit.
I'm sure there are more elegant ways to do this, so I'm open to any feedback if there's room for improvement!
Your loop doesn't exclude NaN values becuase isnan(idx) == 0 checks to see if the index is NaN, rather than checking if the data point is NaN. Instead, check for isnan(my_data(idx,5)).
Also, you can simplify your code using for instead of while:
vert_deviation = 0;
for idx=1:size(my_data,1)
if !isnan(my_data(idx,5))
vert_deviation = vert_deviation + ((my_data(idx,5) - horiz_line_y_val));
end
end
As #Adriaan suggested, you can remove the loop altogether, but it seems that the code in the OP is an oversimplification of the problem. Looking at the additional code posted, I guess it is still possible to remove the loops, but I'm not certain it will be a significant speed improvement. Just use a loop.

Sampling and DTFT in Matlab

I need to produce a signal x=-2*cos(100*pi*n)+2*cos(140*pi*n)+cos(200*pi*n)
So I put it like this :
N=1024;
for n=1:N
x=-2*cos(100*pi*n)+2*cos(140*pi*n)+cos(200*pi*n);
end
But What I get is that the result keeps giving out 1
I tried to test each values according to each n, and I get the same results for any n
For example -2*cos(100*pi*n) with n=1 has to be -1.393310473. Instead of that, Matlab gave the result -2 for it and it always gave -2 for any n
I don't know how to fix it, so I hope someone could help me out! Thank you!
Not sure where you get the idea that -2*cos(100*pi) should be anything other than -2. Maybe you are not aware that Matlab works in radians?
Look at your expression. Each term can be factored to contain 2*pi*(an integer). And you should know that cos(2*pi*(an integer)) = 1.
So the results are exactly as expected.
What you are seeing is basically what happens when you under-sample a waveform. You may know that the Nyquist criterion says that you need to have a sampling rate that is at least two times greater than the highest frequency component present; but in your case, you are sampling one point every 50, 70, 100 complete cycles. So you are "far beyond Nyquist". And that can only be solved by sampling more closely.
For example, you could do:
t = linspace(0, 1, 1024); % sample the waveform 1024 times between 0 and 1
f1 = 50;
f2 = 70;
f3 = 100;
signal = -2*cos(2*pi*f1*t) + 2*cos(2*pi*f2*t) + cos(2*pi*f3*t);
figure; plot(t, signal)
I think you are using degrees when you are doing your calculations, so do this:
n = 1:1024
x=-2*cosd(100*pi*n)+2*cosd(140*pi*n)+cosd(200*pi*n);
cosd uses degrees instead of radians. Radians is the default for cos so matlab has a separate function when degree input is used. For me this gave:
-2*cosd(100*pi*1) = -1.3933
The first term that I got using:
x=-2*cosd(100*pi*1)+2*cosd(140*pi*1)+cosd(200*pi*1)
x = -1.0693
Also notice that I defined n as n = 1:1024; this will give all integers from 1,2,...,1024,
there is no need to use a for loop since many of Matlab's built in functions are vectorized. Meaning you can just input a vector and it will calculate the function for every element in the vector.

??? Index exceeds matrix dimensions PSD Proplem

Hey guys I am trying to find the Power Spectral Density of a .wav signal i recorded which is essentially a sine immersed in noise. The function that i have written is supposed to take records all of 1024 points in length and use it to find the Gxx of the signal by finding Gxx per record and then adding them and dividing them by the number of records better explained in the algorithm below:
a. Step through the wav file and extract the first record length (e.g. 1 to 1024 points). (Note that the record length is your new ā€œNā€, hence the frequency spacing changes in accordance with this, NOT the total length of the wav file).
b. Perform the normal PSD function on this record.
c. Store this vector.
d. Extract the next 1024 points in the wav file (e.g. 1025:2048) and perform PSD on this record.
e. Add this to the previously stored record and continue through steps c to e until you reach the end of your wav file or the total number of records you want. (Remember that total records*record length must be less than the total length of the wavfile!)
f. Divide the PSD by the number of averages (or number of records).
This is your averaged PSD
The function I created is as follows:
%Function to plot PSD
function[f1, GxxAv] = HW3_A_Fn_811003472_RCT(x,fs,NumRec)
Gxx = 0;
GxxAv = 0;
N = 1024;
df = fs/N;
f1 = 0:df:fs/2;
dt = 1/fs;
T = N*dt;
q = 0;
e = 1;
for i = 1:NumRec;
for r = (1+q):(N*e);
L = x(1+q:N*e);
M = length(L);
Xm = fft(L).*dt;
aXm = abs(Xm);
Gxx(1)=(1/T).*(aXm(1).*aXm(1));
for k = 2:(M/2);
Gxx(k) = (2/T) *(aXm(k).*(aXm(k)));
%Gxx = Gxx + Gxx1(k);
end
Gxx((M/2)+1)= (1/T)*(aXm((M/2)+1)).*(aXm((M/2)+1));
q = q+1024;
e = e+1;
%Gxx = Gxx + Gxx1((M/2)+1);
end
GxxAv = GxxAv + Gxx;
%Gxx = Gxx + Gxx1;
end
GxxAv = GxxAv/NumRec;
And the code I used to call this function is as follows:
[x,fs] = wavread('F:\Final\sem1Y3\Acoustics\sinenoise5s.wav');
[f1,GxxAv] = HW3_A_Fn_811003472_RCT(x,fs,100); %where 100 is the number of records to generated
plot(f1,GxxAv)
xlabel ('Frequency / Hz', 'fontsize', 18)
ylabel ('Amplitude Squared per Frequency / WU^2/Hz', 'fontsize', 18)
title ('Plot of the single sided PSD, using Averaging', 'fontsize', 18)
grid on
When Trying to plot this graph the following error was observed:
??? Index exceeds matrix dimensions.
Error in ==> HW3_A_Fn_811003472_RCT at 19
L = x(1+q:N*e);
Error in ==> HW3_A_3_811003472_RCT at 3
[f1,GxxAv] = HW3_A_Fn_811003472_RCT(x,fs,100); %where 100 is the number of records to generated
I am not sure how to fix it and i have tried many different methods but still i get this error. I am not too familiar with Matlab but all I really want to do for line 19 is to go like:
x(1:1024), x(1025:2048), x(2049:3072), x(3072:4096)...etc to 100 records
Any ideas??? Thanks
This is obviously homework, so I am not gonna do your work for you. But there quite some things wrong with your code. Start by fixing all of those first:
Use more appropriate function names, homework123 is not a good name to describe what the function does.
Use more appropriate variable names. More standard in this context would be nfft instead of N and n_average instead of NumRec. I don't care about the exact thing you use, but it should describe exactly what the variable does.
Your error message clearly hints that you are trying to index x in some illegal way. Start with making a loop that just prints the right indices (1..1024, 1025..2048, ...) and make sure it follows your instruction E. Only when this works as expected add the rest of the code.
you use a triple-nested for-loop. You only need a single for-loop or while-loop to solve this problem.

Not sure how the hist function in MATLAB works

I am not very sure how the hist function in MATLAB works. I seem to have few problems with it.
Bascially, in the code below, i am trying to run the rotation invariant Uniform Local Binary Pattern(LBP) code. I have no problem with the LBP code but the problem is with hist function(indicated in the code below).
The problem is that the range i should get is from 0:9 but when i apply the histogram function i get values greater than 9 such as 35, 27 and even values such as 178114.Not very sure how to correct it.
I2 = imread('test.png');
RIUniformHist=[];
m=size(I2,1);
n=size(I2,2);
for i=1:10:m
for j=1:10:n
for k=i+1:i+8
for l=j+1:j+8
J0=I2(k,l);
I3(k-1,l-1)=I2(k-1,l-1)>J0;
I3(k-1,l)=I2(k-1,l)>J0;
I3(k-1,l+1)=I2(k-1,l+1)>J0;
I3(k,l+1)=I2(k,l+1)>J0;
I3(k+1,l+1)=I2(k+1,l+1)>J0;
I3(k+1,l)=I2(k+1,l)>J0;
I3(k+1,l-1)=I2(k+1,l-1)>J0;
I3(k,l-1)=I2(k,l-1)>J0;
LBP=I3(k-1,l-1)*2^7+I3(k-1,l)*2^6+I3(k-1,l+1)*2^5+I3(k,l+1)*2^4+I3(k+1,l+1)*2^3+I3(k+1,l)*2^2+I3(k+1,l-1)*2^1+I3(k,l-1)*2^0;
bits = bitand(LBP, 2.^(7:-1:0))>0;
if nnz(diff(bits([1:end, 1]))) <= 2
RIULBP(k,l)=abs(I3(k-1,l-1)-I3(k-1,l))+ abs(I3(k-1,l)-I3(k-1,l+1))+ abs(I3(k-1,l+1)-I3(k,l+1))+ abs(I3(k,l+1)-I3(k+1,l+1))+abs(I3(k+1,l+1)-I3(k+1,l))+abs(I3(k+1,l)-I3(k+1,l-1))+abs(I3(k+1,l-1)-I3(k,l-1));
else
RIULBP(k,l)=9;
end
end
end
RIULBP=uint8(RIULBP);
RIULBPv=reshape(RIULBP,1,size(RIULBP,1)*size(RIULBP,2));
RIUHist=hist(RIULBPv,0:9); % problem
RIUniformHist = [RIUniformHist RIUHist];
end
end
The vector returned by
RIUHist=hist(data, bins)
is the count of how many elements of data are nearest the point identified by the bins vector. So if you have a value of 178114, that juts means that there were 178114 elements of data that were nearest to the matching index in bins.
You can use
[RIUHist, binsOut] = hist(data)
to let Matlab choose the bins (I believe it uses 20 bins) or
[RIUHist, binsOut] = hist(data, binCount)
To let Matlab choose the bins, but force a certain number of bins (I often use 100 or 200).