2013-06-19 635 views
2

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

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

下面的解决方案我无法使用:

  1. “队列块”或“缓冲块”(我没有信号处理工具箱提供)
  2. “离散延迟”(我需要一个休缓冲区不会将10^6延迟到模型)
  3. “SIM事件”(我需要从这个模型生成代码

的“S-功能”我试图不但是,我正在寻找替代解决方案。

你知道甚么?

+0

为什么不使用MATLAB功能块并将您的缓冲区声明为MATLAB代码中的永久数据? – Navan

+0

据我所知,Matlab功能模块在旧版的Matlab/Simulink版本中(2011年之前)不可用。我正在寻找一种向下兼容的方法。对于只有更新的版本,我会采用Matlab功能块(巫婆Matlab编码器)和Phil Goddard发布的解决方案。 – ToBe

回答

2

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

Top Level Model Read Operation Write Operation

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

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

4

一个简单的循环缓冲器可以用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)。

如果需要,您可以很容易地更改缓冲区的数据类型,但是如果您希望在输入和输出信号上具有不同的采样率(与信号处理模块集中的缓冲区一样),则需要恢复使用S功能。