データを保存するファイル名を実行ごとに変更する


はじめに

Simulinkには、シミュレーション中のデータを保存する「To File」モデルがあります。
このモデルに入力データを繋げて名前をセットすると、その名前のファイルが作られ、そこに入力データが保存されます。
ですが、同じファイル名の場合は上書き保存されるため、実験後に誤ってシミュレーションの実行ボタンを押してしまうと、実験データが消えてしまうという悲劇が起きます。

そこで、このファイル名をシミュレーションの実行ごとに変えることができればこの悲劇は回避できると考え、それ用のS-Functionを作成してみました。
(S-Function自体の解説は後日投下予定ですが、苦戦中・・・)

実装とプログラム

1.まずTo Fileモデルを配置し、入力を接続、保存形式などを設定します。

2.そして空いている場所に、S-Functionモデルを配置します。

3.配置後ブロックパラメータの入力フォームが出てくるので、下記のように設定。
 S-Function名    :SaveFileNameChange
 S-Functionパラメータ:modelname, savename

 ※図と違い配置直後はS-Functionの左右に入出力の矢印がありますが、実行時に消えます

4.入力フォームのS-Function名の横の「編集」を選択し、下記コードの関数ファイルを作成し保存。

SaveFileNameChangeのコード(展開)
SaveFileNameChange.m
function [sys,x0,str,ts] = SaveFileNameChange(t,x,u,flag, modelname, savename)
% 実行時、指定したモデル(modelname)のファイル名を
% 指定したファイル名(savename)+日時の文字列に変更する
%
switch flag

  % Initialization %
  case 0
    [sys,x0,str,ts]=mdlInitializeSizes(modelname, savename);

  case {1, 2, 3, 4, 9}
    sys = [];

  otherwise
    DAStudio.error('Simulink:blocks:unhandledFlag', num2str(flag));

end

% end sfuntmpl
%
%=============================================================================
% mdlInitializeSizes
%=============================================================================
function [sys,x0,str,ts]=mdlInitializeSizes(modelname, savename)

sizes = simsizes;
sizes.NumContStates  = 0;
sizes.NumDiscStates  = 0;
sizes.NumOutputs     = 0;
sizes.NumInputs      = 0;
sizes.DirFeedthrough = 1;
sizes.NumSampleTimes = 1;   % at least one sample time is needed
sys = simsizes(sizes);

x0  = [];
str = [];
ts  = [0 0];

%指定したモデルの検索
ret_sys = find_system(gcs);
cur_sys = [ret_sys{1} '/' modelname];

%現在日時の追加
dstr = datestr(now,'yymmdd_HHMMSS');
fstr = [savename '_' dstr '.mat'];

%ファイル名書き換え
set_param(cur_sys,'Filename',fstr);

% end mdlInitializeSizes

コードの簡単な説明(展開)
  case 0
    [sys,x0,str,ts]=mdlInitializeSizes(modelname, savename);

S-Functionの標準機能で、シミュレーションの状況に合わせてflagの値が変わります。
シミュレーション開始時は0なので、mdlInitializeSizes関数に入ります。
また、後述するマスク操作により、modelname, savenameにモデル名とファイル名の文字列が入ってきます。

sizes.NumOutputs     = 0;
sizes.NumInputs      = 0;
sizes.DirFeedthrough = 1;

mdlInitializeSizes関数の先頭では、S-Functionの動作(入力なし、出力なし、状態変数無し)を指定してます。

ret_sys = find_system(gcs);
cur_sys = [ret_sys{1} '/' modelname];

入力した名前のモデルを検索します。
gcs:実行中のシミュリンクモデル全体。find_systemでそのパスを取得。
cur_sys変数:対象のモデルのパスが格納される

dstr = datestr(now,'yymmdd_HHMMSS');
fstr = [savename '_' dstr '.mat'];

入力したファイル名に日時の文字列を追加してます。

set_param(cur_sys,'Filename',fstr);

最後に、見つけたモデルの「Filename」というパラメータを、作成した文字列に書き換えます。
要するに、To Fileモデルのファイル名の欄を書き換えています。

■コード解説終了■

 
5.S-Functionを右クリックし、「マスク/マスクの作成」を選択

6.「パラメータとダイアログ」タブの「ダイアログボックス」に下記の2つのエディターを追加


 ※分かりやすくするために「A」(テキスト)を追加してますが、無くても動作します

7.S-Functionのパラメータを設定
S-Functionをダブルクリックすると、6で設定した入力項目が出てきます。
下記を設定すると、To Fileモデルのファイル名が、基本ファイル名+日時に変化します。
 To Fileのモデル名:To File
 基本ファイル名:test3

8.あとはシミュレーションの実行を何度も押してみましょう。
押すたびにTo Fileモデルの名前が変わり、フォルダに新しい.matファイルが作られるはずです。

補足(複数の使用について)

このS-Functionは特殊な値は使っていないため、いくつでも配置できます。
なので、下記のようにTo Fileモデルの数だけ配置することができます。
その時は、それぞれのTo Fileモデルの名前に合わせて設定してください。

おわりに

以上でファイル名を実行ごとに変換することができました。
このモデルは一度作ってしまえばコピペで使いまわせるので、2回目以降はほぼ手間なしで使えます。

また、保存するファイル名を変えるのに日時を使用していますが、他の変換規則にしたいときは、コードで日時を追加してる場所を修正してください。あの辺はただの文字列編集なので。

以上です。