Troubleshoot with implementing matlab.system from when inheriting from superclass - matlab

I'm trying to implement a matlab class into a simulink MATLABSystem. When I implement superclass, the simulation works fine, but using the subclass I get the following error:
"Simulink cannot automatically infer the output signal properties of 'subclassSystem'. Simulink uses code generation technology to automatically determine the output signal properties from the System object. The System object 'subclass' contains code that does not support code generation.
The error is
'Undefined function or variable 'obj'. The first assignment to a local variable determines its class.'
The error occurred for MATLAB System block 'subclassSystem'. See line 29, column 28 in file 'superclass.m'. The error was detected during size propagation phase."
I commented this line in the code below
Do I have to specify something additional?
Here the subclass definition:
classdef subclass < superclass
properties(Access = protected) % These variables must be initialised. Here or in the setupImpl function
end
methods (Access=protected)
function resetImpl(obj)
end
%% Common functions
function setupImpl(obj)
% Perform one-time calculations, such as computing constants
setupImpl#superclass();
%obj.initFilter(obj.sampleTime, obj.delta_i, obj.delta_d, obj.g_mps2, obj.q0, obj.b_w0, obj.sigma_2_w, obj.sigma_2_a, obj.sigma_2_b_w, obj.sigma_2_yaw)
end
function attitude = stepImpl(obj,u, y)
% Implement algorithm.
attitude = 5;
end
end
methods
% Constructor must be empty for matlab.System. In Matlab call
% initFilter after the object was created. In simulink setupImpl()
% will be called
function obj = subclass()
obj#superclass();
end
end
end
Here the superclass definition:
classdef superclass < matlab.System
% These variables must be initialized in the simulink model
properties
sigma_2_w;
sigma_2_a;
sigma_2_b_w;
sigma_2_yaw;
end
properties(Access = protected) % These variables must be initialised. Here or in the setupImpl function
R;
Q;
end
methods (Access = protected)
function resetImpl(obj)
end
%% Common functions
function setupImpl(obj)
% Perform one-time calculations, such as computing constants
obj.Q = diag([obj.sigma_2_w',obj.sigma_2_b_w']); % this is line 29
obj.R = diag([obj.sigma_2_a',obj.sigma_2_yaw']);
end
function attitude = stepImpl(obj,u, y)
% Implement algorithm.
attitude = 5;
end
end
methods
% Constructor must be empty for matlab.System. In Matlab call
% initFilter after the object was created. In simulink setupImpl()
% will be called
function obj = superclass()
% Support name-value pair arguments when constructing object
end
end
end

I found the error. In the setupImpl function of the subclass I had to call setupImpl of the superclass with the obj as argument:
setupImpl#Superclass(obj);
This is my constructor. Here I didn't use the obj as return value
function obj = Subclass()
obj = obj#Superclass();
end

Related

Subclass constructor refuses to accept any name-value arguments

TL;DR
I am having an issue with the arguments functionality, wherein a subclass fails to instantiate if any name-value argument pairs are passed to it.
(Class definitions are given at the end.)
The arguments functionality, introduced in R2019b, brings great promise in terms of simplifying argument validation and removing boilerplate code from functions [1]. However, upon trying to implement name-value (NV) arguments taken from public class properties, I got the following error:
Invalid argument list. Check for wrong number of positional arguments or placement of positional arguments after
name-value pairs. Also, check for name-value pairs with invalid names or not specified in pairs.
before any subclass code is even executed. This message is confusing, because tab-completion appears to work as expected for NV pairs:
Moreover, if no arguments are passed at all, everything works fine:
>> FluidLayer()
ans =
FluidLayer with properties:
prop1: NaN
prop2: NaN
vs.
>> FluidLayer('prop1',1)
Error using FluidLayer
Invalid argument list. ...
Questions:
Why am I getting an error? I don't think I'm using the arguments mechanism in some unintended or undocumented way, so I'm doubly puzzled about what I might be doing wrong (assuming this is not a bug).
What can be done to resolve this, other than abandoning the whole arguments approach (I would like to keep argument name suggestions)? I have considered transitioning to varargin and/or using the functionSignatures.json approach - but these require significantly more work.
classdef Layer < handle & matlab.mixin.Heterogeneous
properties (GetAccess = public, SetAccess = protected)
prop1(1,1) double {mustBeNonempty} = NaN
prop2(1,1) double {mustBeNonempty} = NaN
end % properties
methods (Access = protected)
function layerObj = Layer(props)
% A protected/private constructor means this class cannot be instantiated
% externally, but only through a subclass.
arguments
props.?Layer
end
% Copy field contents into object properties
fn = fieldnames(props);
for idxF = 1:numel(fn)
layerObj.(fn{idxF}) = props.(fn{idxF});
end
end % constructor
end % methods
end
classdef FluidLayer < Layer
properties (GetAccess = public, SetAccess = protected)
% Subclass-specific properties
end % properties
methods
function layerObj = FluidLayer(props)
arguments
props.?FluidLayer
end
% Create superclass:
propsKV = namedargs2cell(props);
layerObj = layerObj#Layer(propsKV{:});
% Custom modifications:
end % constructor
end % methods
end
I have been able to simplify your example to this:
classdef Layer
properties (GetAccess = public, SetAccess = protected)
prop1
prop2
end % properties
methods
function layerObj = Layer(props)
arguments
props.?Layer
end
disp(props)
end % constructor
end % methods
end
Now Layer('prop1',1) throws an error as you describe.
Thus, it has nothing to do with subclassing or inheritance.
However, if we remove the SetAccess = protected restriction (leaving the properties with public get and set access), then it all works as you expected.
I don't know why restricting set access would limit this use case, as it has nothing to do with writing those properties, and a class method should have set access anyway. My guess is that this is a bug.
The documentation of R2020a states that the structName.?ClassName syntax can only be used with "settable properties defined by a class (that is, all properties with public SetAccess)". Thus, using it with protected properties is explicitly unsupported.
As such, if we want to use the "automatic" arguments validation mechanism, we have no choice but to set the SetAccess to public. However, this solution exposes the object properties to unwanted external changes, and so a workaround is suggested based on several principles:
properties now have public SetAccess, as required by the documentation.
Custom setters are added that perform access validation based on dbstack and meta.class comparison.
New Layer.m (notice the 2 new methods blocks):
classdef Layer < handle & matlab.mixin.Heterogeneous
properties (GetAccess = public, SetAccess = public)
prop1(1,1) double {mustBeNonempty} = NaN
prop2(1,1) double {mustBeNonempty} = NaN
end % properties
%% Constructor
methods (Access = protected)
function layerObj = Layer(props)
% A protected/private constructor means this class cannot be instantiated
% externally, but only through a subclass.
arguments
props.?Layer
end
% Copy field contents into object properties
fn = fieldnames(props);
for idxF = 1:numel(fn)
layerObj.(fn{idxF}) = props.(fn{idxF});
end
end % constructor
end % protected methods
%% Setters & Getters
methods
function set.prop1(obj, val)
if Layer.getCallerMetaclass() <= ?Layer
obj.prop1 = val;
else
Layer.throwUnprotectedAccess();
end
end
function set.prop2(obj, val)
if Layer.getCallerMetaclass() <= ?Layer
obj.prop2 = val;
else
Layer.throwUnprotectedAccess();
end
end
end % no-attribute methods
%% Pseudo-protected implementation
methods (Access = protected, Static = true)
function throwUnprotectedAccess()
stack = dbstack(1);
[~,setterName,~] = fileparts(stack(1).name);
throw(MException('Layer:unprotectedPropertyAccess',...
['Unable to set "', stack(1).name(numel(setterName)+2:end),...
'", as it is a protected property!']));
end
function mc = getCallerMetaclass()
stack = dbstack(2, '-completenames');
if isempty(stack)
mc = ?meta.class;
else
[~,className,~] = fileparts(stack(1).file);
mc = meta.class.fromName(className);
end
end
end % protected static methods
end % classdef
New FluidLayer.m (the foo method was added):
classdef FluidLayer < Layer
properties (GetAccess = public, SetAccess = protected)
% Subclass-specific properties
end % properties
methods
%% Constructor
function layerObj = FluidLayer(props)
arguments
props.?Layer
end
% Create superclass:
propsKV = namedargs2cell(props);
layerObj = layerObj#Layer(propsKV{:});
end % constructor
function obj = foo(obj)
obj.prop1 = obj.prop1 + 1;
end
end % methods
end % classdef
Here's a demonstration of how it works:
>> fl = FluidLayer('prop1', 2, 'prop2', 1)
fl =
FluidLayer with properties:
prop1: 2
prop2: 1
>> fl.prop1 = 5; % attempting to set property directly (unintended)
Error using Layer/throwUnprotectedAccess (line 51)
Unable to set "prop1", as it is a protected property!
Error in Layer/set.prop1 (line 32)
Layer.throwUnprotectedAccess();
>> fl.foo() % attempting to set property through method (intended)
ans =
FluidLayer with properties:
prop1: 3
prop2: 1
>>
In conclusion: it is possible to overcome the SetAccess = public limitation using setter methods, but convoluted modifications to class code are required.
Practical Notes:
The getCallerMetaclass is limited in that it doesn't correctly identify packages - resulting in potentially empty metaclass objects. So keep in mind that this function should be modified if that is the case.
dbstack is called multiple times, although it is not necessary (it can be called once in the setter and the result can then be passed around).
The setter code for different properties is 5-lines long and mostly replicated (with the exception of the property name) - this can be improved by grabbing the property name through dbstack.

Matlab class dynamic filling of a property

I'm trying to dynamically fill a property in a Matlab class.
I pass vectors to a method function and then compute various parameters. I would like to fill the properties in a for loop, see code example. The OwnClassFunction is just an example of a further function in the class, but is not implemented in the code example. How can I do this correctly?
classdef Sicherung < handle
properties
x = ([],1)
end
methods
function examplefunction(object,...
single_parameter_vector) % (n,1) n can be any size
for i=1:length(param_vector)
[object.x(i,1)] = object.OwnClassFunction(single_parameter_vector(i,1));
end
end
end
end
If i try something like that
...
properties
x = []
end
...
function ...(object,parameter)
for i=1:length(parameter)
[object.x(i)] = function(parameter(i));
end
I get the error message Subscripted assignment dimension mismatch.
I don’t have MATLAB in hand to test, but the following should work.
Your code is pretty close to a correctly functioning method. Change it as follows:
classdef Sicherung < handle
properties
x = [] % initialize to empty array
end
methods
function examplefunction(object,param_vector)
if ~isvector(param_vector)
error('vector expected') % check input
end
n = numel(param_vector)
object.x = zeros(n,1); % preallocate
for i=1:n
object.x(i) = object.OwnClassFunction(param_vector(i));
end
end
end
end

MATLAB: Conditionally define get/set class methods

I have created some MATLAB classes to do some error-checking when I use certain types of structures. This improve development time by preventing errors in the code, but significantly slow down execution time.
One way to get around this is to comment out the set methods inside the class. Is it possible to do this programmatically? For example, only define these methods if a parameter in the constructor is true.
classdef MWE
%MWE Minimum working example
properties
A
B
C
end
methods
function obj = MWE(A, B, C)
if nargin ~= 3
error('A, B and C must all be provided.');
end
obj.A = A;
obj.B = B;
obj.C = C;
end
% function obj = set.A(obj, value)
% validate(obj, value, 'A');
% obj.A = value;
% end
%
% function obj = set.B(obj, value)
% validate(obj, value, 'B');
% obj.B = value;
% end
%
% function obj = set.C(obj, value)
% validate(obj, value, 'C');
% obj.C = value;
% end
end
methods (Access = private)
function validate(obj, value, name)
% Code here
end
end
end
Is it possible to do this programmatically? For example, only define these methods if a parameter in the constructor is true.
After some discussion, I see there are different ways of looking at your question. And, indeed, it may be that you cannot do what you are asking as interpreted by some. Here are two cases, however, that may suffice.
Case 1
You have computationally intensive or otherwise time consuming methods, that you use to "do some error-checking", in a development setting, but want to turn off in a production environment. And, these checks occur when the class is instantiated.
Place these methods in a wrapper function that is called from the constructor.
Here's an example
classdef classFoo
properties(Access=private)
fbar;
end
methods
function this = classFoo(arg1, argN, debugMode)
if(nargin>2 && debugMode)
if(~this.verifyStuff(arg1, argN))
throw(MException('classFoo:ConstructFailure','Could not verify'));
else
this.fbar = timeConsumingFunction();
end
else
this.fbar = 42; % defaultValue;
end
% continue construction
end
function didVerify = verifyStuff(this, varargin)
% complex code
didVerify = randi(2)-1; % 50/50
end
end
end
Then when creating objects you can choose to pass the debug mode flag as true like this:
a=classFoo(1,2,true)
or as false, like this:
a=classFoo(1,2,false)
or not at all, which is the same as the false case, like this:
a=classFoo(1,2)
Case 2
You have two different versions of a get/set method that you are commenting out depending on your development environment.
Add a private member parameter (e.g. isDebugging) and set it at time of construction. Now, instead of commenting out code in your get and set methods, you can handle the different cases with a simple if/else, predicated on your debug state like this:
classdef classFoo
properties(Access=private)
fbar;
isDebugging;
end
methods
function this = classFoo(debugMode)
if(nargin<1 || ~islogical(debugMode))
debugMode = false;
end
this.isDebugging = debugMode;
end
function setfbar(this, fIn)
if(this.isDebugging)
this.fbar = timeConsumingFunction(fIn);
else
this.fbar = fIn; % defaultValue;
end
end
end
end

Call subclass static method from inside superclass static method

I have a large set of small, related classes linked together by an interface class. All classes implement a static method, which retrieves and processes data specific to the class.
The output of that static method needs to be formatted in at least 2 ways. Since the transformation of one format to the other is always the same and rather trivial (though long), I thought I'd implement it as a concrete, sealed, static method in the superclass.
However, then I run into the following problem:
% (in Superclass.m)
classdef SuperClass < handle
methods (Static, Abstract)
[arg1, arg2] = subsStaticMethod;
end
methods (Sealed, Static)
function [other_arg1, other_arg2] = supersStaticMethod
% Get data here
[arg1, arg2] = (???).subsStaticMethod
% transform data here
% ...
end
end
end
% (in Subclass.m)
classdef SubClass < SuperClass
methods (Static)
function [arg1, arg2] = subsStaticMethod
% Get class-specific data here
% ...
end
end
end
As far as I can see, calling SubClass.supersStaticMethod() is impossible with this design, because static methods need to be called using the class name explicitly. In other words, there is no way to insert the subclass name instead of the (???) in SuperClass.supersStaticMethod above.
Things I've tried:
mfilename('class') this doesn't work, because this always returns 'SuperClass'
dbstack does not contain the information that the method is actually being called from a subclass
I know that I can work around this problem by making supersStaticMethod non-static, and calling the method on a temporary instance (like SubClass().supersStaticMethod()). Or create a small wrapper method inside each subclass that just calls the superclass method with mfilename('class') as argument. Or any of a 100 other things that seem equally clumsy.
But I'd really like to know if there is some meta.class trickery or something that can cleanly solve this problem. All I've found is this dated thread, which processes the MATLAB command line programmatically to get the subclass name.
However, my classes are to be used inside scripts/functions, and command line use is going to be for debugging purposes only...
Any ideas?
Below's my hacky proposal. The idea is that you store the current calling class in a "static variable" of SuperClass, then query this field and use it in feval to call the correct subclass' method. Several notes:
It could only work as long as you're not doing some computations in parallel (i.e. calling SubClass#.supersStaticMethod from more than one thread at a time under a shared memory architecture - in which case the calling class field will be overwritten erratically).
SuperClass's supersStaticMethod cannot be Sealed, though the subclasses' versions can.
The "static variable" is cleared after SubClass.supersStaticMethod to ensure that this method is only ever called from a subclass.
I've added matlab.mixin.Heterogeneous as superclass of SuperClass for the purpose of demonstration.
classdef SuperClass < handle & matlab.mixin.Heterogeneous
properties (Abstract = true, Access = private, Constant = true)
subclass#meta.class scalar;
end
methods (Static, Abstract)
[arg1, arg2] = subsStaticMethod;
end
methods (Sealed, Static)
function out = currentClass(input) % < the closest thing in MATLAB to a static variable
persistent currentClass;
if nargout == 0 && nargin == 1 % "setter" mode
currentClass = input;
out = [];
else % "getter" mode
out = currentClass;
end
end
end
methods (Static)
function [other_arg1, other_arg2] = supersStaticMethod
% Who am I?
whosCalling = SuperClass.currentClass();
if isempty(whosCalling) || ~isa(whosCalling,'meta.class')
[other_arg1,other_arg2] = deal(NaN);
return
else
whosCalling = whosCalling.Name;
end
fprintf(1,'\nCalled from: %s\n', whosCalling);
% Get data here
[arg1, arg2] = feval([whosCalling '.subsStaticMethod']);
% transform data here
other_arg1 = arg1+arg2; other_arg2=[arg1(:);arg2(:)];
fprintf(1,'other_arg1: %s, other_arg2: %s\n',...
num2str(other_arg1), mat2str(other_arg2));
% Clear the current class
SuperClass.currentClass([]);
end
end
end
classdef SubClass1 < SuperClass
properties (Constant)
subclass#meta.class scalar = ?SubClass1;
end
methods (Static)
function [other_arg1, other_arg2] = supersStaticMethod
SubClass1.currentClass(SubClass1.subclass);
[other_arg1, other_arg2] = supersStaticMethod#SuperClass;
end
function [arg1, arg2] = subsStaticMethod
arg1 = -1; arg2 = -2;
end
end % static methods
end % classdef
classdef SubClass2 < SuperClass
properties (Constant)
subclass#meta.class scalar = ?SubClass2;
end
methods (Static)
function [other_arg1, other_arg2] = supersStaticMethod
SubClass1.currentClass(SubClass2.subclass);
[other_arg1, other_arg2] = supersStaticMethod#SuperClass;
end
function [arg1, arg2] = subsStaticMethod
arg1 = 1; arg2 = 2;
end
end % static methods
end % classdef
Then you can test it like this:
function q31269260
arr = [SubClass1, SubClass2];
for ind1 = 1:numel(arr)
arr(ind1).supersStaticMethod;
end
% arr.supersStaticMethod would not work because elements are treated as "instances" of
% SuperClass, whose supersStaticMethod should not be called directly.
The output is:
Called from: SubClass1
other_arg1: -3, other_arg2: [-1;-2]
Called from: SubClass2
other_arg1: 3, other_arg2: [1;2]

How to access variables in the properties block of a Matlab System Object?

I am working on a simple System Object in Matlab/Simulink.
It looks like this :
classdef realtime_header_detectorSO < matlab.System & matlab.system.mixin.Propagates
% correlateHeader
%
% This template includes the minimum set of functions required
% to define a System object with discrete state.
properties
Header
%nrOfBitsInPreviousStep=0;
s=100;
d=zeros(1,s);
end
properties (DiscreteState)
end
properties (Access = private)
max_nr_of_packets=20;
max_packet_length_in_bytes=300;
current_packet=1;
% Pre-computed constants.
% h = commsrc.pn('GenPoly', [9 5 0],'NumBitsOut', 8,'InitialStates',ones(1,9));
% data=logical(zeros(max_nr_of_packets,max_packet_length_in_bytes*8));
end
methods (Access = protected)
function setupImpl(obj,u)
% Implement tasks that need to be performed only once,
% such as pre-computed constants.
end
function [maxCorr]= stepImpl(obj,u)
eml.extrinsic('num2str');
coder.extrinsic('sprintf');
% Implement algorithm. Calculate y as a function of
% input u and discrete states.
%y = size(u,1);
symbols=sign(u);
c=abs(conv(flipud(obj.Header),[symbols; symbols]));
maxCorr=max(c);
% maxCorr
if(maxCorr==36)
idx36=find(c(1:size(symbols,1))==36);
disp('header(s) detected at the following location(s) in bytes:');
disp(sprintf('%15.4f \n',idx36/8));
nrOfSymbols=size(symbols,1);
disp(['out of nr. of total symbols: ' num2str(nrOfSymbols)]);
disp('------');
% maxCorr
end
% y=obj.pBufferIdx;
end
function resetImpl(obj)
% Initialize discrete-state properties.
end
function varargout = isOutputFixedSizeImpl(~)
varargout = {true};
end
function varargout = getOutputSizeImpl(obj)
varargout = {[1 1]};
end
end
end
However when I compile/run it I get the following error:
The System object name 'realtime_header_detectorSO' specified in MATLAB System block 'freqScanningRT/Sync and
Find Header/detect header' is invalid.
Caused by:
Undefined function or variable 's'.
However (!) the following code compiles and runs just fine :
classdef realtime_header_detectorSO < matlab.System & matlab.system.mixin.Propagates
% correlateHeader
%
% This template includes the minimum set of functions required
% to define a System object with discrete state.
properties
Header
%nrOfBitsInPreviousStep=0;
s=100;
% d=zeros(1,s);
end
properties (DiscreteState)
end
properties (Access = private)
max_nr_of_packets=20;
max_packet_length_in_bytes=300;
current_packet=1;
% Pre-computed constants.
% h = commsrc.pn('GenPoly', [9 5 0],'NumBitsOut', 8,'InitialStates',ones(1,9));
% data=logical(zeros(max_nr_of_packets,max_packet_length_in_bytes*8));
end
methods (Access = protected)
function setupImpl(obj,u)
% Implement tasks that need to be performed only once,
% such as pre-computed constants.
end
function [maxCorr]= stepImpl(obj,u)
eml.extrinsic('num2str');
coder.extrinsic('sprintf');
% Implement algorithm. Calculate y as a function of
% input u and discrete states.
%y = size(u,1);
disp(obj.s);
symbols=sign(u);
c=abs(conv(flipud(obj.Header),[symbols; symbols]));
maxCorr=max(c);
% maxCorr
if(maxCorr==36)
idx36=find(c(1:size(symbols,1))==36);
disp('header(s) detected at the following location(s) in bytes:');
disp(sprintf('%15.4f \n',idx36/8));
nrOfSymbols=size(symbols,1);
disp(['out of nr. of total symbols: ' num2str(nrOfSymbols)]);
disp('------');
% maxCorr
end
% y=obj.pBufferIdx;
end
function resetImpl(obj)
% Initialize discrete-state properties.
end
function varargout = isOutputFixedSizeImpl(~)
varargout = {true};
end
function varargout = getOutputSizeImpl(obj)
varargout = {[1 1]};
end
end
end
So I can access s in the stepImpl(obj,u) as obj.s but I cannot access s inside the properties block, where it is defined !
Now this is confusing.
Is there way to access s inside the properties block ?
The problem is that I have to use the properties block because if I try this :
function setupImpl(obj,u)
% Implement tasks that need to be performed only once,
% such as pre-computed constants.
d=zeros(1,obj.s);
end
then I get :
Error due to multiple causes.
Caused by:
Problem creating simulation target MEX-file for model 'freqScanningRT'.
Simulink detected an error
'Computed maximum size is not bounded.
Static memory allocation requires all sizes to be bounded.
The computed size is [1 x :?].'.
The error occurred for MATLAB System block 'freqScanningRT/Sync and Find Header/detect header'. See line
34, column 15 in file
'path/realtime_header_detectorSO.m'.
The error was detected during code generation phase.
Start code generation report.
To prevent this error, use one of the following:
* Modify the System object to avoid code that does not support code generation.
* Change 'Simulate using' parameter to 'Interpreted Execution'.
Any idea how to refer to variables in the properties blocks ?
There must be a way to do this.
You should be able to use
properties
s = 100;
d = zeros(1,100);
end
right? If you already have the 100 as a default for s, you should also be able to provide this as part of the default for d.
I'm guessing that you're trying to avoid doing that because you feel uncomfortable repeating the "100". But I'd also guess that really, "100" is some sort of magic number that your system depends on; so really, you should try to pull it out as a constant in any case, whether it's repeated or not.
So in that case, you might improve things with
properties (Constant)
MYCONSTANT = 100;
end
properties
% Reference Constant class properties with the class name
s = realtime_header_detectorSO.MYCONSTANT;
d = zeros(1, realtime_header_detectorSO.MYCONSTANT);
end
You're not going to be able to do what you're originally trying to do - it's not possible to reference the name of one property within the property definition block when defining another property (even though you can perfectly well reference it within a method). I guess I understand why you find that confusing - but to clear up your confusion, note that you have no guarantee over the order in which MATLAB instantiates default values for properties. If it tried to create d before it had created s, it would obviously fail.
You can avoid this problem all together by initializing the properties in the constructor.