Search code examples
code-generationsimulink

Circular Buffer in Simulink


I would like to implement a very huge (10^6 Elements - fixed size) circular buffer in pure Simulink model (no further toolboxes, no S-Function).

At some points I need to read some elements (anywhere, not just begin or end).

The following solutions I can not use:

  1. "Queue Block" or "Buffer Block" (I have no Signal Processing Toolbox available)
  2. "Discrete Delay" ( I need a hugh buffer and will not place 10^6 delays into the model)
  3. "Sim Events" (I need to generate code from this model)

The "S-Function" I tried not yet, and I am looking for an alternative solution.

What further approach do you know?


Solution

  • First, let me compliment you on your quest for pure Simulink! This is quite possible, however, the Mathworks code generator does not handle this use case. It is extremely sloppy and creates a buffered copy of the entire queue. Here's an example:

    Top Level Model Read Operation Write Operation

    Then, look at some of the code. Yikes!

    /* Model output function */
    static void queue_output(int_T tid)
    {
      {
        real_T rtb_MathFunction;
    
        /* DataStoreRead: '<S1>/Data Store Read' */
        memcpy((void *)(&queue_B.DataStoreRead[0]), (void *)(&queue_DWork.A[0]),
               100000U * sizeof(uint16_T));
    
        /* Outport: '<Root>/Out1' incorporates:
         *  DataStoreRead: '<S1>/Data Store Read1'
         *  Selector: '<S1>/Selector'
         */
        queue_Y.Out1 = queue_B.DataStoreRead[(int32_T)queue_DWork.idx];
    
        /* If: '<Root>/If' incorporates:
         *  ActionPort: '<S2>/Action Port'
         *  Constant: '<Root>/Constant'
         *  SubSystem: '<Root>/WriteToQueue'
         */
        if (queue_P.Constant_Value > 0.0) {
          /* DataStoreRead: '<S2>/Data Store Read3' */
          memcpy((void *)(&queue_B.Assignment[0]), (void *)(&queue_DWork.A[0]),
                 100000U * sizeof(uint16_T));
    
          /* Math: '<S2>/Math Function' incorporates:
           *  Constant: '<S2>/Constant1'
           *  Constant: '<S3>/FixPt Constant'
           *  DataStoreRead: '<S2>/Data Store Read2'
           *  Sum: '<S3>/FixPt Sum1'
           */
          rtb_MathFunction = rt_mod_snf(queue_DWork.idx +
            queue_P.FixPtConstant_Value, queue_P.Constant1_Value);
    
          /* Assignment: '<S2>/Assignment' incorporates:
           *  Constant: '<S2>/Constant'
           */
          queue_B.Assignment[(int32_T)rtb_MathFunction] = queue_P.Constant_Value_h;
    
          /* DataStoreWrite: '<S2>/Data Store Write' */
          memcpy((void *)(&queue_DWork.A[0]), (void *)(&queue_B.Assignment[0]),
                 100000U * sizeof(uint16_T));
    
          /* DataStoreWrite: '<S2>/Data Store Write1' */
          queue_DWork.idx = rtb_MathFunction;
        }
      }
    

    Memcpy 10000 uint16's every loop! Until the Mathworks address this issue in a robust manner, here's an initial attempt that requires hard coding indices, S-Functions are the only way.