В начале своего карьерного пути нам ставят мелкие задачки, результат решения которых мы сразу бежим показывать руководителю. Получаем советы и замечания, потом бежим переделывать. В конце рабочего дня мы отключаем компьютер и со спокойной душой идем домой.
Но по мере роста вашего опыта и списка задач возникает дефицит времени. В какой-то момент начинает казаться, что с офиса можно не уходить. Тогда стать продуктивнее нам поможет автоматизация. Под катом будет небольшой опыт проектировщика антенной техники.
Введение
В прошлом и первом своем посте на Хабре я рассказывал тебе дорогой читатель, как управлять САПР CST MWS с помощью кода Matlab. Пускай отклика в комментариях эта статья не получила, но зато есть отзывы моих коллег и друзей. И самый главный вопрос: «А ты покажешь конкретные варианты применения?» Отмазаться, что варианты применения ограничены лишь вашей фантазией и функционалом пакета не получилось. По этому по просьбе трудящихся сегодня мы рассмотрим пример управления CST MWS из вне.
В данном случае я хотел заставить машину выполнять задачи пока меня нет, либо я занят чем-то более важным и полезным на текущий момент времени. Поэтому и не только было решено копаться в любимых пакетах по электродинамическому моделированию (CST Microwave Studio и Ansys HFSS) на предмет управления из вне. В идеале с помощью инструмента, который мне хорошо знаком, коим является Mathworks Matlab.
В первую очередь хочу отметить, что статья не претендует на супер уникальность и в каких- то частях будет состоять из перевода справки по CST, да и вещи, освещенные ниже, кому-то покажутся слишком очевидными.
Работа с параметрами
Я обожаю параметры. По неопытности раньше я разрабатывал непараметрические модели, но теперь я параметризую почти всё. Почему я это делаю? А мне так нравится. Таким образом я могу перестроить любую геометрию за секунды безошибочно, если я сделал хорошую модель. Нет проблем с геометрией = нет проблем с расчетной сеткой = нет проблем с оптимизацией, поэтому всегда можно быстро перенести проект на другие частоты, в другие корпуса и многое другое.
Очень часто возникает ситуация, когда необходимо провести серию расчетов с изменением параметра и анализом поведения структуры при его изменении. Встроенная утилита Parameter Sweep предлагает предлагает нам изменять параметры по линейному или логарифмическому закону, выбирая число точек или шаг между ними. Также есть возможность ввести конкретные значения параметра. А если закон изменения параметра хочется видеть другой?
Стратегия
В общем случае наша задача достаточно проста, сводится она к расчету значений параметра и передаче CST для расчета. Что бы было не так скучно, прикрутим вывод каких-нибудь графиков. Ниже представлена простенькая блок-схема того, что будем делать.
Единственное, что хочу отметить, выводом результата я назвал его экспорт в текстовом формате, а этап представления результатов моделирования в Matlab запихнул в блок «Постобработка».
Начнем
Для примера будем использовать мой 5-минутный проект прямоугольной патч-антенны.
На рисунке выше представлена сама модель для расчета и параметр L, который мы будем менять.
Пусть параметр L изменяется по квадратичному закону закону в пределах от 10 до 100, количество значений 5:
x = sqrt(10):(10-sqrt(10))/5:10;
y = x.^2;
На всякий случай приведу график, хоть все понимают как он должен выглядеть.
Запускаем CST и открываем наш проект, а также привяжем к переменным все необходимые нам объекты CST:
cst = actxserver('CSTStudio.Application');
mws = cst.invoke('NewMWS');
mws.invoke('OpenFile','path\to\file.cst');
solv = mws.invoke('Solver');
export = mws.invoke('ASCIIExport');
plot1d = mws.invoke('Plot1D');
Кратко о том, что эти 6 строк представляют в порядке их написания:
- Привязка объекта приложения CST Studio к переменной cst
- Привязка окна CST MWS к переменной mws
- Открытие в окне CST MWS файла
- Привязка объекта вычислителя к переменной solv
- Привязка объекта Экспорта в ASCII к переменной export
- Привязка объекта одномерных графиков к переменной plot1d
Далее введем промежуточную переменную, которая пригодится для формирования путей к файлам результатов:
f_cell = cell(length(y),1);
Чего мы можем добиться от CST о параметрах используемых в проекте?
Последнюю функцию в списке я как-то не смог прикрутить к матлабу. Но не суть, в данном случае она нам и не нужна.
- Можем удалить параметр командой
mws.invoke('DeleteParameter','ParameterName');
- Узнать число параметров
mws.invoke('GetNumberOfParameters');
- Узнать имя параметра по его номеру
mws.invoke('GetParameterName','ParameterNumber');
- Узнать значения параметра по его номеру в double
mws.invoke('GetParameterNValue','ParameterNumber');
- Узнать значения параметра по его номеру в string
mws.invoke('GetParameterNValue','ParameterNumber');
- Узнать значения параметра по его имени в string
mws.invoke('RestoreParameter','ParameterName');
- Узнать значения параметра по его имени в double
mws.invoke('RestoreDoubleParameter','ParameterName');
- Узнать выражение, с помощью которого вычисляется параметр, по его имени в string
mws.invoke('RestoreParameterExpression','ParameterName');
- Создать новый параметр строку (или заменить существующий) с его описанием
mws.invoke('StoreParameterWithDescription','ParameterName', 'ParameterValue','ParameterDescription');
- Создать новый параметр строку (или заменить существующий) без описания
mws.invoke('StoreParameter','ParameterName', 'ParameterValue');
- Создать новый параметр double (или заменить существующий) без описания
mws.invoke('StoreDoubleParameter','ParameterName', 'ParameterValue');
- Убедиться не занято ли имя параметра, если незанято создать новый с указанным значениям, иначе не трогать существующий
mws.invoke('MakeSureParameterExists','ParameterName', 'ParameterValue');
- Добавить описание к существующему параметру по имени
mws.invoke('SetParameterDescription','ParameterName');
- Выдернуть массивы по номеру запуска расчета с именами параметров и их значениями
mws.invoke('GetParameterCombination','ResultId','ParameterNames','ParametersValues');
Последнюю функцию в списке я как-то не смог прикрутить к матлабу. Но не суть, в данном случае она нам и не нужна.
Так как задачу я сильно упростил, то из представленного в спойлере списка интересна только одна функция:
mws.invoke('StoreDoubleParameter','ParameterName', 'ParameterValue');
В теле цикла нам надо будет сделать всего 4 операции: передать параметр, обновить модель, запустить расчет и экспортировать результаты.
Открываем цикл длиной от 1 до количества значений параметра y:
for i=1: length(y)
Передаем параметр:
mws.invoke('StoreDoubleParameter','L', y(i));
Обновляем модель:
mws.invoke('Rebuild');
Запускаем расчет:
solv.invoke('Start');
Далее подготавливаем строковые переменные путей сохранения файлов (первой строкой переводим текущее значения параметра в строку, второй — создаем строку пути сохранения файла, третьей — записываем в массив ячеек адрес текущего файла результатов:
str_y = num2str(y(i));
f_name = strcat('C:\Results_patch\patch_z_im_y=', str_y,'.txt');
f_cell(i,1) = {f_name};
В качестве результата для экспорта я выбрал график мнимой части входного сопротивления, поэтому далее следует выбор соответствующей ветки дерева результатов, процедура экспорта в ASCII, описанные в предыдущем посте, а также окончание цикла.
mws.invoke('SelectTreeItem','1D Results\Z Matrix\Z1,1');
plot1d.invoke('PlotView','imaginary');
export.invoke('Reset');
export.invoke('FileName',f_name);
export.invoke('Mode','FixedNumber');
export.invoke('Step','1001');
export.invoke('Execute')
end
После проделанных действий мы имеем набор файлов с результатом расчета мнимой части входного сопротивления. Но что еще делать с частотно-зависимыми величинами? Выводить в виде графика.
Так как все результаты вывода в ASCII из CST имеют заголовок, нам надо от него избавиться, в нашем случае это две строки в начале каждого файла:
Frequency / MHz Z1,1/imaginary
----------------------------------------------------------------------
Для этого воспользуемся простенькой функцией, приведенной под спойлером ниже, которую я давненько написал. Входной параметр для функции — путь к фалу для удаления заголовка.
Функция построчно читает файл, потом перезаписывает в него данные без заголовка, а на выходе дает вам переменную с данными из файла.
Удаление заголовка
function [f_cell] = h_remove(ishod)
ffile = fopen(ishod,'rt');
f_cell=cell(1003,1);
i=1;
for i=1:length(f_cell)
%while feof(Farfield) ==0
f_cell{i,1} = fgetl(ffile);
%i = i+1;
end
f_cell = f_cell(3: end, 1);
fclose(ffile);
ffile = fopen(ishod, 'w+');
for i = 1: length(f_cell)
fprintf(ffile, '%s\r\n', f_cell{i,1});
end
fclose(ffile);
f_dat = load(ishod);
end
С помощью указанной выше функции грузим в переменные результаты расчетов, выводим график и слегка причесываем его.
y1 = h_remove(f_cell{1,1});
y2 = h_remove(f_cell{2,1});
y3 = h_remove(f_cell{3,1});
y4 = h_remove(f_cell{4,1});
y5 = h_remove(f_cell{5,1});
y6 = h_remove(f_cell{6,1});
plot(y1(:,1),y1(:,2), '-r', y1(:,1),y2(:,2), '--r',y1(:,1),y3(:,2), '-.r',y4(:,1),y1(:,2), '-b',y1(:,1),y5(:,2), '--b',y1(:,1),y6(:,2), '-.b')
grid on
xlabel('Частота, МГц')
ylabel('Сопротивление, Ом')
legend(num2str(y(1)),num2str(y(2)),num2str(y(3)),num2str(y(4)),num2str(y(5)),num2str(y(6)))
Выводы
Вот таким нехитрым образом всего за 39 строк мы заставили CST сделать параметрический расчет по заданному нами закону изменения параметра, вывели результаты расчета для дальнейшей обработки в ASCII, ну и прикрутили вывод в среде Matlab.
Вы можете сказать: Э«то все можно сделать и без Matlab'а! Что ты тут выдумал есть же встроенный редактор макросов на VBA». И я отвечу: «Да, вы правы. Можете писать всё на VBA, если вам так нравится».
Но дальнейшая обработка результатов в Matlab может быть полезна. Также можно использовать Report Generator. Тогда становится возможным оставить машину выполнять расчет в ваше отсутствие, а потом останется только распечатать и положить уже готовый отчет на стол руководителя.
Ссылки
Ниже размещаю тест скрипта, разобранного здесь, и функции h_remove для ваших экспериментов, а также ссылку на файл проекта для тех кто не заметил ссылку в тексте:
→ Проект антенны
Скрипт
%% Расчет значений параметра
x = sqrt(10):(10-sqrt(10))/5:10;
y = x.^2;
%% Запуск и привязка объектов CST
%cst = actxserver('CSTStudio.Application');
%mws = cst.invoke('NewMWS');
%mws.invoke('OpenFile','C:\patch.cst');
solv = mws.invoke('Solver');
export = mws.invoke('ASCIIExport');
plot1d = mws.invoke('Plot1D');
f_cell = cell(length(y),1);
%% Цикл для расчета
for i=1: length(y)
mws.invoke('StoreDoubleParameter','L', y(i));
mws.invoke('Rebuild');
solv.invoke('Start');
str_y = num2str(y(i));
f_name = strcat('C:\Results_patch\patch_z_im_y=', str_y,'.txt');
f_cell(i,1) = {f_name};
mws.invoke('SelectTreeItem','1D Results\Z Matrix\Z1,1');
plot1d.invoke('PlotView','imaginary');
export.invoke('Reset');
export.invoke('FileName',f_name);
export.invoke('Mode','FixedNumber');
export.invoke('Step','1001');
export.invoke('Execute')
end
%% Постобработка
y1 = h_remove(f_cell{1,1});
y2 = h_remove(f_cell{2,1});
y3 = h_remove(f_cell{3,1});
y4 = h_remove(f_cell{4,1});
y5 = h_remove(f_cell{5,1});
y6 = h_remove(f_cell{6,1});
plot(y1(:,1),y1(:,2), '-r', y1(:,1),y2(:,2), '--r',y1(:,1),y3(:,2), '-.r',y4(:,1),y1(:,2), '-b',y1(:,1),y5(:,2), '--b',y1(:,1),y6(:,2), '-.b')
grid on
xlabel('Частота, МГц')
ylabel('Сопротивление, Ом')
legend(num2str(y(1)),num2str(y(2)),num2str(y(3)),num2str(y(4)),num2str(y(5)),num2str(y(6)))
h_remove
function [f_dat] = h_remove(ishod)
%Грузим файл который надо править
ffile = fopen(ishod,'rt');
%Создаем временную переменную для хранения строк исходнового текста
f_cell=cell(1003,1);
%Цикл читает построчной исходный файл и записывает во временную переменную
i=1;
for i=1:length(f_cell)
%while feof(Farfield) ==0
f_cell{i,1} = fgetl(ffile);
%i = i+1;
end
f_cell = f_cell(3: end, 1);
fclose(ffile);
ffile = fopen(ishod, 'w+');
for i = 1: length(f_cell)
fprintf(ffile, '%s\r\n', f_cell{i,1});
end
fclose(ffile);
f_dat = load(ishod);
end