Этот пример иллюстрирует, как использовать в своих интересах выполнение многопоточного кода по многоядерному процессору с помощью графического разделения. Этот пример требует, чтобы Simulink® Coder™ сгенерировал многопоточный код.
Одна цель модельно-ориентированного проектирования состоит в том, чтобы создать реалистические модели физических систем и моделировать эти модели в режиме реального времени, например, проверить контроллеры с помощью аппаратных средств в цикле (HIL). Однако, когда больше опций добавляется к модели объекта управления, вычислительные требования могут превысить ресурсы, доступные одножильными системами обработки.
Разделение завода и контроллера в отдельные части является одним способом обратиться к вычислительным потребностям сложных моделей. С Simulink® можно разделить завод с помощью Блоков модели и затем присвоить код, сгенерированный каждой подмоделью к потокам для выполнения в реальном времени в системе HIL, таким как Simulink Real-Time™. Чтобы видеть, как это работает, давайте использовать наш хост - компьютер в качестве заместителя для среды выполнения в реальном времени и сгенерируем многопоточный код в реальном времени для следующей модели.
slexMulticoreSolverExample
Иллюстрация выше показов, что код, сгенерированный для модели, разделен на два потока. В этом примере цель принята, чтобы быть Симметричным Многоядерным процессором, так, чтобы потоки не были сопоставлены ни с каким конкретным ядром. Операционная система ответственна за использование лучше всего ядер при планировании выполнения потока. Идеально, чтобы обеспечить максимальную гибкость, количество потоков (Nt) должно быть больше, чем количество ядер (Nc). Дважды кликните на кнопке 'Generate Code and Profile Report', чтобы сгенерировать многопоточный код, профилировать его выполнение и визуализировать результаты. Визуализация показывает базовую карту заполнения того, как ядра использовались на каждом временном шаге выполнения. Можно заметить, что потоки плавают через ядра, как считается лучше всего планировщиком операционной системы. Этот вид планирования хорош, когда операционная система также должна запустить другие процессы.
Simulink® Coder™ генерирует код, таким образом, что два потока могут выполниться одновременно и возможно на двух различных ядрах. Это означает, что значения сигналов для и должны синхронизироваться между двумя потоками. Simulink® предоставляет несколько возможностей обрабатывать это требование, как проиллюстрировано здесь:
Используя скрипт ниже, мы моделируем и продемонстрируем эффект детерминированных режимов понять, как Simulink® обрабатывает синхронизацию.
Контрольный раствор (ode3) - Simulink® сконфигурирован, чтобы предоставить контрольное решение путем синхронизации данных на каждом главном и незначительном временном шаге.
Нулевой Порядок Содержит - Каждый поток решает подсистему уравнений с помощью ее собственного решателя при синхронизации данных только по главным временным шагам.
Линейная экстраполяция - В дополнение к режиму Zero Order Hold, каждый решатель экстраполирует данные с помощью линейных предсказаний, чтобы компенсировать ошибки задержки данных.
Для большинства систем, где точки синхронизации сглаженны, линейный режим экстраполяции обеспечивает хороший компромисс между коммуникационными узкими местами и числовой точностью.
h = figure; hVal = ishold; hold on; mdl = 'slexMulticoreSolverExample'; dt = get_param(mdl, 'DataTransfer'); modes = { ... 'Ensure deterministic transfer (minimum delay)', ... 'None', 'k:', ... 'Ensure deterministic transfer (maximum delay)', ... 'Zero Order Hold', 'm', ... 'Ensure deterministic transfer (maximum delay)', ... 'Linear', 'b' ... }; for i=1:3:length(modes) dt.DefaultTransitionBetweenContTasks = modes{i}; dt.DefaultExtrapolationMethodBetweenContTasks = modes{i+1}; sim(mdl); plot(logsout.get('x1').Values.Time, ... logsout.get('x1').Values.Data, ... modes{i+2}); end legend('Reference solution (ode3)', ... 'Zero Order Hold Extrapolation', ... 'Linear Extrapolation');
close_system('slexMulticoreSolverExample',0); close_system('slexMulticoreSolverMdlref',0); if ~hVal, hold off; end delete(h);