exponenta event banner

Катание по контуру

Одной из функций оптимизации компилятора Target Language Compiler является внутренняя поддержка циклической прокрутки. На основе заданного порога генерация кода для операций закольцовывания может быть развернута или оставлена в виде цикла (свернутого).

С катанием контура связано понятие несмежных сигналов. Рассмотрим следующую модель:

Входные данные для timestwo S-функция происходит от двух массивов, расположенных в двух различных ячейках памяти, один для выхода source1 и один для вывода блока source2. Это происходит из-за оптимизации, которая делает блок Mux виртуальным, что означает, что код не генерируется явно для блока Mux и, таким образом, циклы процессора не расходуются на его оценку (то есть он становится чисто графическим удобством для блок-схемы). Таким образом, это представлено в model.rtw файл в данном случае как

Block {
      Type		      "S-Function"
      MaskType		      "S-function: timestwo"
      BlockIdx		      [0, 0, 2]
      SL_BlockIdx	      2
      GrSrc		      [0, 1]
      ExprCommentInfo {
	SysIdxList		[]
	BlkIdxList		[]
	PortIdxList		[]
      }
      ExprCommentSrcIdx {
	SysIdx			-1
	BlkIdx			-1
	PortIdx			-1
      }
      Name		      "<Root>/timestwo  C-MEX S-Function"
      SLName		      "<Root>/timestwo \nC-MEX S-Function"
      Identifier	      timestwoCMEXSFunction
      TID		      0
      RollRegions	      [0:19, 20:49]
      NumDataInputPorts	      1
      DataInputPort {
	SignalSrc		[b0@20, b1@30]
	SignalOffset		[0:19, 0:29]
	Width			50
	RollRegions		[0:19, 20:49]
      }
      NumDataOutputPorts      1
      DataOutputPort {
	SignalSrc		[b2@50]
	SignalOffset		[0:49]
	Width			50
      }
      Connections {
	InputPortContiguous	[no]
	InputPortConnected	[yes]
	OutputPortConnected	[yes]
	OutputPortBeingMerged	[no]
	DirectSrcConn		[no]
	DirectDstConn		[yes]
	DataOutputPort {
	  NumConnPoints		  1
	  ConnPoint {
	    SrcSignal		    [0, 50]
	    DstBlockAndPortEl	    [0, 4, 0, 0]
	  }
	}
  }
.
.
.

Из этого фрагмента model.rtw вы можете видеть, что блок и входной порт RollRegion записи представляют собой не только одно число, но и две группы чисел. Это означает две группировки в памяти для входного сигнала. Созданный код выглядит следующим образом:

/* S-Function Block: <Root>/timestwo  C-MEX S-Function */
  /* Multiply input by two */
  {
    int_T i1;

    const real_T *u0 = &contig_sample_B.u[0];
    real_T *y0 = contig_sample_B.timestwoCMEXSFunction_m;

    for (i1=0; i1 < 20; i1++) {
      y0[i1] = u0[i1] * 2.0;
    }

    u0 = &contig_sample_B.u_o[0];
    y0 = &contig_sample_B.timestwoCMEXSFunction_m[20];

    for (i1=0; i1 < 30; i1++) {
      y0[i1] = u0[i1] * 2.0;
    }
}

Обратите внимание, что генерируются два контура и между ними входной сигнал перенаправляется с первого базового адреса, &contig_sample_B.u[0], ко второму базовому адресу сигналов, &contig_sample_B.u_o[0]. Если вы не хотите поддерживать это в вашей S-функции или сгенерированном коде, вы можете использовать

ssSetInputPortRequiredContiguous(S, 1);

в mdlInitializeSizes функция, заставляющая Simulink ® неявно генерировать код, выполняющий операцию буферизации. Этот параметр использует как дополнительные циклы памяти, так и циклы ЦП во время выполнения, но может стоить того, если производительность алгоритма увеличится настолько, чтобы компенсировать издержки буферизации.

Используйте %roll директива для создания циклов. См. также% roll для ссылочной записи для %rollи функции входного сигнала для обсуждения поведения %roll.