Иногда Simulink ® регенерирует цель моделирования для модели в начале моделирования в режиме ускорителя (TM), но не всегда ясно, почему происходит регенерация. В этом примере показано, как использовать команды Simulink ® MATLAB ® для определения причин регенерации кода Simulink при моделировании в режиме ускорителя.
Ускоренный режим Simulink ускоряет моделирование модели, создавая исполняемую версию модели, называемую целью моделирования, и выполняя эту цель вместо интерпретации модели, как это делается при моделировании в обычном режиме. Accelerator Mode создает цель моделирования, генерируя код C из модели и вызывая функцию MATLAB ® mex для компиляции и динамического связывания сгенерированного кода с Simulink.
Процесс создания и компиляции кода происходит при первом моделировании модели в режиме ускорителя. Кроме того, генерация кода может происходить при последующих моделированиях, особенно если модель изменяется между моделированиями (например, после добавления блока). Генерация кода требует времени, и часто желательно избегать его, чтобы максимизировать количество имитаций в течение заданного промежутка времени.
Simulink использует контрольную сумму модели для определения необходимости регенерации кода. Эта контрольная сумма представляет собой массив из четырех целых чисел, вычисленных с помощью алгоритма контрольной суммы md5, основанного на атрибутах модели и содержащихся в ней блоках. Любое изменение в модели, которое изменяет контрольную сумму, приводит к тому, что Simulink регенерирует цель моделирования для режима ускорителя.
Иногда неясно, какое изменение модели инициировало изменение контрольной суммы и, следовательно, регенерацию кода. В этом примере показано, почему Simulink необходимо регенерировать код для моделирования режима ускорителя для данной модели и ее конфигурации.
Поскольку при моделировании в режиме ускорителя создаются некоторые файлы, сначала переместите их во временную область.
originalDir = pwd; tempDir = tempname; mkdir(tempDir) cd(tempDir)
В этом примере мы будем использовать простую модель slAccelDemoWhyRebuild.
model = 'slAccelDemoWhyRebuild'; open_system(model) set_param(model,'AccelVerboseBuild','on');

При первом запуске модели в режиме ускорителя она генерирует и компилирует код в соответствии с ожиданиями.
simOutput = evalc(['sim(''',model,''')']); if ~isempty(strfind(simOutput,'Building the Accelerator target for model')) disp('Built Simulink Accelerator mex file') else disp('Did not build Simulink Accelerator mex file') end
Built Simulink Accelerator mex file
При повторном запуске моделирования без каких-либо изменений модели предполагается, что Simulink может повторно использовать существующий код и не нуждается в регенерации кода. Выполните те же команды для проверки.
simOutput = evalc(['sim(''',model,''')']); if ~isempty(strfind(simOutput,'Building the Accelerator target for model')) disp('Built Simulink Accelerator mex file') else disp('Did not build Simulink Accelerator mex file') end
Did not build Simulink Accelerator mex file
Теперь мы изменяем некоторые параметры в модели. Мы установим следующие настройки для блока «Интегратор»: - set 'Ignore limit and reset when linearizing' to 'on' - установите 'Initial Condition' на '5'
set_param([model,'/Integrator'],'IgnoreLimit','on'); set_param([model,'/Integrator'],'InitialCondition','5');
При повторном запуске моделирования будет показано, что Simulink регенерирует код.
simOutput = evalc(['sim(''',model,''')']); if ~isempty(strfind(simOutput,'Building the Accelerator target for model')) disp('Built Simulink Accelerator mex file') else disp('Did not build Simulink Accelerator mex file') end
Built Simulink Accelerator mex file
Мы хотели бы знать почему.
Чтобы определить, является ли ранее созданный код действительным для текущей конфигурации модели, Simulink сравнивает контрольную сумму модели, использованную для создания кода, с текущей контрольной суммой. Если они равны, ранее созданный код остается действительным, и Simulink Accelerator Mode повторно использует его для текущего моделирования. Если значения различаются, Simulink Accelerator Mode регенерирует и перестраивает код. Таким образом, изучение деталей вычисления контрольной суммы может показать, почему Simulink регенерировал код.
Следующая команда получает сведения о вычислении контрольной суммы модели:
[cs1,csdet1]=Simulink.BlockDiagram.getChecksum(model);
Первым выводом является само значение контрольной суммы модели. Второй вывод дает подробную информацию о том, что вошло в вычисление контрольной суммы.
Зададим для параметров измененного блока исходные значения и получим контрольную сумму и подробные данные для этой конфигурации
set_param([model,'/Integrator'],'IgnoreLimit','off'); set_param([model,'/Integrator'],'InitialCondition','0'); [cs2,csdet2]=Simulink.BlockDiagram.getChecksum(model);
Сравнение этих двух значений контрольной суммы эквивалентно определению того, будет ли Simulink Accelerator регенерировать код. Обратите внимание, что значения контрольной суммы отличаются, так как мы ожидаем, что на основе того, что Simulink Accelerator восстанавливает код каждый раз при его запуске.
if (cs1 ~= cs2) disp('Checksums are different') else disp('Checksums are the same') end
Checksums are different
Теперь, когда мы знаем, что контрольные суммы различаются, следующий вопрос - почему. Многие вещи входят в расчет контрольной суммы, включая типы данных сигнала, некоторые значения параметров блока и информацию о связности блока. Чтобы понять, почему контрольные суммы различаются, нам нужно увидеть, что изменилось в элементах, используемых при вычислении контрольной суммы. Сведения о контрольной сумме, возвращенные в качестве второго аргумента, дают эту информацию.
csdet1
csdet1 =
struct with fields:
ContentsChecksum: [1x1 struct]
InterfaceChecksum: [1x1 struct]
ContentsChecksumItems: [186x1 struct]
InterfaceChecksumItems: [49x1 struct]
Сведения о контрольной сумме представляют собой структурный массив с четырьмя полями. Два поля являются контрольными суммами компонентов контрольной суммы модели (они называются ContureChecksum и InteriveChecksum), а два других являются соответствующими подробными данными контрольной суммы. Эти детали соответствуют различной информации, которая вошла в вычисление двух контрольных сумм компонента. Контрольная сумма модели [structural] является функцией ContureChecksum и InteriveChecksum.
Во-первых, давайте определим, лежит ли разница в содержимом модели или в интерфейсе модели.
if (csdet1.ContentsChecksum.Value ~= csdet2.ContentsChecksum.Value) disp('Contents checksums are different') else disp('Contents checksums are the same') end if (csdet1.InterfaceChecksum.Value ~= csdet2.InterfaceChecksum.Value) disp('Interface checksums are different') else disp('Interface checksums are the same') end
Contents checksums are different Interface checksums are the same
Теперь, когда мы знаем, что изменение находится в компоненте Контрольная сумма, мы можем посмотреть на компонент ChecksumItems, чтобы увидеть, что изменилось.
idxForDifferences=[]; for idx = 1:length(csdet1.ContentsChecksumItems) if (~strcmp(csdet1.ContentsChecksumItems(idx).Handle, ... csdet2.ContentsChecksumItems(idx).Handle)) idxForDifferences=[idxForDifferences,idx]; disp(['Handles different for item ',num2str(idx)]); end if (~strcmp(csdet1.ContentsChecksumItems(idx).Identifier, ... csdet2.ContentsChecksumItems(idx).Identifier)) disp(['Identifiers different for item ',num2str(idx)]); idxForDifferences=[idxForDifferences,idx]; end if(ischar(csdet1.ContentsChecksumItems(idx).Value)) if (~strcmp(csdet1.ContentsChecksumItems(idx).Value, ... csdet2.ContentsChecksumItems(idx).Value)) disp(['String Values different for item ',num2str(idx)]); idxForDifferences=[idxForDifferences,idx]; end end if(isnumeric(csdet1.ContentsChecksumItems(idx).Value)) if (csdet1.ContentsChecksumItems(idx).Value ~= ... csdet2.ContentsChecksumItems(idx).Value) disp(['Numeric values are different for item ',num2str(idx)]); idxForDifferences=[idxForDifferences,idx]; end end end
String Values different for item 40
Теперь, когда мы знаем, что различия есть в элементах в индексах, перечисленных в idxForDifferences, мы можем посмотреть на эти элементы в двух массивах ContiveChecksumItems
blk1 = csdet1.ContentsChecksumItems(idxForDifferences(1)).Handle blk2 = csdet2.ContentsChecksumItems(idxForDifferences(1)).Handle id1 = csdet1.ContentsChecksumItems(idxForDifferences(1)).Identifier id2 = csdet2.ContentsChecksumItems(idxForDifferences(1)).Identifier
blk1 =
'slAccelDemoWhyRebuild/Integrator'
blk2 =
'slAccelDemoWhyRebuild/Integrator'
id1 =
'IgnoreLimit'
id2 =
'IgnoreLimit'
Дескриптором для обоих элементов является «slAccelDemoWhyRebuild/Integrator», указывающий блок с изменяющимися данными. Идентификатором для обоих является IgnureLimit, который сообщает нам, что это была измененная настройка блока, что приводит к разной контрольной сумме для модели. Настройка начального условия блока не отображается в подробных данных контрольной суммы. Поэтому мы ожидаем, что если изменяется только настройка для начального условия, то перестроение не произойдет.
Теперь, когда мы нашли параметр, который вызывает различия контрольных сумм для этого рабочего процесса, мы можем проверить результаты, сохраняя этот параметр постоянным и наблюдая, происходит ли перестроение при последовательных моделированиях.
Давайте снова смоделируем модель в режиме акселератора. Мы ожидаем, что он будет перестроен для этого моделирования, потому что мы изменили параметр («IgnireLimit») для вычисления контрольной суммы выше.
simOutput = evalc(['sim(''',model,''')']); if ~isempty(strfind(simOutput,'Building the Accelerator target for model')) disp('Built Simulink Accelerator mex file') else disp('Did not build Simulink Accelerator mex file') end
Built Simulink Accelerator mex file
Теперь давайте изменим только параметр «Начальное условие» и смоделируем снова. Мы ожидаем, что на этот раз не произойдет никакой перестройки.
set_param([model,'/Integrator'],'InitialCondition','-3'); simOutput = evalc(['sim(''',model,''')']); if ~isempty(strfind(simOutput,'Building the Accelerator target for model')) disp('Built Simulink Accelerator mex file') else disp('Did not build Simulink Accelerator mex file') end
Did not build Simulink Accelerator mex file
Как и ожидалось при анализе контрольной суммы, изменение параметра «Initial Condition» не приводит к регенерации кода для моделирования в режиме ускорителя.
Закройте модель и удалите созданные файлы.
bdclose(model) clear([model,'_acc']) cd(originalDir) rmdir(tempDir,'s')