55295
MATLAB のタイマーを使って、プログラムを実行した最後に一度だけ  
excelファイルにデータを書き込もうとしています。

TimerCallback.mとtimer_sample.mを同じフォルダに入れて、timer_sample.mを実行します。  
MATLABは「mac-64bitのバージョンR2017a」です。

考え方としては、[MATLABで複数の addAnalogInputChannel
を同時に定義する時のエラー](https://ja.stackoverflow.com/questions/54908/matlab%E3%81%A7%E8%A4%87%E6%95%B0%E3%81%AE-
addanaloginputchannel-%E3%82%92%E5%90%8C%E6%99%82%E3%81%AB%E5%AE%9A%E7%BE%A9%E3%81%99%E3%82%8B%E6%99%82%E3%81%AE%E3%82%A8%E3%83%A9%E3%83%BC/54914#54914)と[MATLAB
のタイマーを使用して excel
ファイルを作成するプログラムのエラー](https://ja.stackoverflow.com/questions/54899/matlab-%E3%81%AE%E3%82%BF%E3%82%A4%E3%83%9E%E3%83%BC%E3%82%92%E4%BD%BF%E7%94%A8%E3%81%97%E3%81%A6-excel-%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB%E3%82%92%E4%BD%9C%E6%88%90%E3%81%99%E3%82%8B%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%A0%E3%81%AE%E3%82%A8%E3%83%A9%E3%83%BC)で書いたプログラムを組み合わせたプログラムを作成しようとしています。

**問題**  
①TimerCallback.mで以下のように１つ１つ定義しているものをfor文でtimer_sample.mで定義した変数numの値だけxlswriteを個別に実行する方法がわからず困っています。

```

    xlswrite(this.filename, this.x_value, 'sender');
    xlswrite(this.filename, this.y_value, 'receiver');
    xlswrite(this.filename, this.z_value, 'receiver');
    
```

②timer_sample.mにおいて、変数numの値だけタイマーコールバックをfor文で個別に呼び出す方法がわかりません。

**プログラム**  
timer_sample.m

```

    mycallback = TimerCallback('data.xlsx');
    mytimer = timer('TimerFcn', @mycallback.callback, 'StartDelay', 30);
    start(mytimer);
    num = 3
    for i = 1:1:num
        mycallback.x_value = [mycallback.x_value, [1 2 3]];
        mycallback.y_value = [mycallback.y_value, [4 5 6]];
        mycallback.z_value = [mycallback.y_value, [7 8 9]];
    end
    
```

TimerCallback.m

```

    classdef TimerCallback < handle
        properties  %public properties
            state;
            x_value;
            y_value;
            filename;
        end
        methods
            %constructor
            function this = TimerCallback(filename)
                if nargin > 0
                    this.filename = filename;
                end
                this.state = true;
            end
    
            %callback function
            function callback(this, ~, ~)
                xlswrite(this.filename, this.x_value, 'sender');
                xlswrite(this.filename, this.y_value, 'receiver');
                xlswrite(this.filename, this.z_value, 'receiver');
                this.state = false;
                disp('Callback executed');
            end
        end
    end
    
```

**ご回答を受けて補足**

timer_sample.mに関して

```

    for i = 1:1:num
        mycallback.x_values{i} = [mycallback.x_values{i}  event.Data(i)]; 
      end
    
```

event.Dataはnum列からなる多次元行列で、その1列目をmycallback.r1_values、2列目をmycallback.r2_valuesにappendさせていきたいです。

TimerCallback.mに関して

```

    this.x_values = cell(1,num); % cell配列の初期化(1x3の空cell配列)
    
```

とありましたが、event.Data(1)から取得されるのは行数が未定で１列の配列です。  
またここでも、その1列目をmycallback.r1_values、2列目をmycallback.r2_valuesのように変数を入力numに応じで生成したいと考えています。
CC BY-SA 4.0
2019-05-19T10:01:48.973
55092
2019-05-28T06:54:21.343
2019-05-28T06:50:31.247
32568
32568
question
matlab
MATLABのタイマーコールバックに引数を渡して拡張性のあるプログラムを書く方法について
最終的に何をしたいのかが良くわからないので、はっきりしたことは言えませんが、とりあえず思いつくのは二つの方法です。

* * *

## タイマーを`num`個、作成する方法

timer_sample.m

```

    num = 3;
    for i = 1:num
        oneCallback = TimerCallback('data.xlsx');
        mycallbacks(i) = oneCallback;
        mytimers(i) = timer('TimerFcn', @oneCallback.callback, 'StartDelay', 30);
    end
    
    for i = 1:num
        start(mytimers(i))
    end
    
    for i = 1:num
        mycallbacks(i).x_value = [mycallbacks(i).x_value, [1 2 3]+num];
        mycallbacks(i).y_value = [mycallbacks(i).y_value, [1 2 3]+num];
        mycallbacks(i).z_value = [mycallbacks(i).z_value, [1 2 3]+num];
    end
    
```

TimerCallback.m はそのままです (ただ、元のコードは`z_value`の宣言がされていませんが)。

但し、この方法だと、最後に`xlswrite`の書き込みで、タイマー同士で競合が起こる可能性があります。

* * *

## cell配列を利用し、`TimerCallback`クラスで`num`個分のデータを管理する方法

timer_sample.m

```

    num = 3;
    
    mycallback = TimerCallback('data.xlsx', num); % データの個数 num も渡す
    mytimer = timer('TimerFcn', @mycallback.callback, 'StartDelay', 30);
    start(mytimer)
    
    for i = 1:num
        mycallback.x_values{i} = [mycallback.x_values{i} [1 2 3]]; % 波かっこを使っていることに注意
        mycallback.y_values{i} = [mycallback.y_values{i} [4 5 6]];
        mycallback.z_values{i} = [mycallback.z_values{i} [7 8 9]];
    end
    
```

TimerCallback.m

```

    classdef TimerCallback < handle
        properties
            state
            x_values % num個の数値の配列を入れるcell配列
            y_values
            z_values
            filename
            num
        end
    
        methods
            % constructor
            function this = TimerCallback(filename, num)
                this.filename = filename;
                this.num = num;
                this.x_values = cell(1,num); % cell配列の初期化(1 x num の空cell配列)
                this.y_values = cell(1,num);
                this.z_values = cell(1,num);
                this.state = true;
            end
    
            % callback function
            function callback(this, ~, ~)
                for i = 1:this.num
                    xlswrite(this.filename, this.x_values{i}, 'sender')
                    xlswrite(this.filename, this.y_values{i}, 'receiver')
                    xlswrite(this.filename, this.z_values{i}, 'receiver')                
                end
    
                this.state = false;
                disp('Callback executed')
            end
        end
    end
    
```

ただ、この方法でも

  * xlswrite は、同じシート名が既にある時、上書きしてしまう
  * そもそも xlswrite は Mac では、機能が非常に限定されている

ために、思う通りに動くとは限りません。
CC BY-SA 4.0
2019-05-27T16:13:18.720
55295
2019-05-28T06:54:21.343
2019-05-28T06:54:21.343
3605
3605
55092
answer