我想知道是否可以在Simulink中的Matlab Level-2 S函数中导入对象。
过去,我在Matlab中将强化学习应用于动态模型。结果,我创建了一些处理策略生成和更新的类。现在,我需要转移到Simulink,因为我有一个更复杂的动态系统。我熟悉C S函数,但因为我已经在两个类中使用了Matlab代码,所以我正在考虑使用使用这些对象的Matlab S函数。
我的工作流程如下:初始化策略对象的主要Matlab函数使用动态模型调用Simulink文件。在S函数中,策略对象被调用以选择动作(这是控制系统的输出)。然后,在对Simulink文件进行多次模拟之后,在主Matlab函数中更新策略对象(实际上是其权重)。
所以,我需要的是一种在Simulink中的Matlab S函数中导入policy
对象的方法。我试图将其作为参数导入,但只接受数值。我不能只在S函数中保留对象(因此,在初始化函数中初始化它)因为我需要在主Matlab脚本中更新它的权重。
这可能吗?任何建议将不胜感激!
政策类的一个例子如下:
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 :(得分:0)
好的,经过一些试验,我终于发现最好的方法是使用全局变量,即在主Matlab脚本和Level 2 S函数中将对象设置为全局。
在这里你可以找到一个简单的例子,我希望它可以帮助你节省一天的工作。
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文件:
test_class.m level 2 Matlab S-function:
function test_class(block)
% rl_control.m e.anderlini@ucl.ac.uk 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
我测试了它并检查它是否有效。全局变量允许我使用相同的对象并根据需要进行更改。