Интегрируем MATLAB в С#.NET

Вступление


В этой статье я постараюсь максимально полно и пошагово рассказать, как связать MATLAB с С#.NET и сделать приложение с интерфейсом на примере построения 3D-плоскости.

Зачем это нужно?


Очень часто перед программистом встает задача вычисления сложной математики. MATLAB в свою очередь является отличным средством для решения, но слаб в создании полноценного пользовательского приложения (можно воспользоваться инструментами GUI MATLAB'a, но это меня не устроило).

Инструменты


  1. Microsoft Visual Studio 2008 SP1
  2. MATLAB 2010a
  3. MATLAB Component Runtime


Шаг 1. Настройка линкера


Чтобы собрать dll-библиотеку MATLAB'а для интеграции в C#.NET, нужно настроить линкер, т.е. какой средой мы будем собирать проект. Для начала нужно установить среду выполнения MCR (MATLAB Component Runtime). Это набор dll-библиотек для полной поддержки языка MATLAB. Установочный файл можно найти: ...\MATLAB\R2011b\toolbox\compiler\deploy\win32\MCRInstaller. Установка типовая, жмем next.
Для настройки линкера в командном окне MATLAB'а набираем mbuild -setup. Со всем соглашаемся и выбираем нужную нам среду, в нашем случае это MVS 2008 SP1. Получаем что-то похожее:

Please choose your compiler for building standalone MATLAB applications:

Would you like mbuild to locate installed compilers [y]/n? y

Select a compiler:
[1] Lcc-win32 C 2.4.1 in C:\PROGRA~1\MATLAB\R2010a\sys\lcc
[2] Microsoft Visual C++ 2008 SP1 in C:\Program Files\Microsoft Visual Studio 9.0

[0] None

Compiler: 2

Please verify your choices:

Compiler: Microsoft Visual C++ 2008 SP1
Location: C:\Program Files\Microsoft Visual Studio 9.0

Are these correct [y]/n? y


Получаем радостное Done. Все — линкер настроен.

Шаг 2. Пишем m-функцию


Напишем функцию построения 3D-плоскости в заданных граничных условиях, для большего интереса вернем дескриптор функции.

function res=plane(strfunc,vx0,vx1,vy0,vy1,h)
vx=vx0:h:vx1;
vy=vy0:h:vy1;
figure(1)
res=ezsurfc(strfunc,vx,vy);
end


Как видно функция состоит из шести строчек кода, однако выполняет все вышеуказанные действия: в качестве входных параметров принимает символьную функцию (strfunc), начальные и конечные значения векторов границ плоскости (vx0,vx1,vy0,vy1), шаг сетки (h) и возвращает дескриптор (res).
Сохраняем данный код как plane.m.

Важно: компилятор MATLAB'а понимает только функции т.е., каждый сценарий должен начинаться с function (желательно заканчиваться end) и быть отдельным m-файлом.

Шаг 3. Получаем динамическую библиотеку


Набираем в командном окне MATLAB'a deploytool. Создаем новый .NET Assembly проект MATLABplane, указываем размещение.

image

Далее создаем класс planeClass, добавляем в него plane.m и нажимаем кнопку build

image

После успешной компиляции создается интересующая нас библиотека MATLABplane.dll, находиться она будет здесь: ...MATLABplane\distrib\MATLABplane.dll.

Шаг 4. Создаем приложение C#.NET


В MVS 2008 SP1 создаем приложение Windows Forms на С#.

Добавляем ссылки на библиотеки

Перед использованием методов проекта, необходимо добавить ссылки на скомпилированную библиотеку MATLABplane.dll и на библиотеку MWArray.dll, найти ее можно по адресу ...\MATLAB\R2010a\toolbox\dotnetbuilder\bin\win32\v2.0. После добавления должно получиться:

image

Для использования библиотек в проекте необходимо добавить описание пространства имен:

using MathWorks.MATLAB.NET.Utility;
using MathWorks.MATLAB.NET.Arrays;
using MATLABplane;

Создаем форму

С помощью панели инструментов в конструкторе создаем форму будущего приложения.

image

Для создания формы были использованы следующие блоки: Label, TextBox, RichBox, Button.

Пишем код

Для взаимодействия языков программирования C# и MATLAB создан соответствующий типу MATLAB тип данных MWArray C#. MWArray — это массив массивов, он может состоять из переменных, скаляров, векторов, матриц, строк, структур, объектов и т.д. Для получения каких-либо значений из MWArray нужно использовать приведение типов.
Алгоритм работы приложения должен быть следующим:
  1. Получение функции в символьном виде и значений с текстовых полей
  2. Вызов метода plane из класса planeClass
  3. Получение выходного массива descriptor (тип MWNumericArray)
  4. Вывод массива descriptor в RichBox

Ниже представлен полный код с комментариями:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using MathWorks.MATLAB.NET.Utility;
using MathWorks.MATLAB.NET.Arrays;
using MATLABplane;

namespace planeApp
{
  public partial class Form1 : Form
  {
      public Form1()
      {
          InitializeComponent();
          button1.Click += new EventHandler(button1_Click);//инициализация событий
          button2.Click += new EventHandler(button2_Click);
      }

      double x0, x1, y0, y1, h; //объявление переменых
      string func, s_x0, s_x1, s_y0, s_y1, s_h;

      MWArray[] res = null; //выходной массив метода plane
      MWNumericArray descriptor = null; //массив возвращаемого параметра 

      private void button1_Click(object sender, EventArgs e)//событие
      {
          try
          {
              func = textBox1.Text; //считывание с TextBox
              s_x0 = textBox2.Text;
              s_x1 = textBox3.Text;
              s_y0 = textBox4.Text;
              s_y1 = textBox5.Text;
              s_h = textBox6.Text;

              MWCharArray mw_func = new MWCharArray(func);//преобразование строки функции в тип MWCharArray
              x0 = Convert.ToDouble(s_x0); //преобразоване string в double
              x1 = Convert.ToDouble(s_x1);
              y0 = Convert.ToDouble(s_y0);
              y1 = Convert.ToDouble(s_y1);
              h = Convert.ToDouble(s_h);

              planeClass obj_plane = new planeClass(); //экземпляр класса компонента               
              res = obj_plane.plane(1, mw_func, x0, x1, y0, y1, h);//обращение к методу plane, первый параметр - это кол-во возвращаемых аргументов

              descriptor = (MWNumericArray)res[0]; //выбор первого элемента из массива MWArray и преобразование в числовой тип MWNumericArray
              double[,] d_descriptor = (double[,])descriptor.ToArray(MWArrayComponent.Real);//преобразование массива MWNUmericArray  к масииву типа double  

              for (int i = 0; i < d_descriptor.Length; i++)//вывод массива d_descriptor в RichBox
              {
                  richTextBox1.Text += i.ToString() + '\t';
                  richTextBox1.Text += d_descriptor[i, 0].ToString("0.000") + '\n';//преобразование элеметна массива double в string
              }
          }
          catch (Exception ex)//обработка исключения 
          {
              System.Windows.Forms.MessageBox.Show(ex.Message);
          }
      }

      private void button2_Click(object sender, EventArgs e)
      {
          richTextBox1.Text = string.Empty;//очистка RichBox
          res = null;//обнуление массивов
          descriptor = null;
      }
  }
}


Как видим, активно используется приведение типов, по схеме MWArray->MWNUmericArray->тип C#.
Компилируем проект и видим результат:

image

Литература


  1. MATLAB. Программирование на Visual С#, Borland JBuilder, VBA — Н. К. Смоленцев
  2. С# и платформа .NET — Э. Троелсен
Поделиться публикацией

Комментарии 20

    +2
    Спасибо большое за статью :) По лицензированию не подскажите как дела обстоят? Каждому заказчику нужно будет покупать лицензию на матлаб или достаточно фирме-разработчику софта?
      +1
      Фирме-разработчику.
      +4
      а отформатируйте код, пожалуйста.
        0
        Интересно, а как то же самое провернуть с Java? Как раз актуальная задача.
          +6
          2kets
          С лицензированием дела обстоят так: для работы разработанного приложения необходима среда выполнения MCR (MATLAB Component Runtime), которая распространяется свободно и не требует никакой регистрации, ключей и т.д. Соответственно фирме-заказчику необходимо с программой поставить MCR и по необходимости FrameWork 3.5
          2Zenker
          Список поддерживаемых языков .NET, C, C++, Java, add-in Excel. Соответственно при сборке проекта в MATALB необходимо в deploytool выбрать Java Package, а дальше разбираться с синтаксисом, но главное структура MWArray так и останется.
            +1
            Благодарю за информацию
            0
            2asd_lvs: держите лучше исходники: depositfiles.com/files/fusgnazcy
              +1
              существует кнопка ответить :)
              +1
              Чем не устроило использование MATLAB GUI?
              Ожидал увидеть ситуацию, когда его уже не хватает.

              MCRInstaller.exe = ~197 МБ! Когда-то меня это остановило.
              Написал простейшую программку, а весит она ощутимо.

              Очень интересно развитие проекта, если это только его часть!
                0
                Возьмем обратную ситуацию, когда мне не нужно никакое графическое исполнение, а очень сложный обсчет на распознавание образов, плюс после обсчета программа должна выдавать сигнал по COM-порту на объект управления. Это на мой взгляд очень сложно реализовать на одном лишь MATLAB'е или на одном лишь С (openCV в данном контексте не рассматривается), а с помощью этих двух пакетов вполне реально и 197 Мб меня не пугают.
                Оффтопик: По роду деятельности занимаюсь мехатронными системами и на данный момент стоит задача по распознаванию огня как объекта, пока не знаю как подступиться к данной проблеме. Есть мысль, что нужно играть на контрасте или векторизации, буду благодарен за любую помощь.
                  0
                  Я не знаком с С#, С++ и т.д., но довольно давно дружу с MATLAB. Может поэтому и считаю эту систему панацеей)

                  Очень интересно какое железо Вы используете?
                  Полностью уложить все в железо не планируете?

                  Как раз сейчас занимаюсь немного схожей идеей.
                  Распознавание образов — трекинг — выдача информации на внешнее железо — слежение\самонаведение.

                  С радостью обменяюсь с Вами опытом.
                  В личку выслал эмейл.

                  Думаю нам по пути)

                0
                Как обстоят дела с запуском приложения на котором нету MATLAB (к примеру на «чистой» винде)? В свое время это был настоящий геморой и даже MCRInstaller не спасал.
                  0
                  MCRInstaller+FrameWork все работает
                  0
                  А как Simulink-модели интегрировать?
                    0
                    Вам нужно почитать про инструмент Real-Time Workshop
                    0
                    А такой вопрос: рациональное ли (в плане скорости) использовать библиотки матлаба в своем проектк (C++ или C#)?

                    Важна именно скорость. Слышал мнения, что матлаб крайне тормозной, и намного эффективнее будет использовать собственно написанные методы, чем юзать его dll.
                      +1
                      По личному опыту могу сказать что матлаб крайне долго запускает свою среду. Если вам необходимо использовать простенькие функции, то лучше написать самому. Если же речь о чем то более серьезном, то эти накладные расходы будут не так заметны. А так в любом случае всегда быстрее будет использование своих методов, если алгоритм такой же по скорости.
                        0
                        Я как-то так и рассуждал. Спасибо за ответ.
                      0
                      Уважаемый, поставьте, пожалуйста подсветку синтаксиса.
                        0
                        А мы на работе собирали матлабовкий код в сишный с помощью emlc, но его задепрекейтили в matlab 2011 (( Теперь мы имеем codegen, который пока еще очень сырой.

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

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