2017-10-24 11 views
0

Simulink内のMatlab Level-2 S関数でオブジェクトをインポートできるかどうか疑問に思っていました。SimlinkのMatlab Level 2 S関数のMatlabオブジェクトのインポート

以前は、Matlabの動的モデルに強化学習を適用しました。その結果、私はポリシーの生成と更新を扱ういくつかのクラスを作成しました。今、私はより複雑な動的システムを持っているため、Simulinkに移行する必要があります。私はCのS関数に精通していますが、すでに2つのクラスにMatlabコードがあるので、これらのオブジェクトを使用するMatlab S関数を使用することを考えていました。

私のワークフローは次のとおりです。ポリシーオブジェクトが初期化されたMatlabのメイン関数は、動的モデルを使用してSimulinkファイルを呼び出します。 S-機能では、ポリシーオブジェクトはアクション(コントロールシステムの出力)を選択するための呼び出しです。 Simulinkファイルの数多くのシミュレーションの後で、ポリシーオブジェクト(実際にはその重み)がMatlabのメイン関数で更新されます。

したがって、SimulinkのMatlab S-functionでpolicyオブジェクトをインポートする方法が必要です。パラメータとしてインポートしようとしましたが、数値のみが受け入れられます。主なMatlabスクリプトの重みを更新する必要があるため、S関数内でオブジェクトを保持することはできません(したがって、初期化関数内でオブジェクトを初期化します)。

これは可能ですか?どんな提案も大歓迎です!次のように

ポリシークラスの例は次のとおりです。

classdef Policy 
    %% Accessible properties: 
    properties 
     a;     % selected action index 
     actions;   % actions list 
     basis;    % type of basis function 
     centres;   % list of centres of the RBFs 
     exploration_rate; % exploration rate 
     mu;     % width of each RBF 
     nbasis;    % no. basis functions overall 
     states;    % list of discrete states 
     weights;   % weights of the linear function approximation 
    end 

    %% Protected properties: 
    properties (Access = protected) 
     na;     % no. actions 
     ns;     % no. discrete states 
     nrbf;    % no. radial basis functions per action 
     state;    % current state 
     Q;     % Q value for each action-state pair 
    end 

    %% Accessible methods: 
    methods %(Access = protected) 
     %% Initialization function: 
     function obj = Policy(actions,states,epsilon,basis,mu) 
      %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 
      % Input: 
      % actions: actions list 
      % states: states list or centres of the RBFs 
      % epsilon: initial exploration rate 
      % delta: discount factor 
      % basis: type of basis functions 
      % mu:  width of each RBF 
      %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 

      if nargin<4 
       basis = 'basis_exact'; 
      end 

      obj.actions = actions; 
      obj.states = states; 
      obj.exploration_rate = epsilon; 

      switch basis 
       case 'basis_exact' 
        obj.basis = basis; 
        obj.states = states; 
        obj.ns = size(states,1); 
       case 'basis_rbf' 
        obj.basis = basis; 
        obj.centres = states; 
        obj.mu = mu; 
        obj.nrbf = size(states,1); 
       otherwise 
        error(['Only exact and radial basis functions',... 
        'supported']); 
      end 
     end 

     %% Setter function for the features' weights: 
     function obj = set_weights(obj,weights) 
      obj.weights = weights; 
     end 

     %% Update the exploration rate with the given rate: 
     function obj = update_epsilon(obj,rate) 
      obj.exploration_rate = obj.exploration_rate*rate; 
     end 

     %% Select an action: 
     function obj = select_action(obj,state)    
      % Store the current state: 
      obj.state = state; 
      % Compute the state-action values for the current state: 
      obj = obj.qvalues(); 
      % Get the current action with an epsilon-greedy policy: 
      obj.a = obj.eGreedy(); 
     end 

     %% Evaluate the features: 
     function phi = get_features(obj,state,action) 
      % Store the current state: 
      obj.state = state; 
      % Get the features: 
      phi = feval(obj.basis,action); 
     end 
    end 

    %% Protected methods: 
    methods (Access=protected) 
     %% Find the discrete state: 
     function s = discretizeState(obj,x)    
      % Copy the row vector entries (continuous states) to all rows: 
      x = repmat(x,obj.ns,1); 
      % Select the row using the minimum Eucledian distance: 
      [~,s] = min(sum((obj.states-x).^2,2).^0.5); 
     end 

     %% Get the Q-value function for current state and action: 
     function q = qvalue(obj,action) 
      phi = feval(obj.basis,action); 
      q = phi' * obj.weights; 
     end 

     %% Get the Q-value functions for the current state: 
     function obj = qvalues(obj)    
      % Initialize the Q-values for the current state: 
      obj.Q = zeros(obj.na,1); 
      % Calculate the state-action values for the current state: 
      for a=1:obj.na 
       obj.Q(a) = obj.qvalue(a); 
      end 
     end 

     %% Get an action with an epsilon-greedy exploration policy: 
     function a = eGreedy(obj) 
      % Generate a random number: 
      r = rand; 

      % Select the action that maximises Q(s) 
      if (r>obj.exploration_rate)    
       [~,a] = max(obj.Q); % value, action 
      % Choose a random action: 
      else      
       a = randi(obj.na); % random integer based on a uniform 
      end      % distribution 
     end 

     %% Find the features for the exact basis functions: 
     function phi = basis_exact(obj,action) 
      %Initialize the features: 
      phi = zeros(obj.nbasis,1); 

      % Find the current discrete state: 
      s = discretizeState(obj.state); 

      % Find the starting position of the block: 
      base = (action-1) * obj.ns; 

      % Set the indicator: 
      phi(base+s) = 1; 
     end 

     %% Find the features for the radial basis functions: 
     function phi = basis_rbf(obj, action) 
      %Initialize the features: 
      phi = zeros(obj.nbasis,1); 

      % Find the starting position: 
      base = (action-1) * (obj.nbasis/obj.na); 
      % This is because the matrix Theta is converted into a line 
      % vector 

      % Compute the RBFs: 
      for i=1:obj.nrbf 
       phi(base+i) = exp(-norm(obj.state-obj.centres(i,:))^2/... 
        (2*obj.mu)); 
      end 
      % ... and the constant: 
      phi(base+obj.nrbf+1) = 1; 
     end 
    end 
end 
+0

MATLABコマンドプロンプトで 'sfundemos'と入力してください。あなたは良い例を閲覧することができます。また、 'msfuntmpl'と' msfuntmpl_basic'というコメントを持つテンプレートもあります。これらの2つを入力し、Ctrl + Dキーを押します。 一般に、レベル2のMATLAB-S-FunctionですべてのMATLABオブジェクトを使用できます。ソースファイルがMATLABパス上にあることを確認してください。 –

+0

ありがとうございました!したがって、メインファイルとMatlab S関数で同じMATLABオブジェクトを使用したい場合、パラメータとしてインポートする必要はありませんか? –

+0

これは難しいところですが、私はもはや分かりません。変数を 'global'として宣言したり、S-Functionの中で' obj = evalin( 'base'、 'OBJ') 'を使ってベースワークスペースからオブジェクトを取り出し、それを使って' assignin( 'base' 'OBJ'、obj) '。私はこれがあなたのMATLAB-Scriptを持っていて、あなたのSimulink-Modelがメモリ内の同じオブジェクトを参照するのに十分なのかどうか分かりません。それを試してみてください!... –

答えて

0

[OK]を、いくつかの試行の後、私は最善の方法は、グローバルのようにオブジェクトを設定するには、グローバル変数、すなわちを使用することが実際にあることをついに発見しましたメインのMatlabスクリプトとレベル2のS-functionの両方です。

ここでは、簡単な例を見つけることができます。これは、仕事の一日を節約するのに役立ちます。

Test.mクラス:

classdef Test 
    properties 
     a; 
     b; 
    end 

    methods 
     function obj = Test(a,b) 
      obj.a = a; 
      obj.b = b; 
     end 

     function obj = change_a(obj,c) 
      obj.a = obj.a + c; 
     end 

     function c = get_c(obj) 
      c = obj.a*obj.b; 
     end 
    end 
end 

メインMATLABスクリプト - trial.m

clear; 
close all; 

global test; 

test = Test(0,1); 

% Simulink file: 
sfile = 't1'; 
% Load the Simulink file: 
load_system(sfile); 

% Run the simulation: 
sout = sim(sfile,'StopTime','5.0'); 

% Plot data: 
t = sout.tout; 
c = sout.get('logsout').getElement('c').Values.Data; 
figure; 
plot(t,c); 

t1.slx Simulinkのファイル: <code>t1.slx</code> Simulink file test_class.mレベル2 MatlabのS-機能:

function test_class(block) 
% rl_control.m  [email protected]  23/10/2017 
    setup(block); 
end 

%% Set up the block: 
function setup(block) 
% % Register number of dialog parameters: 
% block.NumDialogPrms = 3; 

    % Register number of input and output ports: 
    block.NumInputPorts = 1; 
    block.NumOutputPorts = 1; 

    % Set up functional port properties to dynamically inherited: 
    block.SetPreCompInpPortInfoToDynamic; 
    block.SetPreCompOutPortInfoToDynamic; 

    % Set up the input ports: 
    block.InputPort(1).Dimensions  = 1;   
    block.InputPort(1).DirectFeedthrough = true; 

    % Set up the output port: 
    block.OutputPort(1).Dimensions  = 1;   

    % Set block sample time to continuous: 
    block.SampleTimes = [0 0]; 

%  % Setup Dwork: 
%  block.NumContStates = 1; 

    % Set the block simStateCompliance to default: 
    block.SimStateCompliance = 'DefaultSimState'; 

    % Register methods: 
%  block.RegBlockMethod('InitializeConditions', @InitConditions); 
    block.RegBlockMethod('Outputs',     @Output); 
%  block.RegBlockMethod('Derivatives',    @Derivative); 
end 

% %% Initial conditions: 
% function InitConditions(block) 
%  % Initialize Dwork: 
%  block.ContStates.Data = block.DialogPrm(3).Data; 
% end 

%% Set up the output: 
function Output(block) 
    global test; 
    test = test.change_a(block.InputPort(1).Data); 
    c = test.get_c(); 
    block.OutputPort(1).Data = c; 
end 

私はそれをテストし、それが動作することを確認しました。グローバル変数を使用すると、同じオブジェクトを使用して、私が望むように変更することができます。