subtract a value from an array efficiently in matlab - arrays

I have an 2-dim array representing the arrival times of photons in two channels, the array contains a line with the information about the arrival time and the other with the information about the timestamp
data = stream.getData();
timestamps = data.getTimestamps();
channels = data.getChannels();
timetags = [timestamps; channels];
t= [timetags];
I need a start-multiple stop measurments, so when there is a click in the channel 1 I need to subtract the timestamp for that click in every timestamp of channel 2, until the next click in channel 1 and so on. I used a for cicle for this:
for i=1:length(t)
if t(2,i)==1
t(1,i:end)=t(1,i:end)-t(1,i)
end
end
but it is quite slow. Is there a faster way to do that?

You can use t(2,:)==0 to create an array which is true on your condition, then t(1,:).*(t(2,:)==0) gives either 0 or the current timestamp when this is true.
Therefore, if t(2,:) is non-decreasing you should be able to do something like
t(1,:) = t(1,:) - cummax( t(1,:) .* (t(2,:)==0) );

Related

Number of events in one array within w minutes after any event in a second array

I have two sorted arrays of unix time stamps (so integers representing times at which some events happen). Lets call the arrays ts1 and ts2. I want to find the number of events in ts1 that lie after w-minutes of any event in ts2. Let's say the method signature is (take the first and second arrays and window size then return number of events in ts1 that are within w minutes after any event in ts2):
critical_events(ts1,ts2,w)->int
Here are some test cases:
## Test cases.
ev = critical_events([.5,1.5,2.5],[1,2,3],.5)
print(ev==0)
ev = critical_events([1.4,1.4,2.7],[1,2,3],.5)
print(ev==2)
ev = critical_events([1.4,2.4,3.4],[1,2,3],.5)
print(ev==3)
I expect the length of the first array, n to be much larger than the length of the second one, m. Looking for efficient algorithms in terms of time and space and if possible, their average and worst case complexities in terms of n and m, time and space.
My attempt: instead of explaining my attempts, I'll just link to the code which should be self-explanatory (or at least better than what I can do in words): https://gist.github.com/ryu577/fdc22af4ed17d122a6aa25684597745b
You are showing them as sorted, so my assumption is they are (need to be for this to work).
Because your first array is much larger than your second, you need to take your second in a for loop.
I am using example test case 2:ev = critical_events([1.4,1.4,2.7],[1,2,3],.5)
Next you can use a binary search on the first element of ts2 + interval (1 + 0.5) = 1.5.
Your startIndex is 0 and endIndex is 2. So in first compare you take all elements.
Doing a binary search will result in index 2 in ts1. Note: Because you have equal element in your array, you need to go right until you get higher number. What you can tell now is that 2.7 (and all elements after if there where any) are the element what lies after 1.5. Count is ts2.lenght - foundindex.
Now you can set your start index to 2. because you know, all on the left of this index is smaller and will not lie after 1.5 sec.
You take element2 and do a binary search, you will find index 2 ( 2.5 < 2.7), again:
Count = Count + ts2.lenght - foundindex.
To my knowledge, this is the fastest method. I believe the speed is Log(n).m.

How to select values in an array until a threshold value?

I will explain my problem. I have a 1x1701 sampled array "resampled_WF", once I found the max value of this array ("peak_WF"), I set a threshold 0.7*peak_WF, and I would like to select the farthest value in the array that gets nearer to this threshold.
Example:
power_vs_time_threshold
As you can see, I was able to select ony the first value that resembles... but I would like to get the last one (around t=2 sec).
I tried to flip the array with "flip" function:
WF_threshold_input = 0.7*peak_WF;
flip_resampled_WF = flip(resampled_WF);
diff_peak_threshold = peak_WF - WF_threshold_input; %power loss at 70% power reduction
diff_peak_WF = peak_WF - flip_resampled_WF;
min_diff_threshold = min(abs(diff_peak_WF-diff_peak_threshold));
Doing that, MATLAB computes minimum difference on the whole array, I would like to stop at the first value, not considering further values.
I tried to select values with values <= WF_threshold_input, but again it selects over the whole dataset.
How can I select the value properly?
Thanks!!
Using operations on the matrix will call the operation on every element in the matrix. What you want to do is use a loop so that you can control exactly what elements are examined and then break out of the loop.
index = length(resampled_WF);
your_threshold = ...
while resampled_WF(index) < your_threshold
index = index - 1;
end
The while loop will continue iteration until it reaches a value that is outside of your defined threshold.
After execution, the value of index will be the index of the furthest value in the array which is outside of your threshold. You can access the furthest value outside the threshold by looking at resampled_wf(index) after execution of the code.
We don't have to worry about the values of index leaving the bounds of the array, ie <1, since the condition resampled_wf < your_threshold is guaranteed to be met by the maximal value that you originally generated the threshold with.

Find specific date in a date array

I am working with a datetime array s constructed as follows:
ds = datetime(2010,01,01,'TimeZone','Europe/Berlin');
de = datetime(2030,01,01,'TimeZone','Europe/Berlin');
s = ds:hours(1):de;
I am using ismember function to find the first occurrence of a specific date in that array.
ind = ismember(s,specificDate);
startPlace = find(ind,1);
The two lines from above are called many times in my application and consume quite some time. It is clear to me that Matlab compares ALL dates from s with specificDate, even though I need only the first occurrence of specificDate in s. So to speed up the application it would be good if Matlab would stop comparing specificDate to s once the first match is found.
One solution would be to use a while loop, but with the while loop the application becomes even slower (I tried it).
Any idea how to work around this problem?
I'm not sure what your specific use-case is here, but with the step size between elements of s being one hour, your index is simply going to be the difference in hours between your specific date and the start date, plus one. No need to create or search through s in the first place:
startPlace = hours(specificDate-ds)+1;
And an example to test each solution:
specificDate = datetime(2017, 1, 1, 'TimeZone', 'Europe/Berlin'); % Sample date
ind = ismember(s, specificDate); % Compare to the whole vector
startPlace = find(ind, 1); % Find the index
isequal(startPlace, hours(specificDate-ds)+1) % Check equality of solutions
ans =
logical
1 % Same!
What you can do to save yourself some time is to convert the datetime to a datenum in such a case you will be comparing numbers rather than strings, which significantly accelerates your processing time, like this:
s_new = datenum(s);
ind = ismember(s_new,datenum(specificDate));
startPlace = find(ind,1);

MATLAB cell array indexing and looping

I'm trying to create a script that reads data from a text file, and plots the data onto a scatter plot.
For example, say the file name is prices.txt and contains:
Pens 2 4
Pencils 1.5 3
Rulers 3 3.5
Sharpeners 1 3
Highlighters 3 4
Where columns 2 and 3 are prices of the items for two different stores.
What my script should do is read the prices, calculates (using another function) future prices of the stores and plots these prices onto a scatter plot where x is one store and y is another. This is a silly example I know but it fits the description.
Don't worry to much about the other function that does the calculation, just assume it does what its supposed to.
Basically, I've come up with the following:
pricesfile = fopen('Prices.txt');
prices = textscan(pricesfile, '%s %d d');
fclose(pricesfile);
count = 1;
while count <= length(prices{1})
for item = constants{1}
name = constants{1}{count};
store_A = prices{2}{count};
store_B = prices{3}{count};
(...other function goes here...)
end
end
After doing this I'm completely stuck. My thought process behind this was to go through each item name, and create a vector that's assigned to this name with its two corresponding prices as items in the vector eg:
pens = [2 4]
pencils = [1.5 3]
etc. Then, I would somehow plot those items in the vector on a scatter plot and use the name of the vector as a label.
I'm not too sure how to carry out the rest of my code or even if what I've written will get me to the solution.
Please help and thanks in advance.
pricesfile = fopen('Prices.txt');
data = textscan(pricesfile, '%s %d d');
fclose(pricesfile);
You were on the right track but after this (through a bit of hackery) you don't actually need a loop:
plot(repmat(data{2},1,2)', repmat(data{3},1,2)', '.')
legend(data{1})
What you DO NOT want to do is create variables named after strings. Rather store them in an array with an array of the names (which is basically what your textscan code gives you). Matlab is very good at handling matrices/arrays.
You could also split your price array up for example:
names = prices{1};
prices = [data{2:3}];
now you can perform calculations on prices quite easily like
prices_cents = prices*100;
plot(prices_cents(:,[1,1]), prices_cents(:,[2,2]))
legend(names)
Note that the [1,1] etc above is just using indexing as a short hand to achieve what repmat does...

Create a X times 2 table/array, pair the rows and sort one of the columns (Lua)?

I am a total Lua-newbie, so I need your help:
I'm planning to read values from a receiver sensor which returns
The length between the receiver and the transmitter
The index id (1,2,3...etc) that corresponds of the transmitter
The Lua table pair sorting is really confusing, and I don't get it.
This is my not-working code:
distance = {}
for i=1,#robot.range_and_bearing do
v= robot.range_and_bearing[i].range
table.insert(distance,v, i)
end
table.sort(distance)
table.print(distance)
where,
#robot.range_and_bearing = the number of connections sensed
and
robot.range_and_bearing[i].range returns the distance to that transmitter
The array doesn't sort neither of the columns.
Any suggestions on how to sort the range value "v" and still get the right corresponding robot id "i"?
I appreciate all answers, but simple ones are preferred :p
You seem to be saying that a sensor transmitter has an identity and that the sensor reading should be tagged with that identity.
I would do that as early as possible. If you can't do it when robot.range_and_bearing is created, you can do it later like this (assuming the index is an appropriate identifier):
for i=1,#robot.range_and_bearing do
robot.range_and_bearing[i].transmitter = i
end
Of course, you could combine that with the following step, which just copies the table (presumably you didn't want to modify the order of the original table):
distance = {}
for i=1,#robot.range_and_bearing do
table.insert(distance,robot.range_and_bearing[i])
end
Now, you can sort by range:
table.sort(distance, function(a,b) a.range < b.range end)
And, print:
for i=1,#distance do
print(distance[i].transmitter, distance[i].range)
end

Resources