【问题标题】:Circular Buffer in SimulinkSimulink 中的循环缓冲区
【发布时间】:2017-11-03 17:03:25
【问题描述】:

我想在纯 Simulink 模型中实现一个非常巨大的(10^6 个元素 - 固定大小)循环缓冲区(没有其他工具箱,没有 S-Function)。

在某些时候我需要阅读一些元素(任何地方,不仅仅是开始或结束)。

以下解决方案我不能使用:

  1. “队列块”或“缓冲区块”(我没有可用的信号处理工具箱)
  2. “离散延迟”(我需要一个巨大的缓冲区,并且不会在模型中放置 10^6 个延迟)
  3. “模拟事件”(我需要从这个模型生成代码

我还没有尝试过的“S-Function”,我正在寻找替代解决方案。

您还知道哪些进一步的方法?

【问题讨论】:

  • 为什么不使用 MATLAB Function 模块并在 MATLAB 代码中将缓冲区声明为持久数据?
  • 据我所知,Matlab 功能块在较旧的 Matlab/Simulink 版本(2011 年之前)中不可用。我一直在寻找一种向下兼容的方法。对于只有较新的版本,我会采用 Matlab 功能块(witch Matlab Coder)和 Phil Goddard 发布的解决方案。

标签: code-generation simulink


【解决方案1】:

可以使用 MATLAB Fcn 块创建简单的循环缓冲区:

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;

这完全支持代码生成(并且不执行 memcpy)。

如果需要,您可以轻松更改缓冲区的数据类型,但如果您希望输入和输出信号具有不同的采样率(与 Signal Processing 模块集中的缓冲区一样),则需要恢复为使用 S-Function。

【讨论】:

    【解决方案2】:

    首先,让我恭维您对纯 Simulink 的追求!这是很有可能的,但是,Mathworks 代码生成器不处理此用例。它非常草率,并创建了整个队列的缓冲副本。这是一个例子:

    然后,看一些代码。哎呀!

    /* 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 的每个循环!在 Mathworks 以稳健的方式解决此问题之前,这里有一个 initial attempt that requires hard coding indices,S-Function 是唯一的方法。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2016-06-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-09-26
      • 2022-11-14
      相关资源
      最近更新 更多