Программирование на языке С для пакета MATLAB [часть 3] - Программирование - Каталог статей по программированию - Студия перевода Нуреева Александра
Форма входа
E-mail:
Пароль:
Категории раздела
Программирование [4]
Статьи по программированию по C, C++, Delphi, FoxPro, Assmbler и т.д. Инструкция по Visual Studio .NET.
Поиск
Главная » Статьи » Программирование

Программирование на языке С для пакета MATLAB [часть 3]
ЧАСТЬ 3

Перейти к Части 4 >>
Программирование на языке С для пакета MATLAB

В следующем параграфе будет детально рассказано как скомпилировать реальное Win32 console-приложение на базе представленного текста, которое составляет содержимое файла main.с. Это единственный исходный файл, необходимый для компиляции. Там же будет рассказано, как следует отлаживать такое приложение.

Сейчас же покажем, как выглядит окно приложения после того, как все вычисления будут произведены (см. рис. 13.1):

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

Весь представленный выше код достаточно очевиден после того, как мы кратко описали предназначение всех функций библиотеки MATLAB Engine. Помимо них еще используются функции с префиксом mx, большинство из которых нам также хорошо известно, так как мы достаточно потренировались с ними на примерах из предыдущей главы.

Однако есть все-таки одна новая функция, на которой следует остановить свое внимание. Это функция mxSetName, которую мы только что использовали в представленном выше примере. Это очень важная функция. Можно сказать, что эта функция нивелирует некоторое принципиальное различие между миром программ на языке С и миром программ на М-языке. В первом из них (то есть в мире С-программ) объекты типа mxArray (массивы системы MATLAB) адресуются указателями, которых нет вообще в М-языке. А в мире программ на М-языке есть только обычные имена для массивов. Так вот функция mxSetName и призвана снивелировать это различие, точнее перебросить мостик между двумя способами обращения к массивам (матрицам) в этих двух мирах.

Фрагмент из вышеприведенной программы

// Create real matrix
pArr = mxCreateDoubleMatrix( 3, 2, mxREAL ); mxSetName( pArr, "A" );

показывает, что сначала создается массив 3x2 и он адресуется указателем pArr. После этого с помощью функции mxSetName для массива вводится "человеческое" (в отличие от использования "нечеловеческих" указателей в языке С) имя А. Когда позже этот массив будет внедрен в рабочее пространство системы MATLAB для дальнейшей его обработки, то сама эта обработка в рабочем пространстве системы MATLAB будет происходить над переменной с именем А. Вот соответствующий фрагмент кода:

engPutArray( pEng, pArr );
engEvalString( pEng, "Vec = eig( A*A')" );
pV = eng6etArray( pEng, "Vec" );

Здесь в первой строке массив, адресуемый в С-коде указателем pArr, внедряется в рабочее пространство системы MATLAB, где с ним уже работают как с переменной А, что прекрасно видно из второй строки фрагмента. Далее, поскольку результат вычислений поименован там как Vec, то именно под этим именем мы и извлекаем его назад из рабочего пространства функцией engGetArray. Результат такого извлечения, то есть некоторая область памяти, далее адресуется в С-коде указателем pV.

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

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

Отметим один более-менее очевидный недостаток в коде первого примера, для чего воспроизведем следующий фрагмент:

engEvalString( pEng, "Vec = eig( A*A')" );
pV = engGetArray( pEng, "Vec" );
// Stop Engine session: engClose( pEng );
// Get double values from
// possibly complex mxArray v: pReal = mxGetPr( pV );

Первой строкой здесь запрашивается выполнение некоторого действия в рабочем пространстве системы MATLAB. Результат этого действия извлекается с помощью функции engGetArray. Но что будет, если в процессе выполнения запрошенной операции произошла ошибка? Тогда невозможно получить правильное значение для указателя pV, адресующего результат вычислений. Из-за этого функция mxGetPr, использующая этот указатель, отработает с ошибкой.

С одной стороны, этот недостаток представленного кода легко исправить. Для этого надо лишь перед использованием указателя pV проверять его на равенство значению NULL:

if( pv != NULL )
pReal = mxGetPr( pV );

и тогда все будет работать безошибочно.

Однако остается проблема получения диагностической информации об ошибках, которая всегда выводится в командное окно системы MATLAB. Пусть, к примеру, для вычисления собственных значений выбрана неквадратная матрица. Вот что при этом мы наблюдаем в командном окне системы MATLAB (см. рис. 13.2):

Задачей второго примера будет передача этой диагностической информации в распоряжение С-кода приложения типа MATLAB Engine. Как мы уже рассказывали выше, для этой цели служит функция engCmtPutBuffer. Она задает буфер в памяти, куда и будут поступать сообщения из системы MATLAB.

Добавим в код первого примера несколько строк кода, которые позволят отслеживать ошибочные ситуации, возникающие в процессе вычислений в рабочем пространстве системы MATLAB, а также позволят получить всю диагностическую информацию оттуда. Чтобы не возникло недоразумений и сложностей в восприятии нового варианта текста из первого примера, приведем весь этот код в полном объеме:

#include
#include
#include
#include "engine.h"
#define BUFSIZE 256
double data[6] = {1,2,3,4,5,6};
int main( void )
{
Engine* pEng = NULL;
mxArray* pArr = NULL;
mxArray* pV = NULL;
double* pReal = NULL;
double* plmage = NULL;
int M, i;
char pBuf[BUFSIZE];
// Start Engine session: pEng = engOpen( NULL ); if( pEng == NULL )
{
printf( "\nCan't start Engine session 1" );
return 2;
}
// Create real matrix
pArr = mxCreateDoubleMatrix( 3, 2, mxREAL ); if( pArr == NULL )
{
printf("\nCan't create matrix!");
return 1;
}
mxSetName( pArr, "A" );
// Set its elements:
memcpy( mxGetPr( pArr ), data, 6*sizeof(double) );
// Put array into MATLAB environment // and calculate eigen values of it:
engPutArray( pEng, pArr );
engOutputBuffer( pEng, pBuf, BUFSIZE );
engEvalString( pEng, "Vec = eig( A*A')" );
pV = engGetArray( pEng, "Vec" );

// Stop Engine session:
engClose( pEng ); // Let's see the OutputBuffen
printf( "%e", pBuf );
// Get double values from // possibly complex mxArray v: if( pV != NULL ) {
pReal = mxGetPr( pV ); pImage = mxGetPi( pV ); M = mxGetM( pV );
// Print results:
printf("Real parts of eig vector\n");
for( i=0; i {
printf("%lf\n", pReal[i] ); }
if( plmage )
{
printf("\nImage parts of eig vector\n");
for( i=0; i< M; i++)
{
printf("%lf\n", pImage[i] );
}
}
}
// Free mxArray memory buffers: mxDestroyArray( pArr ); if( pV != NULL ) mxDestroyArray( pV );
// Screen delay:
printf("Press any key to exit");
getch();
return 0;
}

В этот текст включены все проверки указателей на равенство их значению NULL, но самое главное изменение заключается в применении функции engOutputBuffer.

Эту функцию нужно вызвать перед вызовом функции engEvalString, в результате чего весь вывод информации в командное окно системы MATLAB будет продублирован в заранее приготовленный буфер нашей С-программы:

engOutputBuffer( pEng, pBuf, SIZEBUF );
Буфер размером SIZEBUF адресуется указателем pBuf. Третий параметр этой функции задает число байт информации, которое будет направлено в буфер. Если размер диагностической информации, выводимой в командное окно системы MATLAB, будет больше, чем заданное нами число SIZEBUF, то ничего страшного не произойдет: в соответствии со сказанным только первые SIZEBUF байт будут скопированы в предоставленный буфер памяти. Также никаких проблем не возникает, если реально переданное число байт информации будет меньше, чем истинный размер буфера.

На рисунке 13.3 показано окно разработанного приложения с выведенной в него информацией из рабочего пространства системы MATLAB:

В случае штатной ситуации, когда вычисления в рабочем пространстве системы MATLAB осуществляются корректно, вывод информации, предоставленной функцией engOutputBuffer, бывает излишним, что и видно из последнего рисунка.

Чтобы не было избыточной информации, распечатку буфера лучше осуществлять после проверки наличия ошибочных ситуаций. Вот единственное изменение кода, которое потребуется для этого:

if( pV == NULL )
printf( "%s", pBuf );

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

engEvalString( pEng, "Vec = eig( A )" );
(которое следует подставить в приведенный выше код второго примера вместо вызова функции engEvalstring с правильным выражением), то в окно нашего приложения поступит уже крайне полезная информация об ошибочной ситуации, так как других способов продиагностировать ее нет (см. рис. 13.4):

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

#include
#include
#include
#include "engine.h"
double data[10] = { 0.1,0.2,0.3,0.4,0.5,0.6,0.7,0.8,0.9,1.0 };
int main( void )
{
Engine* pEng = NULL;
mxArray* pArr = NULL;

// Start Engine session: pEng = engOpen( NULL );
if( pEng == NULL )
{
printf( "\nCan't start Engine session!" ); return 2;
}
//
// Create real vector
pArr = mxCreateDoubleMatrix( 1, 10, mxREAL );
if( pArr == NULL )
{
printf("\nCan't create vector !"); return 1;
}
mxSetName( pArr, "x" );
// Set its elements:
memcpy( mxGetPr( pArr ), data, 10*sizeof(double) );
// Put vector into MATLAB environment
// and calculate y-sin(x). Then plot graph:
engPutArray( pEng, pArr );
engEvalString( pEng, "y » sin( x );plot(xry);" );
// Free mxArray memory buffers:
mxDestroyArray( pArr );
// Screen delay:
printf("Press any key to exit"); getch();
// Stop Engine session: engClose( pEng ); return 0;
}

После запуска на выполнение нашего приложения система MATLAB породит следующее графическое окно (см. рис. 13.5):

Обратите внимание на то, что закрытие сессии (сеанса) MATLAB Engine функцией engClose следует осуществлять после вызова функции getch, осуществляющей ожидание ввода с клавиатуры, тем самым обеспечивающей пользователя достаточным временем для наблюдения графических изображений. После же вызова функции engClose приложение MATLAB заканчивает работу и закрывает все свои графические окна.



Перейти к Части 4 >>

Другие материалы по теме
Категория: Программирование | Добавил: rusoft (2006-11-12) | Автор: Н.Н. Мартынова
Просмотров: 731 | Рейтинг: 0.0/0 |
Всего комментариев: 0
Имя *:
Email:
Код *:
Пятница, 2010-07-30, 19:24:26
Приветствую Вас Гость
Наш опрос
Как вам новый дизайн?
Всего ответов: 325
Мини-чат
200
Друзья сайта
  • Создать сайт
  • Все для веб-мастера
  • Программы для всех
  • Мир развлечений
  • Лучшие сайты Рунета
  • Кулинарные рецепты
  • Статистика

    Онлайн всего: 2
    Гостей: 2
    Пользователей: 0