我想每隔30分钟运行一个函数。每次运行该函数时,都会采用不同的输入。假设我要运行100次。函数为lookupweather,输入为location1,location2,location3,...,location100
我尝试过:
for a = 1:100
t = timer;
t.StartDelay = 30*60*(a-1)
t.TimerFcn = @(scr, event) run('lookupweather');
start(t)
end
这里的问题是我找不到地方输入位置信息。如果我尝试了一些lookupweather(location1),则代码将失败。当然,如果没有位置输入,lookupweather函数将失败。有人可以帮忙吗?
编辑:我意识到我可以固定间隔
t = timer;
t.Period = 30*60;
t.TasksToExecute = 100;
t.ExecutionMode = 'fixedRate';
t.TimerFcn = @(src, event) run('lookupweather');
start(t)
但是,我仍然不知道如何将位置信息输入到我的函数lookupweather中。
答案 0 :(得分:3)
您需要使用单元格数组声明计时器回调函数,如下所示:
location_index = 1;
t = timer;
t.Period = 1; %30*60;
t.TasksToExecute = 5; %100;
t.ExecutionMode = 'fixedRate';
t.TimerFcn = {@timer_callback, location_index};
start(t);
process_locations = true;
while process_locations
% . . .
end
stop(t);
delete(t);
function timer_callback(obj, event, location_index)
fprintf("Location index = %03d\n", location_index);
end
您可能还需要使用位置的一维向量(或数组),如下所示:
locations = zeros(1, 100);
t = timer;
t.Period = 1; %30 * 60;
t.TasksToExecute = 5; %100;
t.ExecutionMode = 'fixedRate';
%t.TimerFcn = {@timer_callback2};
t.TimerFcn = {@timer_callback3, locations};
start(t);
process_locations = true;
while process_locations
% . . .
end
stop(t);
delete(t);
function timer_callback2(obj, event)
persistent location_index;
if isempty(location_index)
location_index = 1;
end
fprintf("Location index = %03d\n", location_index);
location_index = location_index + 1;
end
function timer_callback3(obj, event, locations)
persistent location_index
if isempty(location_index)
location_index = 1;
end
locations(location_index) = 12.3; % Get value from temperature sensor.
fprintf("locations(%03d) = %f\n", location_index, locations(location_index));
location_index = location_index + 1;
end
这使用在计时器回调中修改的全局结构。考虑将其封装在处理程序类或嵌套函数中,以避免使用全局变量。
clear all;
clc;
number_of_iterations = 10; % 100
number_of_locations = 5;
% Create a global struct for the data.
% Consider encapsulating in a class rather than using a global.
global temperature_data;
temperature_data = struct("IterationIndex", 1, "Processed", false, "Locations", zeros(number_of_iterations, number_of_locations));
t = timer;
t.Period = 1; %30 * 60;
t.TasksToExecute = number_of_iterations;
t.ExecutionMode = 'fixedRate';
t.TimerFcn = {@TimerCallback4};
start(t);
while temperature_data.Processed == false
% . . .
% Yield some processing time.
time_delay = t.Period * 1000 / 10;
java.lang.Thread.sleep(time_delay);
end
stop(t);
delete(t);
function TimerCallback4(obj, event)
global temperature_data;
% Cycle through locations.
for location_index = 1:5
% Get value from temperature sensor.
temperature_data.Locations(temperature_data.IterationIndex, location_index) = 100 * rand;
fprintf("temperature_data(%03d, %d) = %5.2f\n", temperature_data.IterationIndex, location_index, temperature_data.Locations(temperature_data.IterationIndex, location_index));
end
% Test for completion of processing.
if temperature_data.IterationIndex >= size(temperature_data.Locations, 1)
temperature_data.Processed = true;
else
temperature_data.IterationIndex = temperature_data.IterationIndex + 1;
end
end
TimerCallback4() 0.058
TimerCallback4() 1.023
TimerCallback4() 2.033
TimerCallback4() 3.042
TimerCallback4() 3.961
TimerCallback4() 4.975
TimerCallback4() 5.982
TimerCallback4() 6.990
TimerCallback4() 8.002
TimerCallback4() 9.008
10.7889 18.2228 9.9095 48.9764 19.3245
89.5892 9.9090 4.4166 55.7295 77.2495
31.1940 17.8982 33.8956 21.0146 51.0153
90.6364 62.8924 10.1534 39.0855 5.4617
50.1283 43.1721 99.7560 81.1603 48.5652
89.4448 13.7547 39.0005 92.7356 91.7494
71.3574 61.8337 34.3288 93.6027 12.4774
73.0585 64.6477 83.3152 39.8282 74.9822
83.5221 32.2460 55.2262 97.9129 54.9309
33.0424 61.9472 36.0637 75.6510 41.3901
此版本使用句柄类。它可以同步或异步处理。
clear all;
clc;
% Define the settings.
number_of_iterations = 10; % 100
number_of_locations = 5;
period = 1; % 30 * 60 % Seconds.
% Create the object with required settings.
temperature_processor = TemperatureProcessor(number_of_iterations, number_of_locations, period);
% Do the process synchronously.
temperature_processor.ProcessSync();
disp(temperature_processor.Locations);
% Do the process asynchronously.
temperature_processor.IsProcessed = false;
temperature_processor.ProcessAsync();
while temperature_processor.IsProcessed == false
% Do other stuff.
% . . .
% Yield some processing time.
%pause(0.001);
java.lang.Thread.sleep(1); % milliseconds.
end
disp(temperature_processor.Locations);
% Delete the object.
delete(temperature_processor);
classdef TemperatureProcessor < handle
properties
IsProcessed = false;
Locations;
end
properties (Access = private)
% Define default values.
NumberOfIterations = 100;
NumberOfLocations = 5;
Period = 30 * 60; % Seconds.
AsyncIterationIndex = 1;
AsyncTimer;
end
methods
% Constructor.
function obj = TemperatureProcessor(number_of_iterations, number_of_locations, period)
fprintf("obj.TemperatureProcessor() constructor\n");
if nargin == 3
obj.NumberOfIterations = number_of_iterations;
obj.NumberOfLocations = number_of_locations;
obj.Period = period;
end
obj.Locations = zeros(obj.NumberOfIterations, obj.NumberOfLocations);
end
% Destructor.
function delete(obj)
fprintf("obj.delete() destructor\n");
try
stop(obj.AsyncTimer);
delete(obj.AsyncTimer);
catch
end
end
function ProcessSync(obj)
fprintf("obj.ProcessSync()\n");
iteration_index = 1;
the_timer = timer;
the_timer.Period = obj.Period;
the_timer.TasksToExecute = obj.NumberOfIterations;
the_timer.ExecutionMode = 'fixedRate';
the_timer.TimerFcn = {@TimerCallbackSync};
tic;
start(the_timer);
wait(the_timer);
delete(the_timer);
function TimerCallbackSync(timer_obj, timer_event)
fprintf("obj.Process.TimerCallbackSync() %0.3f\n", toc);
% Cycle through locations.
for location_index = 1:obj.NumberOfLocations
% Get value from temperature sensor.
obj.Locations(iteration_index, location_index) = 100 * rand;
fprintf("obj.Locations(%03d, %d) = %5.2f\n", iteration_index, location_index, obj.Locations(iteration_index, location_index));
end
% Test for completion of processing.
if iteration_index >= obj.NumberOfIterations
obj.IsProcessed = true;
else
iteration_index = iteration_index + 1;
end
end
end
function ProcessAsync(obj)
fprintf("obj.ProcessAsync()\n");
try
stop(obj.AsyncTimer);
delete(obj.AsyncTimer);
catch
end
obj.AsyncIterationIndex = 1;
obj.AsyncTimer = timer;
obj.AsyncTimer.Period = obj.Period;
obj.AsyncTimer.TasksToExecute = obj.NumberOfIterations;
obj.AsyncTimer.ExecutionMode = 'fixedRate';
obj.AsyncTimer.TimerFcn = {@obj.TimerCallbackAsync};
tic;
start(obj.AsyncTimer);
end
function TimerCallbackAsync(obj, timer_obj, timer_event)
fprintf("obj.Process.TimerCallbackAsync() %0.3f\n", toc);
% Cycle through locations.
for location_index = 1:obj.NumberOfLocations
% Get value from temperature sensor.
obj.Locations(obj.AsyncIterationIndex, location_index) = 100 * rand;
fprintf("obj.Locations(%03d, %d) = %5.2f\n", obj.AsyncIterationIndex, location_index, obj.Locations(obj.AsyncIterationIndex, location_index));
end
% Test for completion of processing.
if obj.AsyncIterationIndex >= obj.NumberOfIterations
try
stop(obj.AsyncTimer);
delete(obj.AsyncTimer);
catch
end
obj.IsProcessed = true;
else
obj.AsyncIterationIndex = obj.AsyncIterationIndex + 1;
end
end
end
end
obj.TemperatureProcessor() constructor
obj.ProcessSync()
obj.Process.TimerCallbackSync() 0.051
obj.Process.TimerCallbackSync() 1.029
obj.Process.TimerCallbackSync() 2.026
obj.Process.TimerCallbackSync() 3.025
obj.Process.TimerCallbackSync() 4.034
obj.Process.TimerCallbackSync() 5.024
obj.Process.TimerCallbackSync() 6.023
obj.Process.TimerCallbackSync() 7.023
obj.Process.TimerCallbackSync() 8.023
obj.Process.TimerCallbackSync() 9.023
obj.ProcessAsync()
obj.Process.TimerCallbackAsync() 0.009
obj.Process.TimerCallbackAsync() 1.005
obj.Process.TimerCallbackAsync() 2.004
obj.Process.TimerCallbackAsync() 3.005
obj.Process.TimerCallbackAsync() 4.007
obj.Process.TimerCallbackAsync() 5.005
obj.Process.TimerCallbackAsync() 6.005
obj.Process.TimerCallbackAsync() 7.005
obj.Process.TimerCallbackAsync() 8.005
obj.Process.TimerCallbackAsync() 9.005
obj.delete() destructor
答案 1 :(得分:1)
对于一般解决方案,您可以创建自己的Event and Listener类。
例如,创建一个名为sampleEvent.m
的新.m文件,并在其中写入
classdef weather < handle
events
lookup_timedriven
end
methods
function lookup(self)
notify(self,'lookup_timedriven')
end
%%%% optional
function self = weather(self)
t = timer;
t.StartDelay = 1; % leave some time for event handler to be created
t.TimerFcn = @()[]; % You can't create a true empty function_handle unless you have a do nothing function in your library.
start(t)
for a = 0:99 % the weather calls
t = timer;
t.StartDelay = 30*60*a;
t.TimerFcn = @self.lookup;
start(t)
end
end
%%%%
end
end
和另一个名为sampleListener.m
的.m文件,您可以在其中写入
classdef sampleListener < handle
methods
function sampleListener(weather_obj)
lh = addlistener(weather_obj,'lookup_timedriven',@sampleListener.handleEvnt);
end
end
methods (Static) % static is a must. Because addlistener calls the function without instantiating an object
function handleEvnt(src,~)
cellfun(@lookupweather, cellOfLocations, 'UniformOutput', false);
end
end
end
假设您的函数lookupweather
接受1个参数并将数据正确存储在幕后,并且cellOfLocations
是“位置”的单元格数组。每当触发事件时,您都可以将cellfun(@lookupweather, cellOfLocations, 'UniformOutput', false)
替换为想要执行的操作。 Matlab允许您使用event-specific data。
如果您不熟悉Maltab中的对象,请参见this mathwork article。基本上,在开始任何计时例程之前,您需要使用
实例化事件和处理程序类。weatherEvent = weather;
weatherEventHandler = sampleListener(weather);
现在,您只需每30分钟或以您希望的其他方式调用weather.lookup
即可触发事件。
实际上,如果希望在后台运行timer
,则可以使用weatherlookup
。您已经知道timer
的工作方式,在我上面的示例中,weather.lookup
没有任何参数。因此,您遇到的问题不会在这里发生。
您可以在单独的.m文件中或直接在wheather
类中实现计时代码。如果希望计时器自动启动,则可以在weather
的构造函数中定义方法,这就是我在示例中显示的内容。
一些评论:
您为weatherlookup
指定100个变量没有任何意义。如果是由于Matlab固有地获取了未指定数量的“位置”,则只需一次调用1个“位置”来调用weatherlookup
,然后使用cellfun
。
我也不确定您的timer
问题是否是Matlab的真正限制。 .TimerFcn
字段can be any function handle。换句话说,您应该尝试将我的示例中的@self.lookup
替换为@()notify(self,'lookup_timedriven')
。
此外,使用Google AppScript + GoogleSheet可能可以更好地实现您的目标。 Google提供了时间驱动的触发器,无需任何额外的操作,并且可以在云端运行您的程序(只要您不经常执行该程序;一次30分钟就可以了)。