%% Unifying MATLAB and Simulink: A User Story Part 3
% In today's post, I will add features to the framework presented in the previous post to help controlling variants.
% If you missed the previous posts in this series, here are links to all posts:
% Unifying MATLAB and Simulink: A User Story Part 1: Parameterizing a model with MATLAB objects
% Unifying MATLAB and Simulink: A User Story Part 2: The slPart class, block template and data variants
% Unifying MATLAB and Simulink: A User Story Part 3: Controlling variants with MATLAB objects
% Unifying MATLAB and Simulink: A User Story Part 4: Post-processing and visualizing logged data
% Unifying MATLAB and Simulink: A User Story Part 5: Larger examples
%% Variant slPart Block
% To handle variants, I added a second template block to the library where I had previously stored the slPart template block. This second template is a Variant Subsystem with the same mask and same mask initialization callback as described in my previous post:
%
% In the block dialog, I set the Variant Control Mode to Label.
%
% Using label mode will allow us in the next step to change the active variant based on the class of the slPart object specified in the mask parameter.
% When I will copy this block to models, I will be able to add to it as many algorithm variants as I want.
%% Adding Variant Specification to slPart
% The goal here is to select the active variant based on the class of the object, which is specified as a mask parameter. For that, I add the following code to the maskInit method of slPart:
% classdef slPart < handle
%     properties (Hidden = true)
%         BlockPath char
%     end
%     methods
%         function obj = maskInit(obj,blk)
%             obj.BlockPath = blk;
%             % If the block has variants, set active variant based on the object class
%             if strcmp(get_param(blk,'Variant'),'on')
%                 variantChoices = get_param(blk,'VariantChoices');  % Get all variant choices
%                 variantChoices = {variantChoices.Name}';           % Extract the labels
%                 classList = [class(obj);superclasses(obj)];        % Get the list of class and superclasses
%                 matchingChoices = intersect(classList,variantChoices); % Find the label that matches the class or closest superclass
%                 set_param(blk,'LabelModeActiveChoice',matchingChoices{1}); % Apply the first match
%             end
%         end
%     end
% end
% This code will compare the variant control labels of each variant and find the one that matches the class of the object or its closest superclass. At the end, it uses set_param to activate the chosen variant based on its label (More on that below).
%% Implementing a Variant slPart
% Let's keep building on the spring example from the previous post. I add my template block to a model and create two variants, one is the same linear spring as in the previous example, and the other is a non-linear version:
%
% I create a new slPart class for the non-linear version and save it in the +springLib package created in the previous post. From now on, I will refer to this class as springLib.springNonLinear:
% classdef springNonLinear < slPart
%     properties
%         m
%         displacementBreakPoints;
%         stiffnessTable;
%         velocityBreakPoints;
%         dampingTable;
%     end
%     methods
%         function obj = springNonLinear()
%             obj.m = 1;
%             obj.displacementBreakPoints = -5:5;
%             obj.stiffnessTable = tanh(-5:5);
%             obj.velocityBreakPoints = -5:5;
%             obj.dampingTable = 2*tanh(-5:5);
%         end
%     end
% end
% Now, the key thing for the mask initialization method to be able to set the proper variant is to set the label of each variant to the name of corresponding class.
%
% One thing I want to point out here is that it would be possible to obtain a similar variant activation logic using expression mode instead of label mode. The main difference in my opinion is that, by using label mode controlled by the mask initialization method defined in the slPart superclass, the complexity is managed in a single place: in the slPart superclass. While expression mode offers more possibilities, for example different activation times, it puts the complexity on writing down the condition expression on each user adding a new variant.
%% More Variant Parameterizations
% Once the Variant Subsystem has been configured, as described in post 2 of this series, I can optionally create variant parameterizations for the newly created non-linear spring:
%
% With those saved in the +springLib package folder, I now have doubled the size of my library of springs, which I can still access through tab-completion:
%
%% Selecting a Part and Simulating the Corresponding Variant
% Once the model is properly configured and the MATLAB classes have been created, I can assign an object of the desired type to the variable specified in the block mask dialog and Simulink will automatically use the appropriate variant subsystem during simulation.
%
% I like the fact that, if I give this model to someone, all that person needs to do is to pick a spring from the springLib package. No need to know or care about the fact that it might be activating a different variant subsystem under the hood.
% That way, you inherit a component where the inner mechanics have been abstracted so you can focus on using it and not be distracted by implementation details.
%% Now it's your turn
% Obviously, what I showed here is the bare minimum to get this technique working. For a realistic project, I would add validation code and error checking to better guide the user in case something goes wrong.
% If you want to analyze this project in more detail, you can download the current version here.
% What do you think of this approach to variants? Did you or your company came up with other ways to systematically control variants? I would be interested to hear how the usability compares with what I described in this post.
% Let us know in the comments below.