我想知道是否可以在 Simulink 的 Matlab Level-2 S-Function 中导入对象。
过去,我在 Matlab 中将强化学习应用于动态模型。因此,我创建了一些处理策略生成和更新的类。现在,我需要迁移到 Simulink,因为我有一个更复杂的动态系统。我熟悉 C S-Function,但因为我已经在两个类中拥有 Matlab 代码,所以我正在考虑使用使用这些对象的 Matlab S-Function。
我的工作流程如下:初始化策略对象的主要Matlab函数调用带有动态模型的Simulink文件。在 S-Function 中,策略对象被调用来选择一个动作(它是控制系统的输出)。在对 Simulink 文件进行多次模拟后,策略对象(实际上是其权重)会在 Matlab 主函数中更新。
所以,我需要一种policy
在 Simulink 的 Matlab S-Function 中导入对象的方法。我试图将其作为参数导入,但只接受数值。我不能只将对象保留在 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