Matlab: variable index size in loop - matlab

I've been trying to figure this out myself and also searched here. The fact that I am not quite sure what the problem is isn't helping with this. I have previously found good help in answers to other people here, so I hope that you can help me.
I have a dataset (2000x1100) that consists of 1's and 0's, where each row represents one datapoint over time (columns).
I am trying to find sequences of 0's for each row and exclude those that are below a specific length. I have already found helpful answers here that allowed me to do this (thanks!).
'test' is a reduced test dataset that I am using to test the code.
for j = 1:size(test,1)
testThresh(j,:) = diff([1 test(j,:)]);
startIndex = find(testThresh(j,:) < 0);
if isempty(startIndex)
continue
j = j+1;
end
endIndex = find(testThresh(j,:) > 0)-1;
if numel(endIndex) == 1
for m = 1:size(startIndex,2)
duration = (endIndex(m)-startIndex(m))+1;
threshold = (duration < 10);
startIndexC = startIndex(threshold);
endIndexC = endIndex(threshold);
end
else
duration = (endIndex(j,:)-startIndex(j,:))+1;
threshold = (duration < 10);
startIndexC = startIndex(threshold);
endIndexC = endIndex(threshold);
end
..
I would later replace the below-threshold sequences of 0's with 1's.
The code works fine until I happen to have a row that doesn't contain any 0's. It would skip to the next row as supposed to, but there it will result in an error:
Attempted to access endIndex(2,:); index out of bounds because size(endIndex)=[1,4].
I don't really understand why this causes an error. There isn't any problem with this specific row if it isn't preceded by a no-zero-containing row.
I assume that encountering a row w/o 0 does something to the allowed size of the array. I don't really know how to get around it. I can't pre-allocate because I don't know the size the variable will reach in each iteration (I tried anyway and it didn't help).
I also tried to say that numel(endIndex) >= 1 otherwise skip to next step. That also didn't work. I probably made a really silly mistake, but I am still quite new to Matlab and just can't figure it out.
I hope anyone can help with this!
Any help is greatly appreciated!
Edit:
duration = (endIndex(1,:)-startIndex(1,:))+1;
This is very stupid. I am ashamed. Thanks for pointing this out.
Just for reasons of completion since I wasn't specific enough of what I want to accomplish (sorry about that): I want to determine the start, end and length of stretches of 0's within a lot of 1's. If the length of any of these stretches is below the threshold of 10 (i.e. too short for my purposes to be considered) I want to disregard it.

Related

peak finder for multidimensional array

I'm trying the following and is not working. Could someone help me on this?
A=rand(1,4,5);
peak_num=zeros(5,4);
for w=1:5
peak_num(w,:)=peakfinder(A(1,1:4,w))
end
peak_num;
in this case the vector of peaks found for each w has a different size.
Thanks
I haven't really taken a look at the internals of the peakfinder function but if you make sure that it does not output a vector with more than 4 elements this is a workaround:
A=rand(1,4,5);
peak_num=zeros(5,4);
for w=1:5
temp = peakfinder(A(1,1:4,w));
peak_num(w, 1:length(temp) ) = temp
end
peak_num;
It sets the first elements to the return values and keeps the others being zero.

Matlab get amount of clipping

Hi I am trying to measure the amount of clipped Samples in audio files with matlab. That means i want to get the number of all Samples that are at the Fullscale Value (at min and max). But it should just count them when there are at least two following samples at this Value.
My code so far:
for i = 1 :20
fileName = ['Elektro',num2str(i) '.wav'];
unclipped = audioread(fileName);
summeMax = sum(1 ==unclipped);
summeMin = sum(-1==unclipped);
summe = summeMin +summeMax;
str=sprintf('%d ',summe);
disp(str);
end
As you see its counting every sample and I would need a loop and if statements to detect if there are more than one sample at the fullscale Value.
I tried this it with a loop from j = 1 : length(unclipped) but it takes to long with this Method.
Anyone have suggestions how i could do this?
As #Daniel pointed out in his answer to a previous question of yours, you can find all samples at which the maximum is reached by
maxReached = max(unclipped(:))==unclipped;
To remove all places where the maximum is reached for only one sample, you can use a morphological opening with the structuring element [1,1]:
clippedSamples = imopen(maxReached, [1 1]);
The number of clipped samples is now
sum(clippedSamples);
Of course you'll have to do the same with those samples where the minimum is reached.

Assigning arrays to a matrix in a function, syntax problems

I'm having trouble with the syntax in Matlab.
I'm trying to split an audio signal up into different segments (frames).
I would like to return the y-axis values to a matrix (each segment having its own column), and the corresponding time values with each segment having its own row.
I can't even get it to return just one single column and row pair (ie one frame). I just get returned two empty matrices. Here's my code.
function [mFrames, vTimeFrame] = Framing(vSignal,samplingRate,frameLPerc,frameshPerc)
totalTime=size(vSignal,1)/samplingRate
frameLength = totalTime*frameLPerc;
frameShift = totalTime*frameshPerc;
frameNumber =0;
check=frameLPerc;
while check<1
check = check+frameshPerc;
frameNumber=frameNumber+1;
end
start = 1;
% problem part
mFrames = vSignal(round((start:1/samplingRate:frameLength)*samplingRate));
vTimeFrame = round((start:1/samplingRate:frameLength)*samplingRate);
end
In the end I would like to be able to segment my entire signal into mFrames(i) and vTimeFrame(i) with a for-loop, but never mind that I cannot even get my function to return the first one (like I said empty matrix).
I know my segment code should be correct because I've got another script working with the same vSignal (it's a column vector by the way) that works just fine (y==vSignal):
voiced = y(round((1.245:1/Fs:1.608)*Fs));
plot(1.245:1/Fs:1.608,voiced)
I titled this with syntax problems because I'm very new to matlab and am used to Java. It feels very weird not initializing anything, and so I'm unsure whether my code is actually making any sense.
When testing I enter [m1,m2]=Framing(y,16000,0.1,0.05).
I got it.
start was not in the right domain. This is correct:
round((start/samplingRate:1/samplingRate:frameLength)*samplingRate)
When I plot(m2,m1) I now get the correct answer.
I do still have another question though, how can I assign these segments to my matrices?
for i=1:frameNumber
mFrames(:,i) = vSignal(round((start/samplingRate:1/samplingRate:frameLength)*samplingRate));
vTimeFrame(i) = round((start/samplingRate:1/samplingRate:frameLength)*samplingRate);
start=start+frameShift;
frameLength=frameLength+frameShift;
end
I get this error
In an assignment A(I) = B, the number of elements in B and I must be the same.
Like I said I'm trying to get the y-axis numbers in columns next to each other and the x-axis in rows.

While exits before it should

It's a simple problem I am having, but a little hard to explain.
I have a while loop that looks like this;
(Not the actual code)
x = [1;2;3;4]
while size(x(:,1),1) > 1
%Do stuff
%When a condition is met move it to the bottom to be processed last
%In this case "2"
x = [x; x(2,:)];
%Remove the original line for two
x(2,:) = [];
end
However it exits on the third iteration instead of the fourth missing the last row.
My theory is, the original size of x is 4 going into the while loop. By adding a row and deleting another matlab thinks that the variable is now size == 3 and exits when 3 variables are removed.
It doesn't make much sense to me. The code is confidential so I can't share the actual code, but if necessary I could attempt to replicate the error with code I can share.
I'm hoping someone has a magical answer.
Thanks
I got it, sorry to bug everyone. It needs to be a >= 1 then it will also process the last item in the list. The example code, while it was an infinite loop, would never process the last item in the list.

How to speed up array concatenation?

Instead of concatening results to this, Is there other way to do the following, I mean the loop will persist but vector=[vector,sum(othervector)]; can be gotten in any other way?
vector=[];
while a - b ~= 0
othervector = sum(something') %returns a vector like [ 1 ; 3 ]
vector=[vector,sum(othervector)];
...
end
vector=vector./100
Well, this really depends on what you are trying to do. Starting from this code, you might need to think about the actions you are doing and if you can change that behavior. Since the snippet of code you present shows little dependencies (i.e. how are a, b, something and vector related), I think we can only present vague solutions.
I suspect you want to get rid of the code to circumvent the effect of constantly moving the array around by concatenating your new results into it.
First of all, just make sure that the slowest portion of your application is caused by this. Take a look at the Matlab profiler. If that portion of your code is not a major time hog, don't bother spending a lot of time on improving it (and just say to mlint to ignore that line of code).
If you can analyse your code enough to ensure that you have a constant number of iterations, you can preallocate your variables and prevent any performance penalty (i.e. write a for loop in the worst case, or better yet really vectorized code). Or if you can `factor out' some variables, this might help also (move any loop invariants outside of the loop). So that might look something like this:
vector = zeros(1,100);
while a - b ~= 0
othervector = sum(something);
vector(iIteration) = sum(othervector);
iIteration = iIteration + 1;
end
If the nature of your code doesn't allow this (e.g. you are iterating to attain convergence; in that case, beware of checking equality of doubles: always include a tolerance), there are some tricks you can perform to improve performance, but most of them are just rules of thumb or trying to make the best of a bad situation. In this last case, you might add some maintenance code to get slightly better performance (but what you gain in time consumption, you lose in memory usage).
Let's say, you expect the code to run 100*n iterations most of the time, you might try to do something like this:
iIteration = 0;
expectedIterations = 100;
vector = [];
while a - b ~= 0
if mod(iIteration,expectedIterations) == 0
vector = [vector zeros(1,expectedIterations)];
end
iIteration = iIteration + 1;
vector(iIteration) = sum(sum(something));
...
end
vector = vector(1:iIteration); % throw away uninitialized
vector = vector/100;
It might not look pretty, but instead of resizing the array every iteration, the array only gets resized every 100th iteration. I haven't run this piece of code, but I've used very similar code in a former project.
If you want to optimize for speed, you should preallocate the vector and have a counter for the index as #Egon answered already.
If you just want to have a different way of writing vector=[vector,sum(othervector)];, you could use vector(end + 1) = sum(othervector); instead.