I am creating a simulation to model a robot moving through river currents. The more code I add, the slower the simulation gets. Sometimes, it runs so slow that the buttons don't work. Does anyone know how I might speed it up?
It is possible that it might be my computer. A few times, the simulation ran flawlessly.
Code:
function CleanRiverSolutionsSimulation
%Initialize Figure
f = figure('Visible','off','Position',[250,250,1000,500],'Name','Clean River Solutions Simulation');
%Initialize variables (when changing these, don't forget to change them in
%the stop button function)
robot_position = [0 0 0];
last_robot_position = [-1 0 0];
time_data = [0];
depth_data = robot_position(3);
simulation_mode = 'paused'; %options: 'paused' 'running' 'stopped'
river_depth = 10;
water_flow_rate = 1;
%Initializes Plots
main_plot = axes('Units','pixels','Position',[50,225,500,250]);
data_plot1 = axes('Units','pixels','Position',[625,350,200,100]);
%Initializes Sliders
water_flow_slider = uicontrol('style','slider','position',[50 175 200 20],'min',0,'max',2.5,'callback',#callback_waterflow,'value',water_flow_rate);
water_flow_text = uicontrol('Style','text','String','River Water Flow','Position',[30 140 200 30]);
water_flow_text.String = sprintf('River Water Flow: %f m/s',get(water_flow_slider,'value'));
river_depth_slider = uicontrol('style','slider','position',[50 125 200 20],'min',0,'max',10,'callback',#callback_riverdepth,'value',river_depth);
river_depth_text = uicontrol('Style','text','String','River Depth','Position',[30 90 200 30]);
river_depth_text.String = sprintf('River Depth: %f m',get(river_depth_slider,'value'));
%Initializes Push Buttons
run_button = uicontrol('Style','pushbutton','String','Run','Position',[300 175 50 20],'callback',#callback_runbutton);
pause_button = uicontrol('Style','pushbutton','String','Pause','Position',[360 175 50 20],'callback',#callback_pausebutton);
stop_button = uicontrol('Style','pushbutton','String','Stop','Position',[420 175 50 20],'callback',#callback_stopbutton);
status_text = uicontrol('Style','text','String','Status','Position',[300 140 150 30]);
status_text.String = sprintf('Status: %s','Paused');
%After setup, makes figure visible
f.Visible = 'on';
%Environment Settings
riv_length = 20;
riv_width = 20;
%River flow settings
flow_dots = 4;
%Initialize Main Plot (when changing these, don't forget to change them in
%the stop button function)
plot3(main_plot,robot_position(1),robot_position(2),robot_position(3),'Marker', 'o','Color','r')
main_plot.XLim = [-riv_length/2 riv_length/2];
main_plot.YLim = [-riv_width/2 riv_width/2];
main_plot.ZLim = [-1*river_depth 1];
main_plot.XGrid = 'on';
main_plot.YGrid = 'on';
main_plot.ZGrid = 'on';
%Initialize time sequence (when changing these, don't forget to change them in
%the stop button function)
time = clock;
pausedStartTime = time(6)+60*time(5)+3600*time(4);
startTime = pausedStartTime;
pausedTime = 0;
totalPausedTime = 0;
%MAIN SIMULATION LOOP
while ishandle(f)
switch simulation_mode
case 'running'
%TODO-add forces and have the positions depend on the forces
%creates a time t to use in simulated equations
time = clock;
t = ((time(6)+60*time(5)+3600*time(4))-startTime-totalPausedTime);
%X
last_robot_position(1) = robot_position(1);
robot_position(1) = 0;
%Y
last_robot_position(2) = robot_position(2);
robot_position(2) = 0;
%Z
last_robot_position(3) = robot_position(3);
robot_position(3) = -4+2*sin(2*t); %just did a sin wave to show movement
%UPDATE MAIN PLOT
%update robot position
plot3(main_plot,robot_position(1),robot_position(2),robot_position(3),'Marker','o','Color','r')
%update robot velocity vector?
forward_vector = [robot_position(1)-last_robot_position(1),...
robot_position(2)-last_robot_position(2),...
robot_position(3)-last_robot_position(3)];
forward_unit_vector = forward_vector./norm(forward_vector);
hold(main_plot,'on')
plot3(main_plot,[robot_position(1) (robot_position(1)+forward_unit_vector(1))],...
[robot_position(2) (robot_position(2)+forward_unit_vector(2))],...
[robot_position(3) (robot_position(3)+forward_unit_vector(3))]);
%update river flow dots
for dot = 1:flow_dots
plot3(main_plot,-riv_length/2+(dot-1)*(riv_length/flow_dots)+mod((t/water_flow_rate),(riv_length/flow_dots)),10,0,'Marker','o','Color','b')
end
%update plot settings
main_plot.XLim = [-riv_length/2 riv_length/2];
main_plot.YLim = [-riv_width/2 riv_width/2];
main_plot.ZLim = [-1*river_depth 1];
main_plot.XGrid = 'on';
main_plot.YGrid = 'on';
main_plot.ZGrid = 'on';
hold(main_plot,'off')
%Update Data Plot 1 (depth)
time = clock;
time_data = [time_data ((time(6)+60*time(5)+3600*time(4))-startTime-totalPausedTime)];
depth_data = [depth_data robot_position(3)];
plot(data_plot1,time_data,depth_data)
title('Robot Depth')
data_plot1.XLim = [max(0,(((time(6)+60*time(5)+3600*time(4))-startTime-totalPausedTime)-15)),...
max(0,(((time(6)+60*time(5)+3600*time(4))-startTime-totalPausedTime)-15)+20)];
data_plot1.YLim = [-1*river_depth 1];
pause(0.1); %anything lower and the simulation won't pause
case 'paused'
pause(0.01); %need this or the sim won't start
case 'stopped'
%so far, this line is never run
end
end
%executes callback for water flow slider
function callback_waterflow(source,eventdata)
water_flow_text.String = sprintf('River Water Flow: %f m/s',get(water_flow_slider,'value'));
water_flow_rate = get(water_flow_slider,'value');
end
%executes callback for river depth slider
function callback_riverdepth(source,eventdata)
river_depth_text.String = sprintf('River Depth: %f m',get(river_depth_slider,'value'));
river_depth = get(river_depth_slider,'value');
end
%executes callback for run button
function callback_runbutton(source,eventdata)
switch simulation_mode
case 'stopped'
%Reinitialize time sequence
time = clock;
startTime = time(6)+60*time(5)+3600*time(4);
pausedTime = 0;
totalpausedTime = 0;
case 'paused'
time = clock;
currentTime = time(6)+60*time(5)+3600*time(4);
pausedTime = currentTime-pausedStartTime;
totalPausedTime = totalPausedTime + pausedTime;
pausedTime = 0;
end
simulation_mode = 'running';
status_text.String = sprintf('Status: %s','Running');
end
%executes callback for run button
function callback_pausebutton(source,eventdata)
switch simulation_mode
case 'running'
status_text.String = sprintf('Status: %s','Paused');
time = clock;
pausedStartTime = time(6)+60*time(5)+3600*time(4);
end
simulation_mode = 'paused';
end
%executes callback for run button
function callback_stopbutton(source,eventdata)
simulation_mode = 'stopped';
status_text.String = sprintf('Status: %s','Stopping');
%Reset all simulation data
robot_position = [0 0 0];
time_data = [0];
depth_data = robot_position(3);
%Reinitialize time sequence
time = clock;
pausedStartTime = time(6)+60*time(5)+3600*time(4);
startTime = pausedStartTime;
pausedTime = 0;
totalPausedTime = 0;
%Reinitialize Plots
plot3(main_plot,robot_position(1),robot_position(2),robot_position(3),'Marker','o','Color','r')
main_plot.XLim = [-riv_length/2 riv_length/2];
main_plot.YLim = [-riv_width/2 riv_width/2];
main_plot.ZLim = [-river_depth 1];
plot(data_plot1,time_data,depth_data)
status_text.String = sprintf('Status: %s','Data is reset.');
simulation_mode = 'paused';
end
end
matlab provides you tools to do this - it is called a profiler. try this
profiler on;
your_script_name;
profiler viewer;
from the output, you can tell which lines or functions cost most of your run time. I use it every time I need to speed up my matlab code.
For some reason when I try to reverse the sign of my current velocity in MATLAB, it just won't do it.
For example, I start off with velocity_x = 3 and velocity_y = 3 (I am drawing circle collisions).
Now inside of checking conditions I need to reverse the sign and I do the following:
% This doesn't work:
velocity_x = -velocity_x;
velocity_y = -velocity_y;
These expressions don't seem to work. Even though in the variable list it still shows as -3, the ball is just twitching and not going in the opposite direction. But when I simply put numbers there, it works fine!
% This works perfectly fine:
velocity_x = -3;
velocity_y = -3;
Here's the whole loop:
velocity_x = 3;
velocity_y = 3;
% While is not commanded to exit the loop
while exit_loop == false
[b1_x_c, b1_y_c] = getCenter(b1);
xMove(b1, velocity_x);
yMove(b1, velocity_y);
if ((b1_x_c + radius + 1) >= WINDOW_WIDTH) || ((b1_y_c + radius + 1) >= WINDOW_HEIGHT)
velocity_x = -1 * velocity_x;
velocity_y = -1 * velocity_y;
elseif ((b1_x_c - radius - 1) <= 0) || ((b1_y_c - radius - 1) <= 0)
velocity_x = (-1) * velocity_x;
velocity_y = (-1) * velocity_y;
end
redraw;
end % of the while loop
When you come in region where if or elseif condition fulfills, sign could change every cycle turn - velocity value 3 -3 3 -3 and so on...
You have to use some flag to indicate that the sign has already been changed and don't change it until that region will be leaved (a kind of hysteresis)
I'm writing a "Peak finder" in Matlab. I've never used Matlab or anything similar before this project, so I'm new to "vectorizing" my code. Essentially, the program needs to take a video of molecules and plot circles on the molecules present in each frame of the video. If a molecule is crowded then it gets a red circle, but if it is not crowded it gets a green circle.
My problem is that some of these videos have 2000 frames and my program takes up to ~25 seconds to process a single frame, which is not practical.
Using tic and toc I've found the trouble maker: A for-loop which calls a function that contains a for-loop.
function getPeaks( orgnl_img, processed_img, cut_off, radius )
% find large peaks peaks by thresholding, i.e. you accept a peak only
% if its more than 'threshold' higher than its neighbors
threshold = 2*std2(orgnl_img);
peaks = (orgnl_img - processed_img) > threshold;
% m and n are dimensions of the frame, named peaks
[m, n] = size(peaks);
cc_centroids = regionprops(peaks, 'centroid');
% Pre-allocate arrays
x_centroid = zeros(1, length(cc_centroids));
y_centroid = zeros(1, length(cc_centroids));
for i = 1:length(cc_centroids)
% Extract the x and y components from cc_centroids struct
x_centroid(i) = cc_centroids(i).Centroid(1);
y_centroid(i) = cc_centroids(i).Centroid(2);
row = int64(x_centroid(i));
col = int64(y_centroid(i));
% Assure that script doesnt attempt to exceed frame
if col-2 > 0 && row-2 > 0 && col+2 < m && row+2 < n
region_of_interest = orgnl_img(col-2:col+2,row-2:row+2);
local_intensity = max(region_of_interest(:));
% Do not plot circle when intensity is 'cut off' or lower
if local_intensity > cut_off
dist_bool = findDistance(cc_centroids, x_centroid(i), y_centroid(i), radius);
if dist_bool == 1
color = 'g';
else
color = 'r';
end
plotCircle(color, x_centroid(i), y_centroid(i), radius)
end
end
end
end
And here is the findDistance function which contains another for-loop and determines if the circles overlap:
function dist_bool = findDistance( all_centroids, x_crrnt, y_crrnt, radius )
x_nearby = zeros(1, length(all_centroids));
y_nearby = zeros(1, length(all_centroids));
for i = 1:length(all_centroids)
if all_centroids(i).Centroid(1) < (x_crrnt+2*radius) &&...
all_centroids(i).Centroid(1) > (x_crrnt-2*radius) &&...
all_centroids(i).Centroid(2) < (y_crrnt+2*radius) &&...
all_centroids(i).Centroid(2) > (y_crrnt-2*radius)
x_nearby(i) = all_centroids(i).Centroid(1);
y_nearby(i) = all_centroids(i).Centroid(2);
pts_of_interest = [x_nearby(i),y_nearby(i);x_crrnt,y_crrnt];
dist = pdist(pts_of_interest);
if dist == 0 || dist > 2*radius
dist_bool = 1;
else
dist_bool = 0;
break
end
end
end
end
I think that there must be much improvement to be done here. I would appreciate any advice.
Thanks! :)
UPDATE: Here are the profiler results. The first section of code is the "getPeaks" function
http://i.stack.imgur.com/VaLdH.png
The hold comes from the plot circle function:
function plotCircle( color, x_centroid, y_centroid, radius )
hold on;
th = 0:pi/50:2*pi;
xunit = radius * cos(th) + x_centroid;
yunit = radius * sin(th) + y_centroid;
plot(xunit, yunit, color);
hold off;
end
I need to write a function spin(pic,x) where it will take a picture and rotate it 90 degrees counter clockwise X amount of times. I have just the 90 degree clockwise rotation in a function:
def rotate(pic):
width = getWidth(pic)
height = getHeight(pic)
new = makeEmptyPicture(height,width)
tarX = 0
for x in range(0,width):
tarY = 0
for y in range(0,height):
p = getPixel(pic,x,y)
color = getColor(p)
setColor(getPixel(new,tarY,width-tarX-1),color)
tarY = tarY + 1
tarX = tarX +1
show(new)
return new
.. but I have no idea how I would go about writing a function on rotating it X amount of times. Anyone know how I can do this?
You could call rotate() X amount of times:
def spin(pic, x):
new_pic = duplicatePicture(pic)
for i in range(x):
new_pic = rotate(new_pic)
return new_pic
a_file = pickAFile()
a_pic = makePicture(a_file)
show(spin(a_pic, 3))
But this is clearly not the most optimized way because you'll compute X images instead of the one you are interested in. I suggest you try a basic switch...case approach first (even if this statement doesn't exists in Python ;):
xx = (x % 4) # Just in case you want (x=7) to rotate 3 times...
if (xx == 1):
new = makeEmptyPicture(height,width)
tarX = 0
for x in range(0,width):
tarY = 0
for y in range(0,height):
p = getPixel(pic,x,y)
color = getColor(p)
setColor(getPixel(new,tarY,width-tarX-1),color)
tarY = tarY + 1
tarX = tarX +1
return new
elif (xx == 2):
new = makeEmptyPicture(height,width)
# Do it yourself...
return new
elif (xx == 3):
new = makeEmptyPicture(height,width)
# Do it yourself...
return new
else:
return pic
Then, may be you'll be able to see a way to merge those cases into a single (but more complicated) double for loop... Have fun...
I have an hour selection drop down 0-23 and minutes selection drop down 0-59 for Start time and End time respectively (so four controls).
I'm looking for an algorithm to calculate time difference using these four values.
Since they're not stored in fancy date/time selection controls, I don't think I can use any standard date/time manipulation functions.
How do I calculate the difference between the two times?
This pseudo-code gives you the algorithm to work out the difference in minutes. It assumes that, if the start time is after the end time, the start time was actually on the previous day.
const MINS_PER_HR = 60, MINS_PER_DAY = 1440
startx = starthour * MINS_PER_HR + startminute
endx = endhour * MINS_PER_HR + endminute
duration = endx - startx
if duration < 0:
duration = duration + MINS_PER_DAY
The startx and endx values are the number of minutes since midnight.
This is basically doing:
Get number of minutes from start of day for start time.
Get number of minutes from start of day for end time.
Subtract the former from the latter.
If result is negative, add number of minutes in a day.
Don't be so sure though that you can't use date/time manipulation functions. You may find that you could easily construct a date/time and calculate differences with something like:
DateTime startx = new DateTime (1, 1, 2010, starthour, startminute, 0);
DateTime endx = new DateTime (1, 1, 2010, endhour , endminute , 0);
Integer duration = DateTime.DiffSecs(endx, startx) / 60;
if (duration < 0)
duration = duration + 1440;
although it's probably not needed for your simple scenario. I'd stick with the pseudo-code I gave above unless you find yourself doing some trickier date/time manipulation.
If you then want to turn the duration (in minutes) into hours and minutes:
durHours = int(duration / 60)
durMinutes = duration % 60 // could also use duration - (durHours * 60)
This will compute duration in minutes including the year as factor
//* Assumptions:
Date is in Julian Format
startx = starthour * 60 + startminute
endx = endhour * 60 + endminute
duration = endx - startx
if duration <= 0:
duration = duration + 1440
end-if
if currday > prevday
duration = duration + ((currday-preday) - 1 * 1440)
end-if
First you need to check to see if the end time is greater than or equal to the start time to prevent any problems. To do this you first check to see if the End_Time_Hour is greater than Start_Time_Hour. If they're equal you would instead check to see if End_Time_Min is greater than or equal to Start_Time_Min.
Next you would subtract Start_Time_Hour from End_Time_Hour. Then you would subtract Start_Time_Min from End_Time_Min. If the difference of the minutes is less than 0 you would decrement the hour difference by one and add the minute difference to 60 (or 59, test that). Concat these two together and you should be all set.
$start_time_hr = 5;
$start_time_mi = 50;
$end_time_hr = 8;
$end_time_mi = 30;
$diff = (($end_time_hr*60)+$end_time_mi) - (($start_time_hr*60)+$start_time_mi);
$diff_hr = (int)($diff / 60);
$diff_mi = (int)($diff) - ($diff_hr*60);
echo $diff_hr . ':' . $diff_mi;
simple equation should help:
mindiff = 60 + endtime.min - starttime.min
hrdiff = ((mindiff/60) - 1) + endtime.hr - starttime.hr
This gives you the duration in hours and minutes
h1 = "hora1"
m1 "min1"
h2 "hora2"
m2 = "min2"
if ( m1 > m2)
{
h3 = (h2 - h1) - 1;
}
else
{
h3 = h2 - h1;
}
m1 = 60 - m1;
if (m1 + m2 >= 60)
{
m3 = 60 - (m1 + m2);
} else if (m3 < 0)
{
m3 = m3 * -1;
}
else
{
m3 = m1 + m2;
}
System.out.println("duration:" + h3 + "h" + m3 + "min");
If you have a function that returns the number of days since some start date (e.g. dayssince1900) you can just convert both dates to seconds since that start date, do the ABS(d1-d2) then convert the seconds back to whatever format you want e.g. HHHH:MM:SS
Simple e.g.
SecondsSince1900(d)
{
return dayssince1900(d)*86400
+hours(d)*3600
+minutes(d)*60
+seconds(d);
}
diff = ABS(SecondsSince1900(d1)-SecondsSince1900(d2))
return format(diff DIV 3600)+':'+format((diff DIV 60) MOD 60)+':'+format(diff MOD 60);
Hum: Not that simple if you have to take into account the leap seconds astronomers are keen to put in from time to time.