Circular Buffer in Simulink

前端 未结 2 1252
北荒
北荒 2021-01-07 02:20

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

相关标签:
2条回答
  • 2021-01-07 03:15

    A simple circular buffer can be created with a MATLAB Fcn block:

    function y = CircularBuffer(u, N)
    %#codegen
    % Function to implement a simple N element circular buffer
    
    % Define the internal buffer variable as persistent so
    % so that it will maintain its values from one time step
    % to the next.
    persistent buffer writeIdx
    
    % Initialize the buffer the first time through
    if isempty(buffer)
        % Initialize the buffer
        buffer = zeros(N,1);
        writeIdx = 1;
    else
        buffer(writeIdx) = u;
        if (writeIdx == N)
            writeIdx = 1;
        else
            writeIdx = writeIdx+1;
        end
    end
    
    % Output the buffer
    y = buffer;
    

    This fully supports code generation (and doesn't do a memcpy).

    You can easily change the data type of the buffer if required, but if you want to have different sample rates on the input and output signals (as with the buffer in the Signal Processing blockset) then you'd need to revert to using an S-Function.

    0 讨论(0)
  • 2021-01-07 03:23

    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.

    0 讨论(0)
提交回复
热议问题