首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何使用MATLAB中的计时器在固定的时间间隔内运行函数

如何使用MATLAB中的计时器在固定的时间间隔内运行函数
EN

Stack Overflow用户
提问于 2019-07-19 22:23:01
回答 2查看 920关注 0票数 4

我想每隔30分钟运行一个函数。每次函数运行时,它将接受不同的输入。假设我想跑这100次。函数为查找天气,输入为location1、location2、location3、.、location100

我试过:

代码语言:javascript
复制
for a = 1:100
    t = timer;          
    t.StartDelay = 30*60*(a-1)       
    t.TimerFcn = @(scr, event) run('lookupweather');
    start(t)
end 

这里的问题是我无法找到输入位置信息的方法。如果我尝试了查找天气(Location1),代码就失败了。当然,如果没有位置输入,则查找天气函数就会失败。有人能帮忙吗?

编辑:我意识到我可以做固定的间隔

代码语言:javascript
复制
t = timer;
t.Period = 30*60;
t.TasksToExecute = 100;
t.ExecutionMode = 'fixedRate';
t.TimerFcn = @(src, event) run('lookupweather');
start(t)

不过,我仍然不知道如何将位置信息输入到我的函数lookupweather中。

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2019-07-19 23:12:45

您需要使用单元格数组声明计时器回调函数,如下所示:

代码语言:javascript
复制
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

您还可能需要使用位置的一维矢量(或数组),如下所示:

代码语言:javascript
复制
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

第4版

这使用在计时器回调中修改的全局结构。考虑将其封装到处理程序类或嵌套函数中,以避免使用全局变量。

代码语言:javascript
复制
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

第4版结果

代码语言:javascript
复制
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

第5版

此版本使用句柄类。它可以同步处理,也可以异步处理。

Test.m

代码语言:javascript
复制
    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);

TemperatureProcessor.m

代码语言:javascript
复制
    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

第5版结果

代码语言:javascript
复制
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
票数 4
EN

Stack Overflow用户

发布于 2019-07-21 07:44:08

对于一般的解决方案,您可以创建自己的事件和侦听器类。

例如,创建一个名为.m的新sampleEvent.m文件,您可以在其中编写

代码语言:javascript
复制
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

和另一个名为.m的sampleListener.m文件,您在其中编写

代码语言:javascript
复制
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允许您使用特定事件数据

如果您不熟悉Maltab中的对象,请参见这篇数学文章。基本上,在启动任何定时例程之前,您需要用

代码语言:javascript
复制
weatherEvent = weather;
weatherEventHandler = sampleListener(weather);

现在,您只需要通过每30分钟或以其他方式调用weather.lookup来触发事件。

实际上,如果希望在后台运行timer,可以使用weatherlookup。您已经知道timer是如何工作的,在我前面的示例中,weather.lookup不接受任何参数。所以你遇到的问题不会发生在这里。

您可以在单独的.m文件中或直接在wheather类中实现计时代码。如果希望计时器自动启动,可以在weather的构造函数中定义方法,这就是我在示例中展示的。

一些评论:

使用100个变量的weatherlookup规范是没有意义的。如果这是由于Matlab本机获取未指定数量的“位置”,则只需一次使用1 "location“调用weatherlookup,并使用cellfun

我也不确定timer的问题是否是Matlab真正的限制。.TimerFcn字段可以是任何函数句柄.换句话说,您应该尝试将我的示例中的@self.lookup替换为直接向上的@()notify(self,'lookup_timedriven')

另外,你似乎想做的是用谷歌AppScript + GoogleSheet更好地实现。Google提供了时间驱动的触发器,没有任何额外的东西,它将在云中为您运行程序(只要您不太频繁地运行;一次非常30分钟就可以了)。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/57120178

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档