Search code examples
matlabtimer

How to use timer in MATLAB to run a function at a fixed interval


I would like to run a function at 30 mins interval. Each time the function run, it will take a different input. Let's say I want to run this 100 times. The function is lookupweather and the input is location1, location2, location3,..., location100

I've tried:

for a = 1:100
    t = timer;          
    t.StartDelay = 30*60*(a-1)       
    t.TimerFcn = @(scr, event) run('lookupweather');
    start(t)
end 

The issue here is that I cannot find away to input the location information. If I tried something lookupweather(location1), the code failed. Of course, without the location input, the lookupweather function fails. Could anyone help?

Edit: I've realized I could do fixed interval

t = timer;
t.Period = 30*60;
t.TasksToExecute = 100;
t.ExecutionMode = 'fixedRate';
t.TimerFcn = @(src, event) run('lookupweather');
start(t)

I still don't know how to input the location information into my function lookupweather, though.


Solution

  • You need to declare the timer callback function using a cell array, something like this:

    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
    

    You may also need to use a one-dimensional vector (or array) of locations, something like this:

    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
    

    Version 4

    This uses a global struct that is modified in the timer callback. Consider encapsulating this in a handler class or nested function to avoid using a global variable.

    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
    

    Version 4 Results

    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
    

    Version 5

    This version uses a handle class. It can process either synchronously or asynchronously.

    Test.m

        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

        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
    

    Version 5 Results

    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