Search code examples
matlabsimulinkmex

Display-like Simulink block with dynamically changing icon


The Display block in Simulink dynamically changes its icon during a simulation depending on the input signal (it displays the input signal value). I would like to create an own block which does the same. Sufficient would be to switch from a red to a green background when the input signal becomes non-zero. Programming the icon is trivial, the question is how to force a repaint of the icon, say, every 0.1s or when the input changes.

I tried...

  • to look at dashboard blocks. But I didn't find how to write my own. The ones which are there are not sufficient. It also seems that they cannot have inputs.
  • I masked a Display block and changed in the mask icon script the icon depending on the input. The old Display icon paints over my mask icon and updates when the signal changes. The mask icon doesn't update/repaint.
  • I noticed that block icons seem to update/repaint when you change block parameters. Currently, I am thinking about programmatically setting an artificial parameter to the input value to force the update, but I am not sure how to best do it/ if this would work.

Best would be to know how this was done in Display, since this block (and thus the feature) will probably persist forever.


Solution

  • The MultiStateImage block indicated in the comment does not have the flexibility to do whatever you want with the block icon.

    I am not aware of a MATLAB command to trigger the repaint of Simulink interface, including icons. However, there is a trick that allows you to achieve what you want: create a MATLAB Function that sets the name of your block to its current name. You'd probably need coder.extrinsic('set_param'); and coder.extrinsic('get_param');. Moreover you need to know the block ID (something as MyModel/MyBlock. From my experience, changing the name of the function triggers a repaint of the icon, so doing that at each timestamp/sample time allows you to refresh the shown icon. I tested this approach on Simulink 2023b.

    function updateBlocks()
    coder.extrinsic('set_param');
    coder.extrinsic('get_param');
    blocks = {'untitled/Sin'};
    for j=1:numel(blocks)
         set_param(blocks{j}, 'Name', get_param(blocks{j}, 'Name'));
    end
    

    In order to actually change the icon according to the input signal(s) however, you should set the code of the icon to something like this:

    rto = get_param(gcb, 'RunTimeObject');
    if numel(rto)>0
        inputPort = rto.InputPort(1);
        inputValue = inputPort.Data;
        fprintf("Block value is %d", inputValue);
    else
        fprintf("Block uninitialized");
    end
    

    Basically, you get the simulation object, its input port, and retrieve the value. The if condition avoids warnings when the simulation is not running (because no runtime object is associated to the block yet).

    Here is a GIF showing the result. I used a sine block camouflaged with a mask icon. At the beginning I step through the simulation, then I let it run and the icon is updating. I suspect that the update rate is bounded to a certain limit, because the current simulation was run for about 1000 steps but I only got a bunch of values displayed. With slower simulation, this is not a problem, but I don't think that you could achieve fast FPS on the update in any way. GIF showing the block icon updating

    Hint: if you just want to display, your MATLABFunction can be masked as well so you avoid unnecessary blocks.

    I also remember the possibility to add a Callback at each simulation step; this could avoid the need of having the MATLABFunction. However, I couldn't find the Callback in the new version, so either they removed it or I remember wrong.