Circular Buffer in Simulink

痴心易碎 提交于 2019-12-19 04:14:22

问题


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?


回答1:


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:

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.




回答2:


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.



来源:https://stackoverflow.com/questions/17194078/circular-buffer-in-simulink

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!