全國最多中醫師線上諮詢網站-台灣中醫網
發文 回覆 瀏覽次數:1979
推到 Plurk!
推到 Facebook!

在Borland C++ 中引用Matlab的函式庫時發生的問題?

尚未結案
joeabcyes
一般會員


發表:9
回覆:2
積分:2
註冊:2004-07-15

發送簡訊給我
#1 引用回覆 回覆 發表時間:2004-07-17 18:55:10 IP:218.166.xxx.xxx 未訂閱
以下我先附上版主的兩個方法 最後面才有我的問題 第一個方法: Borland C++Builder是一種新穎的可視化編程語言。 在工程應用中,我們一般用C++Builder語言編寫應用程序,實現交互界面、數據 採集和端口操作等,但C++Builder在數值處理分析和算法工具等方面,其效率遠 遠低於Matlab語言。在準確方便地繪製數據圖形方面,Matlab語言更具有無可比 擬的優勢。此外,Matlab還提供功能強大的工具箱。但Matlab的缺點是不能實現 端口操作和實時控制。因此,若能將兩者結合運用,實現優勢互補,將獲得極大的 效益。     本文結合實際介紹了應用Borland C++Builder3.0開發的Windos應用程序 中,對Matlab的調用方法。     一、C++Builder調用Matlab的實現方案      1. 實現思路     在高版本的Matlab中(如Matlab V4.2)提供了DDE接口,用戶可以通過 Windows的DDE通信基制實現外部調用。這種實現方式比較簡單,但將增大主程序 代碼,影響運行速度。     在Windows系統中,DLL是一種很特別的可執行文件,可以被多個Windows應用 程序同時訪問,具有固定的共享數據段。該數據段的數據在DLL被Windows下載前 會一直保留在內存中,因此可以通過DLL實現用戶程序與Matlab之間的數據傳輸和函數調用。     具體地說,就是利用Matlab的32位動態連接庫(DLL),生成相應的可以被 C++Builder調用的DLL,用來提供二者之間的基本支撐環境。只需在用戶程序中 加載該DLL,即可實現其數據段的共享。然後在用戶程序中操作DLL數據段的數 據,並通過某種方式在用戶程序中使Matlab執行該DLL,就可實現用戶程序對 Matlab的調用。其形式可以是混合編程或函數調用,非常方便而高效。     2. 實現方式     Matlab提供了可外部連接的DLL文件,通過將其轉換為相應的Lib文件,並加 以必要的設置,就可以在C++Builder中直接進行Matlab函數調用,實現C++  Builder語言與Matlab語言的混合編程。     (1) 運行環境要求     由於Matlab提供的是32位的DLL。其運行環境要求是Matlab V4.2或更高版 本。C++Builder可以進行32位編程,這裡我們採用的是V3.0版本。     (2) C++Builder下LIB文件的生成     Matlab提供的Def文件允許用戶通過Implib命令生成相應的Lib文件。其命令格式為 Implib ???.lib ???.def     在\extern\include目錄下,提供了如下三個.Def文件:     _libeng.def,_libmat.def,_libmx.def     通過上述命令可以生成相應的三個Lib文件。這些Lib文鹼中包含了可外部調用的Matlab函數的必要信息。     二、實現計算和繪圖     為清楚起見,通過一個簡單的CBuilder例程進行說明。該實例通過調用 Matlab實現矩陣運算並繪製圖形,來演示C++Builder對Matlab的調用。     在C++Builder編輯環境中,建立一個新的窗體MyForm,並放置一個按鈕Demo。將工程文件命名為Try.prj,其主函數為try.cpp。在主函數中,我們將使 用一個實現Matlab調用的子函數DemoMatlab,作為按鈕Demo的響應事件。其源代 碼如下:    #include  #pragma hdrstop #include "Unit1.h" #pragma package(smart_init) #pragma resource "*.dfm" TMyForm *MyForm; __fastcall TMyForm::TMyForm(TComponent* Owner) : TForm(Owner) { } void __fastcall TMyForm::DemoClick(TObject *Sender) { DemoMatlab(); //演示Matlab語言調用 }      為了調用Matlab中的函數,必須進行必要的設置,將包含這些函數的文件加 入工程文件Try.prj。以下是操作過程:     1. 在頭文件中加入Engine.h。其包含了啟動Matlab調用和關閉的函數聲明。     2. 打開Project|Option...對話框,點擊Directories/Conditionals。     ● 在Include Path中,加入目錄路徑\extern\include,該路徑包含了engine.h和matlab.h等有用的頭文件。 ● 在Library Path中,加入\bin和\extern\include。這兩個目錄路徑包含 了可外部調用的DLL和LIB文件。     3. 點選Project|Add to Project...對話框,加入如下庫文件:     _libeng.lib,_libmat.lib和_libmx.lib。     在進行了這些必要的設置之後,我們就可以選用適當的函數來實現目標。 以下是子函數DemoMatlab的程序代碼。    void DemoMatlab { Engine *eng; //定義Matlab引擎 char buffer[200]; //定義數據緩衝區 int array[6]={1,2,3,4,5,6}; mxArray *S = NULL, *T = NULL; engOpen(NULL); //打開MATLAB 引擎 ---1 S= mxCreateDoubleMatrix(1,6, mxREAL); // 產生矩陣變量 mxSetName(S, "S"); memcpy((char*) mxGetPr(S),(char *) array, 6*sizeof(int)); engPutArray(eng, S); //將變量X置入Matlab的工作空間 engEvalString(eng, "T = S/S.^2;"); //計算 engEvalString(eng, "plot(S, T);"); //繪製圖形 …… …… engOutputBuffer(eng, buffer, 200); //獲取Matlab輸出 T = engGetArray(eng, "T"); //獲得計算結果----2 engClose(eng); //關閉Matlab引擎,結束調用 mxDestroyArray(S); //釋放變量 mxDestroyArray(T); }      若還需要執行其他功能和任務,那麼按照上面介紹的方法,進行變量聲明後, 在1、2處加寫需要的語句即可。     當然,使用這種方法調用Matlab不能脫離Matlab環境的支撐。但當我們不需 要看到Matlab的命令窗口時,可將其賦      /*生活是一種藝術,用心生活才能享受生活*/    發表人 - axsoft 於 2004/01/06 10:53:17    --------------------------------------------------------------------- 第二個方法: C++Builder與Matlab混合編程的實現     作者:中國大陸-長沙 張雲洲 資料來源: http://bcbdev.myrice.com/bcjq/bcjq041.htm    --- 在C++Builder中調用Matlab工具箱涵數,有兩種實現方式。一種是基於Matlab環境支持,通過必要的設置實現;筆者在本刊上曾撰文對這種方式進行了專門的闡述。另一種則是完全脫離Matlab環境,通過動態連接庫方式實現對Matlab工具箱涵數的調用,這可以通過一種開發平台Mediva來實現。相對來說,前者的限制因素較多,而後者則較為方便靈活。     一、Mediva軟件平台     ---- Mediva是Mathtools公司推出的一種Matlab編譯開發軟件平台,提供對Matlab程序文件(M文件)的解釋執行和開發環境支持。該軟件有為Borland C++、Visual Basic和Dephi等編程語言開發的不同版本,目前其版本已經到了4.5版。軟件大小僅6.5M,可以通過訪問其站點www.mathtools.com免費下載試用一個月。 Mediva軟件平台本身的功能相當強大,提供近千個Matlab的基本功能函數,通過必要的設置,就可以直接實現與C++的混合編程,而不必再依賴Matlab;同時,Mediva還提供編譯轉換功能,能夠將Matlab函數或編寫的Matlab程序轉換為C++形式的DLL,從而實現脫離Matlab環境對Matlab函數和過程的有效調用,這樣就有可能實現對Matlab強大的工具箱涵數的利用。     ---- Mediva的缺點是C++與Matlab混合編寫的應用軟件必須攜帶必要的DLL,從而增大了軟件的體積(約4M),同時也不能對所有的Matlab函數提供支持,例如採用類庫進行設計的部分函數。但儘管如此,對於控制系統計算機設計、分析的工作來說,Mediva仍不失為一個好的工具。     ---- 由於利用Mediva將Matlab工具箱涵數轉換成DLL的內容較多,限於篇幅本文在此僅給出對Matlab函數直接調用的實現,而將另撰文闡述DLL的實現。     二、C++Builder直接調用Matlab函數     ---- 本文假設已經安裝了Mediva軟件或已經得到必要的兩個動態連接庫mdv4300.dll和ago4300.dll。     ---- Mediva提供的近千個Matlab基本功能函數,都可以在C++Builder中直接調用。這些函數包括基本的操作、命令、I/O、線性代數、位圖、控制等,基本上可以滿足我們的一般需要。當然其最大的優點就是可以直接在C++Buider中直接調用而不必考慮安裝龐大的Matlab。         ---- 其實現方式和步驟如下:     ---- 1.Lib文件的生成     ---- 在Dos下用C++Builder中的Implib.exe,通過如下命令生成mdv4300.lib: implib mdv4300.lib mdv4300.dll     ---- 將上述兩個DLL文件和此Lib文件拷貝到當前目錄下。     ---- 2.實現與Matlab的混合編程     ---- Matlab.h包含了Mediva中所有類型、常量、函數的說明和定義,必須將此頭文件放於程序的第一行。Mediva給出的Matlab函數形式並不特殊,如繪線函數Plot,在Mediva中說明為:Mm DLLI plot(cMm varargin);varargin與Matlab 中的意義是一樣的,與輸入變量的個數相對應。所有可以直接使用的函數都在Matlib.h頭文件中定義,而在mdv4300.dll中實現。     ---- 但在C++Builder中使用Mediva提供的Matlab函數的格式,與Matlab編程稍有不同,這主要體現在C++中必須進行必要的說明上。例如我們要用繪線函數Plot來繪製數組x[100]的紅色圖線。在Matlab中調用為Plot(x,'r');在C++中調用則為:Plot(CL(x),TM("r")),其中CL是一個關鍵字,是多變量輸入時所必須使用的,用以指明調用的變量;而TM則指明,這是一個字符。     ---- 下面我們給出一個示例程序,其功能是對一個1024點的輸入數組進行FFT 變換,並繪製變換後頻譜實部的火柴桿圖,最後將原數據和變換後的數據寫入數據文件中。         #include "matlib.h"  //必須包含的頭文件 #include < vcl.h > #pragma hdrstop    #include "TryMatcomU.h" #pragma package(smart_init) #pragma resource "*.dfm" TForm1 *Form1; __fastcall TForm1::TForm1(TComponent* Owner) : TForm(Owner) { } void __fastcall TForm1::Button1Click(TObject *Sender) { int k=0; initM(MATCOM_VERSION); //必須進行的初始化 Mm cur1,cur2;  //定義變量 cur1=zeros(128); cur2=zeros(128); //變量初始化     for (k=1;k< =128;k++)    cur1.r(k)=randM(); //生成一個隨機數列 figure(1); plot(cur1);//圖形顯示該數列  cur2=fft(cur1,128); //做128點fft變換  figure(2);  //繪製fft變換後實部的火柴桿圖,注意此處多變量輸入的格式  stem((CL(cur1),real(cur2),TM("r")));   fid=fopen(filename,mode,format) opens   exitM();  //退出調用 }    ---- 如果完全使用C++來實現本程序的工作,其代碼將超過300行!由此可以看出,C++Builder與Matlab函數的混合編程可以給我們帶來多麼大的方便!  ---- 3.變量內部狀態/數據的觀察方法     ---- Mediva使用的所有變量均定義為Mm類型。如果在C++Builder中觀察Mm類型變量的內部狀態/數據,要稍麻煩一些。但在調試程序時,這又是不可避免的一步,這裡舉例給出變量觀察的方法。     ---- 例如對上面生成的cur2數列進行觀察,  ---- *cur2.pr 0.1892 cur2(1)的實部  ---- *cur2.pi 0.0013 cur2(1)的虛部     三、C++Builder調用Matlab工具箱涵數轉換後的DLL     ---- 1.Matlab函數向DLL的轉化     ---- Mediva軟件提供了將Matlab函數轉換為DLL的功能,非常方便。但需要注意的是:     ---- 1.Matlab5.0以上版本,所有帶有tf類的函數均無法轉換;     ---- 2.Matlab4.2以下版本,多數函數能夠轉換,但轉換後大多不能直接使用,而必須加以處理。     ---- MATCOM V4.3中把含有輸入參數的M文件轉換成DLL時,生成的DLL無法調用.以.M為例,         ---- function [x1,x2]=flower(x3)     ---- MATCOM生成的FLOWER.CPP和FLOWER.H中聲明為:     Mm flower(Mm x3, i_o_t, Mm& x1__o, Mm& x2__o) { begin_scope x3.setname("x3");  ...  }    Mm flower(Mm x3); Mm flower(Mm x3, i_o_t, Mm& x1__o, Mm& x2__o); 而生成的G_FLOWER.CPP聲明為:    ---- void DLLX _stdcall flower_1_1(Mm** in01, Mm **out01)     ---- void DLLX _stdcall flower_1_2(Mm** in01, Mm **out01, Mm **out02)     ---- 其中對於in01的說明是不正確的.應按如下修改。然後,按如下MAKE文件進行編譯。     # # MATCOM makefile #    all: flower.dll    g_flower.obj: g_flower.cpp bcc32 -c -Id:\matcom43\ -WD -Id: \matcom43\lib -H=matlib.csm -a4 -5 -eg_flower.obj g_flower.cpp    flower.dll: flower.obj g_flower.obj  bcc32 -Ld:\matcom43\ -WD -Id: \matcom43\lib -H=matlib.csm -a4 -5 -eflower.dll @flower.rsp d:\matcom43\lib\mdv4300b.lib    ---- 在CPP中調用這個函數之前,一定要先給in01分配空間。      #include "matlib.h" #pragma hdrstop #include "flower.h" #define WIN32_LEAN_AND_MEAN #include < windows.h > #include "matlib.h" #pragma hdrstop extern "C" { void DLLX _stdcall flower_1_1(Mm in01, Mm **out01) { *out01=new Mm();  //*in01=new Mm(); **out01=flower(in01); exitM(); } void DLLX _stdcall flower_1_2(Mm in01, Mm **out01, Mm **out02) { *out01=new Mm(); *out02=new Mm();  //*in01=new Mm();  flower(in01, i_o , **out01, **out02); exitM(); }    /*生活是一種藝術,用心生活才能享受生活*/    -------------------------------------------------------------------- ------------------------------------------------------------------------------------------------------------------------------------------ 以下是我的問題: 第一個方法我有照作了 可不知道為什麼出不來 圖檔的問題可以幫我解釋一下嗎? 謝謝 第一個問題:(我不大會上傳圖片,好像怪怪的,要點一下下面才會展開) 第二個問題:(我不大會上傳圖片,好像怪怪的,要點一下下面才會展開) 還有第二個方法 請問一下 哪裡可以找到那個軟件 mdv4300.dll和ago4300.dll 發表人 - joeabcyes 於 2004/07/17 18:58:40
joeabcyes
一般會員


發表:9
回覆:2
積分:2
註冊:2004-07-15

發送簡訊給我
#2 引用回覆 回覆 發表時間:2004-07-21 14:38:52 IP:218.166.xxx.xxx 未訂閱
有人可以幫忙一下嗎?
paf
初階會員


發表:36
回覆:70
積分:41
註冊:2002-12-27

發送簡訊給我
#3 引用回覆 回覆 發表時間:2004-08-30 04:19:38 IP:218.164.xxx.xxx 未訂閱
引言: 有人可以幫忙一下嗎?
#define V5_COMPAT
#include 
一定要在engine.h前面加上紅色那行!!! 發表人 - paf 於 2004/08/30 04:20:59
chewchew
一般會員


發表:1
回覆:2
積分:0
註冊:2004-05-02

發送簡訊給我
#4 引用回覆 回覆 發表時間:2004-09-12 02:01:20 IP:140.113.xxx.xxx 未訂閱
請問一下,我也是用方法一,也加了檔頭..可是一樣有出現同一個問題 那有別的可能的問題嗎?
香草臭豆腐
一般會員


發表:0
回覆:4
積分:0
註冊:2005-01-14

發送簡訊給我
#5 引用回覆 回覆 發表時間:2005-03-01 19:24:20 IP:211.75.xxx.xxx 未訂閱
我也遇過這個問題, 原因是matlab引擎開啟失敗 你可以在engOpen(NULL)那一行 改寫成 if(!engOpen(NULL)) { ...... } 確認一下引擎開啟是否成功.
peterfrog
一般會員


發表:0
回覆:2
積分:0
註冊:2005-03-25

發送簡訊給我
#6 引用回覆 回覆 發表時間:2005-06-02 11:37:35 IP:61.224.xxx.xxx 未訂閱
請問前輩,我猜是引擎開啟不成功,有什麼辦法可以解決嗎? 謝謝您
系統時間:2024-11-23 13:30:28
聯絡我們 | Delphi K.Top討論版
本站聲明
1. 本論壇為無營利行為之開放平台,所有文章都是由網友自行張貼,如牽涉到法律糾紛一切與本站無關。
2. 假如網友發表之內容涉及侵權,而損及您的利益,請立即通知版主刪除。
3. 請勿批評中華民國元首及政府或批評各政黨,是藍是綠本站無權干涉,但這裡不是政治性論壇!