Plugin: MATLAB Code (GInsMatlabPlugin)

The GInsMatlabPlugin is a custom controller plugin where the functionality can be written in MATLAB or Simulink.

In ⚠️❗⚠️ PRELIMINARY - NOT PUBLISHED YET⚠️❗⚠️

Table of Contents:

  1. Introduction
  2. Requirements and Limitations
  3. Plugin Installation
  4. User Interface of the Matlab App

  5. Matlab Interface to GIns Plugin

  6. Plugin Configuration - Mapping of Variables
  7. Example

1. Introduction

With this plugin the following functions are available:

  • Data processing written with Matlab and executed in a Q.station
  • Create a custom plugin in a short time

2. Requirements and Limitations

The minimum system requirements for this plugin are:

Furthermore only MATLAB functions supported by C++ code generation can be used in this plugin. A list of all supported functions can be found here.


3. Plugin Installation

Installation of Matlab App

 No additional installation is required on the controller itself, instead a Matlab app is needed that contains the user interface. For this purpose navigate working directory of Matlab to the file "GIns Matlab Code Generation.mlappinstall" and double-click it. Afterwards follow the instructions to install the app.

Installation of Docker Container

⚠️ To be added... ⚠️


4. User Interface of the Matlab App

The user interface of the Matlab app is kept simple and consists of three main parts: General Information, Select Device and Code Generation.

In General Information are setup information set but mostly no changes are needed. The most important part here is the selection of the source folder or current working directory in Matlab.  If this folder is set wrong or the basic setup do not exist there, the code generation is not possible. In order to generate a default workspace use the button Generate Matlab Default Files or Generate Simulink Default Files.
For Simulink models the Calculation Rate must be set, which should be equalt ot CPU calculation rate of the used Q.station.

A minimal Matlab workspace consists of following files:

  • MatlabFunction_Build.m
  • MatlabFunction_GetInfo.m
  • MatlabFunction_Main.m

A Simulink workspace consists of:

  • GInsSimulinkMain.slx

In Select Device the target device is selected by clicking on the name. The list can be updated with the button Scan Devices.

The plugin is generated and built with the buttons in the lower section. This process of building the final plugin can be done partially (left buttons) or completely (right button).

MatlabPluginUI



5. Matlab Interface to GIns Plugin

The basis of the plugin consists of two Matlab files, which contain the desired functionality. MatlabFunction_GetInfo.m describes the inputs and outputs used and MatlabFunction_Main.m includes the actual logic. The file MatlabFunction_Build.m is needed for the code generation and does not require any changes.

In the case of Simulink the needed information are generated in the model GInsSimulinkMain.slx. In this model the number of inputs and outputs and their description is set.

A basic body for a GIns plugin is included in the used docker container. This template in combination with generated C/C++ files from Matlab are later used to compile the final plugin in the container. 

MatlabFunction_GetInfo.m

This file describes the interface between the plugin and Matlab. The three parameters inputs, outputs and debugs can be used to provide information such as the name, but for each variable used in the interface such a description must be given. The parameter Helptext is an optional description of the whole function.

The parameter inputs and outputs are exchanged periodically with the CPU clock of the Q.station but debugs only asynchronous using the XML-RPC interface.

The file itself consists of a needed predefined part and some possibilities for user input as shown in an exemplary file below.  As mentioned in Helptext, this function generates two different sinusoidal waveforms with a noise and a filtering.

The interface is defined in inputs (Timestamp, amplitude and frequency of two sinusoidal waveforms, noise amplitude and a offset),  outputs (Ideal signal, signal with noise and a filtered signal) and debugs (Current noise amplitude and two constants for debugging).

Only changes on the intended parts in the function are allowed! Otherwise the plugin cannot be executed properly. 

function [InputDesc, OutputDesc, numberInputs, numberOutputs, Helptext, DebugDesc, numberDebugs] = MatlabFunction_GetInfo(InputDesc, OutputDesc, DebugDesc)
%% This is the help for the matlab function
% It returns some helpful description of the inputs/outputs for the
% main functions. 

%% How to use
% Just modify the cell arrays inputs, outputs and Helptext

%% Params (don't change!)
% InputDesc: An array containing description for each input
% outputVector: An array containing description for each output
% Helptext: An additional Text for general information

% numberInputs: The number of inputs (=number of rows in InputDesc)
% numberOutputs: The number of outputs (=number of rows in OutputDesc)

%% User Inputs (Change according to your values)
    % Enter the description for each input/output
    inputs = {'Timestamp (ns)','Amplitude 1','Amplitude 2','Frequency 1','Frequency 2','Amplitude Noise', 'DC Offset'};
    outputs = {'Signal without Noise', 'Signal with Noise', 'Signal filtered'};
    debugs = {'Amplitude Noise', 'ConstValue 1', 'ConstValue 2'};

    Helptext = "This function generates two Sinus signals with an additional Noise. The Signal is then filtered using a lowpass filter.";

%% Processing (don't change!)
    MAX_VARIABLE_NAME_LENGTH = 150;     

    numberInputs = size(inputs,2);
    numberOutputs = size(outputs,2);
    numberDebugs = size(debugs,2);

    InputDesc = char(zeros(MAX_VARIABLE_NAME_LENGTH, numberInputs));
    OutputDesc = char(zeros(MAX_VARIABLE_NAME_LENGTH, numberOutputs));
    DebugDesc = char(zeros(MAX_VARIABLE_NAME_LENGTH, numberDebugs));
    
    % Fill in Names
    for idx = 1:numberInputs
        InputDesc(1:length(inputs{idx}),idx) = inputs{idx};
    end

    for idx = 1:numberOutputs
        OutputDesc(1:length(outputs{idx}),idx) = outputs{idx};
    end  

    for idx = 1:numberDebugs
        DebugDesc(1:length(debugs{idx}),idx) = debugs{idx};
    end 
end

MatlabFunction_Main.m

This file describes the desired logic of the plugin. It also consists of a predefined and a part for user input containing the logic.

The interface variables defined in MatlabFunction_GetInfo.m (inputs, outputs and debugs) are represented in the vectors inputVector, outputVector and debugVector with the order from the description.

An exemplary file is also shown below implementing the sinusoidal waveform generation. As seen there, custom functions (MyLowpassFilter.m) can also be used as long as they are supported in the code generation. 

Only changes on the intended parts in the function are allowed! Otherwise the plugin cannot be executed properly. 

Keep in Mind: Vectors in Matlab start with index 1.

function [returnCode, inputVector, outputVector, debugVector] = MatlabFunction_Main(inputVector, outputVector, debugVector)
%% This is the main matlab function
% This is a small example.

%% How to use
% Change the expected number of inputs/output (inputSize,
% outputSize). The custom logic can be added like the example seen below.

%% Params (don't change!)
% inputVector: A vector containing the input of this function. Passed as
% pointer

% outputVector: A vector containing the result of this function. Passed
% as points

% returncode: Some returncode to give information about success


%% Check if input/output size is big enough (don't change)
    [~, ~, inputSize, outputSize, ~, ~, debugSize] = MatlabFunction_GetInfo();

    if (max(size(inputVector)) ~= inputSize || min(size(inputVector)) ~= 1 || ...
            max(size(outputVector)) ~= outputSize || min(size(outputVector)) ~= 1)
        returnCode = -1;
        return;
    end


%% User Logic (Change according to your needs)
    % Inputs
    currentTime = inputVector(1);       % in ns
    currentTime = currentTime *10^-9;   % in s

    noiseAmplitude = inputVector(6);
    noise = rand*noiseAmplitude*2 - noiseAmplitude;

    dcOffset = inputVector(7);

    currentSignal = MySinus(currentTime, inputVector(2), inputVector(4)) + MySinus(currentTime, inputVector(3), inputVector(5)) + dcOffset;
    noiseSignal = currentSignal + noise;
    filteredSignal = MyLowpassFilter(noiseSignal);

    % Outputs
    outputVector(1) = currentSignal;
    outputVector(2) = noiseSignal;
    outputVector(3) = filteredSignal;

    debugVector(1) = noise;
    debugVector(2) = 1;
    debugVector(3) = 2;

    returnCode = 0;
end

GInsSimulinkMain.slx

In this file the model for Simulink code generation is described. On the left and right side the mapping is done and in the middle there is a placeholder for a model.

In the mapping blocks the number of descriptions and ports must be equal. The amount of Inputs and Outputs needs to be at least two to create a list.

MatlabPlugin_SimulinkMain


6. Plugin Configuration - Mapping of Variables

The configuration of a plugin is done through the Plugin Website or a plugin-specific configuration interface using GI.monitor.

  1. The Matlab plugin can read and write data to the controller's virtual variables. The controller virtual variables must be created first before configuring the plugin. The virtual variables should be configured as Setpoint.
  2. Use the Plugin Website to assign the Mapping of the variables.
    Website Address: <IP address of your Controller>:8090/<Plugin Name>/index.htm
  3. Start GI.monitor from the GI.bench menu in the system tray. To connect to the plugin, enter the Server Address (IP address of your controller), set the Server Port to 1200, and click Connect. If you do not know the IP address of your Q.series controller, use the Search button to find all controllers connected to your network.
  4. Next to the Route dropdown list click Reload and then select /GInsMatlabPlugin.
  5. Select ConfigureMapping under GInsMatlabPlugin/PluginAPI to add the mapping of the controller variables with the Matlab variables. Finally click Send to store the new plugin configuration on the controller.

The configuration of the plugin consists only of the variable mapping between the Plugin and Matlab (Configure). In addition, the current value of debug variables can be shown with GetCurrentDebugValues.


7. Example

Setup Project in GI.bench

  • Create Project and add a controller
  • Create virtual setpoint variables on the controller for each variable used in the plugin

Build Plugin

  • Open Matlab app
  • Generate default files
  • Set input/output/debug variables in MatlabFunction_GetInfo.m. At least one entry is needed in each category.
  • Implement functionality in MatlabFunction_Main.m.
  • In the Matlab app select desired Q.station and check working directory and path to websocket util.
  • Start process of code generation with the desired buttons. Afterwards the plugin should be installed in the Q.station.

Apply Variable Mapping

  • Connect to Q.station with GI.monitor and navigate to plugin.
  • Set variable mapping under Configure.

Show Results

  • Back in GI.bench add a YT-chart for example.
  • Drag the output variables into the chart.

 

8. Manual Installation

Introduction

This manual describes needed steps to manualy use the Plugin. This may be the case if docker cannot be used on windows for example.

Requirements

- PC with installed Matlab and GIns-app (for example Windows or linux) and internet connection.

- PC with installed docker (for example Linux) and internet connection.

- PC with installed GI.bench (Windows) to install plugin on device.

In this tutorial following setup was used:

- Main PC (Windows 10) with Matlab R2021b and GI.bench V1.14.4 installed.

- Build PC (Debian 10) with docker.

Build Docker Container

- Open `GIns Matlab Code Generation` app in Matlab and nvaigate to working directory

- Click button `Build Docker Container`. Now a subdirectory called *docker/* is generated and filled with a `dockerfile` and a `SDK` for compiling. (If needed replace SDK with matching version).

- Copy the directory to the system with installed docker. Make sure the SDK is marked as executable.

- Run build command  specified in `BuildContainer.bat` (`docker build -t gins_matlab_container .`).

Generate MATLAB Code


- In `GIns Matlab Code Generation` app generate default files and change functionality as needed.

- In Ribbon `Advanced Options` of the app use the buttons `Generate Source code` to start code generation. For this step only MATLAB and its toolboxes are needed.

Compile Plugin

- Copy the complete folder *Sources/* (with `MatlabSourceCode.zip`) to the build system. 

- Call the build container with following command (change options to your needs): `docker run --rm -v "/home/user1/Downloads/MATLAB/Sources/":/GInsPluginWork/ gins_matlab_container ./opt/GInsContainerTemplates/StartUp.sh -n "GInsMatlabPlugin" -t "Matlab Plugin" -d 175 -v 2.17.0 -a V3-32 -m`
  
  - -n: Name of Plugin (see `MatlabFunction_GetPluginDescription.m`)
  
  - -t: Title of Plugin seen on website (see `MatlabFunction_GetPluginDescription.m`)
  
  - -d: Device ID (use `175` for Q.station) - No change needed
  
  - -v: Version of SDK (for sdk `gins-qstation-sdk-toolchain-2.17.0.919.sh` use `2.17.0` and skip last build number)
  
  - -a: Firmware architecture (use `V3-32` for 32bit) - No change needed
  
  - -m/s: Use `-m` if MATLAB is used and `-s` for Simulink

- Rename `Sources/GInsMatlabPlugin_usb_install.zip` to `GInsMatlabPlugin_##qstation-x32_2.17.0.999999.zip` (use your plugin name from `-n` option and SDK version `-v`).

Install Plugin

The final `GInsMatlabPlugin_##qstation-x32_2.17.0.999999.zip` can no be installed on the Q.station for example with GInsFirmwareManager (see Knowledge base).