Определение, почему акселератор Simulink регенерирует код

Sometimes Simulink® регенерирует цель моделирования для модели в начале моделирования в Accelerator Mode(TM), но не всегда ясно, почему регенерация происходит. Этот пример показывает, как использовать команды Simulink® MATLAB®, чтобы определить, почему Simulink регенерирует код для моделирований Режима Accelerator.

Режим Accelerator Симулинка ускоряет моделирование вашей модели путем создания выполняемой версии модели, названной целью моделирования, и выполнения этой цели вместо того, чтобы интерпретировать модель, как сделан во время моделирования Режима normal mode. Режим Accelerator создает цель моделирования путем генерации кода С от модели и вызова MEX-функции MATLAB®, чтобы скомпилировать и динамически соединить сгенерированный код с Simulink.

Процесс генерации кода и компиляция происходят в течение первого раза, когда вы моделируете свою модель в Режиме Accelerator. Кроме того, генерация кода может произойти на последующих моделированиях, особенно если модель изменяется между моделированиями (например, после сложения блока). Генерация кода занимает времена, и часто желательно избежать его в порядке максимизировать количество моделирований в данном отрезке времени.

Симулинк использует контрольную сумму модели, чтобы определить, должен ли код быть регенерирован. Эта контрольная сумма является массивом четырех целых чисел, вычисленных при помощи md5 алгоритма контрольной суммы на основе атрибутов модели и блоков, которые это содержит. Любое изменение в модели, которая изменяет контрольную сумму, заставляет Симулинка, регенерируют цель моделирования для Режима Accelerator.

Иногда, это не ясно, какое образцовое изменение инициировало изменение контрольной суммы и следовательно регенерацию кода. Этот пример показывает, как заняться расследованиями, почему Simulink должен регенерировать код для моделирования Режима Accelerator для данной модели и ее настройки.

Создайте временную работающую директорию

Начиная с моделирования в Режиме Accelerator создает некоторые файлы, первый шаг к временной области.

originalDir = pwd;
tempDir = tempname;
mkdir(tempDir)
cd(tempDir)

Откройте модель в качестве примера

Мы будем использовать простую модель, slAccelDemoWhyRebuild, всюду по этому примеру.

model = 'slAccelDemoWhyRebuild';
open_system(model)
set_param(model,'AccelVerboseBuild','on');

В первый раз образцовые выполнения в Режиме Accelerator, это генерирует и компилирует код как ожидалось.

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

Теперь мы изменяем некоторые параметры в модели. Мы установим следующие настройки для блока 'Integrator': - устанавливают, 'Игнорируют предел и сбрасывают при линеаризации' к 'on' - установленное 'Начальное Условие' к '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 сравнивает контрольную сумму модели, как используется сгенерировать код к текущей контрольной сумме. Если они равны, ранее сгенерированный код является все еще допустимым и Режимом Accelerator Simulink, снова использует его для текущего моделирования. Если значения отличаются, Режим Accelerator Simulink регенерирует и восстанавливает код. Таким образом исследование деталей вычисления контрольной суммы может показать, почему 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 регенерирует код. Обратите внимание на то, что значения контрольной суммы отличаются, когда мы ожидаем на основе того, что Акселератор Simulink регенерирует код каждый раз, когда это запускается.

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: [180x1 struct]
    InterfaceChecksumItems: [47x1 struct]

Детали контрольной суммы являются массивом структур с четырьмя полями. Два из полей являются контрольными суммами компонента образцовой контрольной суммы (они называются ContentsChecksum и InterfaceChecksum), и другие два являются соответствующими деталями контрольной суммы. Эти детали соответствуют различной информации, которая вошла к вычислению двух контрольных сумм компонента. Образцовая [структурная] контрольная сумма является функцией ContentsChecksum и InterfaceChecksum.

Во-первых, давайте определим, заключается ли различие в содержимом модели или интерфейсе модели

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

Используйте детали, чтобы определить почему измененная контрольная сумма

Теперь, когда мы знаем, что изменение находится в ContentsChecksum, мы можем посмотреть на ContentsChecksumItems, чтобы видеть то, что изменилось.

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 41

Теперь, когда мы знаем, что различия находятся в элементах в индексах, перечисленных в idxForDifferences, мы можем посмотреть на те элементы в двух массивах ContentsChecksumItems

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', который указывает на блок с изменяющимися данными. Идентификатором для обоих является 'IgnoreLimit', который говорит нам, что это было блочной установкой, которая изменилась, приведя к различной контрольной сумме для модели. Установка для Начального Условия блока не появляется в деталях контрольной суммы. Поэтому мы ожидаем, что, если только установка для Начального Условия изменяется, которые не восстанавливают, произойдет.

Избегайте восстанавливания на последовательных моделированиях

Теперь, когда мы нашли параметр, который заставляет контрольные суммы, отличаются для этого рабочего процесса, мы можем подтвердить результаты путем хранения того параметра постоянным и наблюдения, восстанавливают ли, происходит на последовательных моделированиях.

Давайте моделируем модель в Режиме Accelerator снова. Мы ожидаем, что он восстановит для этого моделирования, потому что мы изменили параметр ('IgnoreLimit') для вычисления контрольной суммы выше.

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

Теперь давайте только изменим настройки Initial Condition и моделировать снова. Мы ожидаем, что не восстанавливают, должен произойти на этот раз.

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

Как ожидалось от анализа контрольной суммы, изменяя параметр для 'Начального Условия' не вызывает регенерацию кода для моделирования в Режиме Accelerator.

Очистка

Закройте модель и удалите сгенерированные файлы.

bdclose(model)
clear([model,'_acc'])
cd(originalDir)
rmdir(tempDir,'s')
Была ли эта тема полезной?