Подключение MATLAB к Wolfram Mathematica

http://mathematica.stackexchange.com/questions/10231/calling-matlab-from-mathematica
  • Перевод
  • Tutorial


Вызов MATLAB из Mathematica с помощью MATLink


Как можно вызывать функции MATLAB напрямую из Mathematica и организовать обмен данными и переменными между двумя системами?

Для этого существует кроссплатформенный пакет под названием MATLink. С помощью него легко организовать вызов функций MATLAB прямо из Mathematica и передавать различные данные от одной системы другой.

Приведу небольшую инструкцию:

● Установка
Сперва стоит перейти на главную страницу MATLink и выполнить указанные там инструкции. Самый простой путь — скачать архив и распаковать его в эту папку:

In[1]:=
SystemOpen@FileNameJoin[{$UserBaseDirectory, "Applications"}]


Далее следует выполнить инструкции для конкретной операционной системы в разделе «Link with MATLAB» на главной странице.

● Использование MATLink

MATLink можно загрузить, вычислив ячейку с кодом:

In[2]:=
Needs["MATLink`"]


А затем запустить MATLAB командой:

In[3]:=
OpenMATLAB []


Таким образом будет запущен новый процесс в MATLAB, с которым Mathematica сможет взаимодействовать.

Для использования произвольных команд MATLAB'а следует использовать MEvaluate. Данные будут переданы в виде строки.

Пример:

In[4]:=
MEvaluate["magic(4)"]

Out[4]=
(* ==>
ans =

    16     2     3    13
     5    11    10     8
     9     7     6    12
     4    14    15     1
 *)


Чтобы передать данные в MATLAB, следует использовать MSet:

In[5]:=
MSet["x", Range[10]];MEvaluate["x"]

Out[5]=
(* ==>
x =
 
     1     2     3     4     5     6     7     8     9    10
*)


Чтобы вернуть данные обратно, следуйте использовать MGet:

In[6]:=
MGet["x"]

Out[6]=
(* ==> {1., 2., 3., 4., 5., 6., 7., 8., 9., 10.} *)


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

Функции MATLAB'а могут вызываться непосредственно из Mathematica с помощью функции MFunction:

In[7]:=
eig = MFunction["eig"];
eig[{{1, 2}, {3, 1}}]

Out[7]=
(* ==> {{3.44949}, {-1.44949}} *)


В документации можно более подробно прочесть об особенностях использования и прочих функциональных возможностях.

Несколько простых примеров


Построим в Mathematica для начала поверхность логотипа MATLAB и добавим манипулятор, который будет регулировать период колебаний:

In[8]:=
Manipulate[
ListPlot3D@MFunction["membrane"][k],
{k, 1, 12, 1}
]

Out[8]=
image

Фуллереновая структура (bucky ball) прямо из MATLAB:

In[9]:=
AdjacencyGraph@Round@MFunction["bucky"][]

Out[9]=
image

Отобразить данные из Mathematica в отдельном масштабируемом окне для рисунков, которые применяются в MATLAB также легко:

In[9]:=
mlf = LibraryFunctionLoad["demo_numerical", "mandelbrot", {Complex}, Integer];
mandel = Table[mlf[x + I y], {y, -1.25, 1.25, .002}, {x, -2., 0.5, .002}];
MFunction["image", "Output" -> False][mandel]

Out[9]=
image

Несколько примеров посложнее


Указанные ниже примеры иллюстрируют решения реальных задач с использованием MATLink, позволяя использовать лучшие качества систем MATLAB и Mathematica.

● Быстрые триангуляции Делоне

В составе Mathematica содержится функция DelaunayTriangulation внутри пакета ComputationalGeometry (в 10-й версии этот пакет стал встроенным в ядро и теперь эта функции носит имя DelaunayMesh, она оптимизирована и теперь её производительность не уступает MATLAB — прим. ред.), однако работает она весьма медленно (хотя у неё есть и свои сильные стороны, такие как использование точной арифметики и работа с коллинеарными точками). Это, в свою очередь, приводит к тому, что ListDensityPlot работает весьма неэффективно (что становится заметно при построении нескольких тысяч точек и более). С использованием MATLink, мы можем задействовать функцию Делоне из MATLAB для вычисления триангуляции Делоне некоторого набора точек следующим образом:

In[10]:=
delaunay = Composition[Round, MFunction["delaunay"]];


Поскольку функция системы Mathematica возвращает список смежных вершин, нам необходимо провести пост-обработку результата для того, чтобы сравнить с результатом из MATLAB'а:

In[11]:=
Needs["ComputationalGeometry`"];
delaunayMma[points_] :=
	Module[{tr, triples},
		tr = DelaunayTriangulation[points];
		triples = Flatten[
			Function[{v, list},
				Switch[Length[list],
				 (* account for nodes with connectivity 2 or less *)
				 1, {},
				 2, {Flatten[{v, list}]}, _, {v, ##}& @@@ Partition[list, 2, 1, {1, 1}]]
			] @@@ tr, 1];
		Cases[GatherBy[triples, Sort], a_ /; Length[a] == 3 :> a[[1]]]
	]


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

In[12]:=
pts = RandomVariate[NormalDistribution[], {100, 2}];
Sort[Sort /@ delaunay[pts]] === Sort[Sort /@ delaunayMma[pts]]


И построим триангуляцию с помощью:

In[13]:=
trianglesToLines[t_] :=
  Union@Flatten[{{#1, #2}, {#2, #3}, {#1, #3}} & @@
	  Transpose[Sort /@ t], {{1, 3}, {2}}];
Graphics@GraphicsComplex[pts, Line@trianglesToLines@delaunay[pts]]

Out[13]:=
image

Однако помимо того, что delaunay работает значительно быстрее DelaunayTriangulation (особенно для больших наборов данных), она также быстрее и triangulator, который используется внутри ListDensityPlot. Следовательно, мы можем использовать delaunay из MATLAB'а для разработки своей версии listDensityPlot, которая работает быстрее, чем встроенная функция, а также может обрабатывать большие наборы данных следующим образом:

In[14]:=
Options[listDensityPlot] = Options[Graphics] ~Join~ {ColorFunction -> Automatic, MeshStyle -> None, Frame -> True};

listDensityPlot[data_?MatrixQ, opt : OptionsPattern[]] :=
	Module[{in, out, tri, colfun},
		tri = delaunay[data[[All, 1;;2]]];
		colfun = OptionValue[ColorFunction];
		If[Not@MatchQ[colfun, _Symbol | _Function], Check[colfun = ColorData[colfun], colfun = Automatic]];
		If[colfun === Automatic, colfun = ColorData["LakeColors"]];
		Graphics[
			GraphicsComplex[data[[All, 1;;2]],
				GraphicsGroup[{EdgeForm[OptionValue[MeshStyle]], Polygon[tri]}],
				VertexColors -> colfun /@ Rescale[data[[All, 3]]]
			],
			Sequence @@ FilterRules[{opt}, Options[Graphics]], Method -> {"GridLinesInFront" -> True}
		]
	]


Давайте теперь сравним нашу функцию со встроенной, используя при этом массив из 30 000 точек:

In[15]:=
pts = RandomReal[{-1, 1}, {30000, 2}];
values = Sin[3 Sqrt[#1^2 + #2^2]] & @@@ pts;


In[16]:=
listDensityPlot[ArrayFlatten[{{pts, List /@ values}}], Frame -> True] // AbsoluteTiming

Out[16]=
{0.409001, --Graphics--}


In[17]:=
ListDensityPlot[ArrayFlatten[{{pts, List /@ values}}]] // AbsoluteTiming

Out[17]=
{12.416587, --Graphics--}


Разница в скорости выполнения получилась весьма значительной (~30 раз). Для работы с сотнями тысяч точек ListDensityPlot оказывается практически непригодной, в то время как listDensityPlot требует лишь несколько секунд.

Также важно учитывать, что для замеров скорости работы MATLink необходимо использовать функцию AbsoluteTiming, с помощью которой вычисляется всё затраченное время, в то время как Timing измеряет только то время, когда CPU использовался ядром Mathematica, не измеряя время, которое затратил MATLAB.

● Фильтрация аудиоданных с помощью инструментов для обработки сигналов (signal processing toolbox)

Как известно, функционал по обработке сигналов отсутствовал в Mathematica до девятой версии, и по-прежнему уступает инструментам MATLAB с точки зрения функциональности и простоты использования. Предположим, у нас 8 версия Mathematica, новые функции отсутствуют и мы хотим провести частотный анализ некоторого аудиофайла и реализовать фильтрацию. Вот как это можно будет сделать:

In[18]:=
{data, fs}  = {#[[1, 1, 1]], #[[1, 2]]} &@ExampleData[{"Sound", "Apollo13Problem"}];
spectrogram = MFunction["spectrogram", "Output" -> False]; (* Use MATLAB's spectrogram *)
spectrogram[data, 1000, 0, 1024, fs]


Очевидно, что частоты в основном приходятся на диапозон ниже 2,5 кГц, так что мы можем разработать в MATLAB фильтр нижних частот, а также сделать вспомогательную функцию, которая будет возвращать отфильтрованные данные:

In[19]:=
MSet["fs", fs];
MEvaluate["
	[z, p, k] = butter(6, 2.5e3/fs, 'low') ;
	[sos, g]  = zp2sos(z, p, k)            ;
	Hd        = dfilt.df2tsos(sos, g)      ;
"]
filter = MFunction["myfilt", "@(x)filter(Hd,x)"];

Out[19]=
image

Теперь мы всё подготовили для того, чтобы применять фильтрующую функцию к данным напрямую из Mathematica. Этот пример показывает, как мы можем восполнить пробелы в функциональности. Таким образом, мы можем сэкономить большое количество времени на проектирование фильтра в Mathematica (а это не самая простая задача) и многие часы на его отладку. Код для фильтра Баттерворта можно взять откуда угодно — c файлообменника или Stack Overflow, из фрагментов ранее написанного кода, или, как в данном случае, из примера в документации. Небольшие изменения в параметрах под текущие нужды, и мы теперь можем работать с этим материалом в Mathematica.

В качестве последнего примера предлагаю обработать некоторые данные с помощью нашего фильтра и построить спектрограмму:

In[19]:=
filteredData = filter@data;
spectrogram[filteredData, 1000, 0, 1024, fs]


Чисто ради забавы можем проиграть оба аудиофайла — отфильтрованный и исходный —и сравнить разницу в их звучании:

In[20]:=
ListPlay[data, SampleRate -> fs]
ListPlay[filteredData, SampleRate -> fs]


image

Если вдруг вы найдёте какие-то ошибки и проблемы в работе MATLink, пожалуйста, сообщите о них на почту (matlink.m@gmail.com), либо на GitHub, либо в комментариях к оригиналу этой статьи.

Дополнения


● Вызов MATLAB из Mathematica с помощью NETLink

Небольшое замечание о том, как можно вызвать MATLAB с помощью NETLink в операционной системе Windows, используя COM-интерфейс MATLAB:

In[21]:=
Needs["NETLink`"]
matlab = CreateCOMObject["matlab.application"]

Out[21]=
«NETObject[COMInterface[MLApp.DIMLApp]]»


Теперь можно обращаться к функциям MATLAB:

In[22]:=
In[4]:= matlab@Execute["version"]

Out[22]=
"
ans =

7.9.0.529 (R2009b)

"


In[23]:=
matlab@Execute["a=2"];matlab@Execute["a*2"]

Out[23]=
"
ans =
     4
 
"


● О преобразовании выражений из синтаксиса Mathematica в синтаксис MATLAB'а

Существует пакет под названием ToMatlab, который преобразовывает выражения из Mathematica в их MATLAB-эквиваленты. Вот пример:

In[24]:=
<<ToMatlab`
Expand[(x + Log@y)^5] // ToMatlab

Out[24]:=
x.^5+5.*x.^4.*log(y)+10.*x.^3.*log(y).^2+10.*x.^2.*log(y).^3+5.* ...
x.*log(y).^4+log(y).^5;


Можно заметить, что выражения весьма удобным способом разбиваются с использованием ...;

Вот ещё пример с конвертацией матриц:

In[25]:=
RandomInteger[5, {5, 5}] // ToMatlab

Out[25]:=
[5,0,5,3,4;
    5,5,3,0,2;
    1,4,4,4,4;
    0,3,2,5,5;
    4,5,5,1,1];


Стоит отметить, что такие вещи, как общие определения, не могут быть преобразованы в синтаксис MATLAB'а. Разумеется, не могут быть сконвертированы и те конструкции, которые не поддерживаются MATLAB'ом — шаблонные выражения, например.

Чтобы установить этот пакет, достаточно просто извлечь файл ToMatlab.m в папку:

In[26]:=
FileNameJoin[{$UserBaseDirectory, "Applications"}]


По вопросам о технологиях Wolfram пишите на info-russia@wolfram.com
Wolfram Research 45,30
Wolfram Language, Mathematica, Wolfram Alpha и др.
Поделиться публикацией
Комментарии 0

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

Самое читаемое