多線程VC++和Matlab混編在信號采集和處理中的應用





多線程VC++和Matlab混編在信號采集和處理中的應用












作者姓名: 李 寧 秦樹人 吳 瑩
作者單位: 重慶大學測試中心
所屬雜志:《中國測試技術》
所屬期號:2006第3期






要:在信號采集和處理過程中,Visual C++存在數據處理和結果顯示方面的不足,Matlab存在可視化和數據采集方面的不足,本文在Visual C++環境下調用Matlab Engine函數,有效地解決了這兩方面的問題;采用多線程編程技術,同時采集和顯示信號,有效地防止了采樣過程中的掉點。利用本方法對UA302型采集卡采集到的信號進行處理,得到了滿意的結果。



Singal Sampling and Processing Based on Mixed Programming with Multi-Thread VC++ and Matlab


Li Ning,Qin Shuren,Wu Ying


(Test Center, Chongqing University,Chongqing,400044,China)


AbstractIn signal sampling and processing system, VC shows inefficiency in data procession and results demonstration, while Matlab shows its inefficiency in virtualization and data acquisition. In this paper, a mixed programming used by invoking the Matlab engine in VC environment, effectively solved two problems. Multi-thread technology is developed to realize the synchronization of signal sampling and demonstration, and prevent the signal gathering from missing sample spots. An example of an sine wave acquired from UA302 using this using this technique is also introduced in the paper,which has been proved to be feasible in practice.


Key WordsVisual C++,Matlab Engine,Multi-thread technology,UA302





0引言


Visual C++自誕生以來,一直是Windows環境下最主要的應用開發系統,利用Visual C++開發系統可以完成各種應用程序的開發,從底層軟件直到上層直接面向用戶的軟件都可以用Visual C++來開發,而且Visual C++強大的調試功能也為大型復雜軟件的開發提供了有效的排錯手段[1],但是其數值計算能力和二、三維圖形顯示方面卻不理想。Matlab是由MathWorks公司于1984年推出的一套數值計算軟件,其功能十分強大,可以實現數值分析、優化、統計、偏微分方程數值解、自動控制、信號處理、圖像處理等若干個領域的計算和圖形顯示功能[2]。但是,Matlab在實現人機對話、數據的傳輸方面卻不是很方便,將兩者結合起


來,取長補短,發揮兩種語言的優勢,是開發人員研究的一個方向。


1 VCMatlab混合編程的方法:


Visual C++和Matlab混合編程有多種方法[3-7],其中最主要的有以下三種方法:


1.1 在VC++中利用Matlab Engine函數


Matlab Engine函數庫是MathWorks公司提供的一組函數庫,它提供了一種在用戶程序進程中與獨立的Matlab進程通訊的方法,它包括了和Matlab進行交互所必需的全部功能,用戶不用去關心Matlab Engine是如何實現的,只需利用這些函數,開發者就可以方便的操縱Matlab完成所需的功能。具體應用中往往在Visual C++中設計程序框架,以編譯的程序作為前端客戶機,通過調用Matlab Engine在后臺與Matlab服務器建立連接,實現動態通訊。


1.2 利用Matlab豐富的數學函數庫


Matlab中包含內容豐富的數學庫函數,同時它還提供了C語言和C++語言的數學函數接口,從Matab5.1版本開始,MathWorks公司推出了一系列的Matlab自帶編譯器來解決Matlab與C++接口問題,LCC編譯器可以將Matlab的C/C++數學庫編譯成VC++能識別的代碼嵌入VC++環境,用戶可以方便的在VC++的IDE(集成開發環境)中調用這些代碼。


1.3 利用Matcom


Matcom是MathTools公司推出的一個能將M文件轉化成相同功能C++代碼的工具,是為Matlab中的M文件進行高效解釋和調試的集成開發環境,Matcom編譯M文件,先將M文件按照與Matcom的cpp庫的對應關系,翻譯為cpp源代碼,然后用對應版本的C編譯器將.cpp文件編譯成相應的.exe文件。


本文采用的是第一種方法,利用VC++強大的可視化功能編輯應用程序對話框,方便對采集卡的控制,采集數據,在VC++環境中調用Matlab Engine函數,對采集到的數據進行處理,并顯示處理后的圖形。


2 本文所用采集卡簡介[8]


本文采用UA302型USB采集卡,這種采集卡具有16bit的分辨率,滿量程時精度優于0.02%,最高采樣頻率可達100KHz,輸入通道為16或32模入通道,可以采用定時器觸發和軟件觸發兩種觸發方式。UA302采集卡可以使用各種Windows編程工具編程,專用的動態鏈接庫UA300.DLL提供了簡潔高效的采集和控制函數,支持UA302采集卡的各種功能,用戶可簡單方便的調用這些函數完成各種采集工作。本文要用到的采集卡函數:


OpenUA300 打開UA302設備


CloseUA300 關閉UA302設備


minit 單或多通道多點采集初始化(第一種方式)


readdata 單或多通道多點采集(第一種方式)


3 混合編程實例:


3.1 用VC++6.0編寫如圖1所示的基于對話框的應用程序界面


對話框上的Button控件用來控制采集卡采集信號并對其進行處理,以灰色顯示的按鈕在程序運行時不可用,Picture控件用來顯示采集到的信號。



圖1 應用程序界面


3.2本文用到的MatlabEngine函數:


engopen 打開Matlab引擎


engcolse關閉Matlab引擎


mxCreateDoubleMatrix創建雙精度數據類型的Matlab矩陣


engPutVariable向Matlab引擎傳輸一個矩陣


engOutputBuffer創建字符緩沖區以獲取Matlab的文本輸出


engEvalString執行Matlab命令


3.3程序的具體實現:


本程序使用了多線程編程技術,除了主線程外采用了兩個輔線程,一個用來采集信號數據,另一個用來顯示采集到的信號。


采集數據線程程序:


UINT AdoptDataThreadProc(LPVOID pParam)//采集數據線程函數,該線程不能停否則會有漏點


{


//初始化端口,用于單次采樣


minit(husb,0,1,1);


readdata(husb,singleaddata,6000000/SampFrequency,1024);


return 1;


}


繪制波形線程程序:


UINT DrawThreadProc(LPVOID pParam) //該線程負責繪制波形


{


do


{


CDC *pDC=pWnd->GetWindowDC();


CBitmap *m_pBitmap;


CDC *m_pdcmem;


m_pdcmem=new CDC;


m_pBitmap=new CBitmap;


m_pdcmem->CreateCompatibleDC(pDC);


m_pBitmap->CreateCompatibleBitmap(pDC,rect1.right,rect1.bottom);


CBitmap* poldbitmap=m_pdcmem->SelectObject(m_pBitmap);


NCCDraw(m_pdcmem,1);


Sleep(100);


pDC->BitBlt(0,0,rect1.Width(),rect1.Height(),m_pdcmem,0,0,SRCCOPY); m_pdcmem->SelectObject(poldbitmap);


Sleep(1);//可有可無


delete m_pBitmap;


delete m_pdcmem;


pWnd->ReleaseDC(pDC);


}while(1);


return 1;


}


這兩個線程在單擊“采集”按鈕時被啟用,程序如下:


void CVcMatlabDlg::OnBtnAdoptData() //首先打開斷端口,然后再開線程用來采集


{


husb=OpenUA300();


AdoptDataThread=AfxBeginThread(AdoptDataThreadProc,0,THREAD_PRIORITY_NORMAL); DrawThread=AfxBeginThread(DrawThreadProc,0,THREAD_PRIORITY_NORMAL);


GetDlgItem(IDC_BTN_ADOPT)->EnableWindow(FALSE);


GetDlgItem(IDC_BTN_STOP)->EnableWindow(TRUE);


}


用上面的程序采集頻率為1000Hz的正弦信號后的圖形如圖2:



采集到的數據在單擊“FFT”按鈕時被處理,Matlab Engine就是在這個函數里被調用的,程序如下:



圖2 采集到的正弦信號


void CVcMatlabDlg::OnBtnFft()


{


// TODO: Add your control notification handler code here


Engine *ep;


mxArray *X=NULL;


mxArray *Num=NULL;


mxArray *Frequency=NULL;


char buffer[1024];


if (!(ep=engOpen("\0")))


//打開Matlab引擎,建立與本地Matlab的連接


{


AfxMessageBox("Can't start MATLAB engine!");


exit(-1);


}


//參與matlab運算的參數都是矩陣形式,因而要將參數轉換為Matlab可接收的矩陣形式


X=mxCreateDoubleMatrix(1,1024,mxREAL);


Num=mxCreateDoubleMatrix(1,1,mxREAL);


Frequency=mxCreateDoubleMatrix(1,1,mxREAL);


double var1=(double)SampNum;//強制轉換SamNum和SampFrequency從short到double


double var2=(double)SampFrequency;


memcpy((double*)mxGetPr(Num),(double*)&var1,sizeof(double));


memcpy((double*)mxGetPr(Frequency),(double*)&var2,sizeof(double));


double var3[1024];


for (int i=0;i<1024;i++)


{


var3=(double)(singleaddata/1);


} memcpy((char*)mxGetPr(X),(char*)var3,1024*sizeof(double));



//將轉換的參數放入引擎中,可在Matlab commond窗口下察看參數值


engPutVariable(ep, "X", X);


engPutVariable(ep, "Num",Num);


engPutVariable(ep, "Frequency", Frequency);


//下面開始執行MATLAB命令


engEvalString(ep,"pxx=fft(X,Num);");//engEvalString()函數是在vc中執行matlab函數


engOutputBuffer(ep,buffer,1024);


engEvalString(ep,"ff1=-Frequency/2:1/Num*Frequency:Frequency/2-Frequency/Num;");


engEvalString(ep,"subplot(2,1,1);");


engEvalString(ep,"plot(ff1,fftshift(abs(pxx)));");


engEvalString(ep,"title('信號頻譜圖')");


engEvalString(ep,"xlabel('頻率/Hz')");


engEvalString(ep,"ylabel('幅值譜')");


engEvalString(ep,"p=pxx.*conj(pxx)/1024");


engEvalString(ep,"ff2=Frequency*(0:511)/1024;");


engEvalString(ep,"subplot(2,1,2);");


engEvalString(ep,"plot(ff2,p(1:512));");//利用引擎畫圖


engEvalString(ep,"title('信號功率譜圖')");


engEvalString(ep,"xlabel('頻率/Hz')");


engEvalString(ep,"ylabel('功率譜密度')");


mxDestroyArray(X);//釋放內存


mxDestroyArray(Num);


mxDestroyArray(Frequency);


engClose(ep);//關閉引擎,圖片隨之關閉


GetDlgItem(IDC_BTN_FFT)->EnableWindow(FALSE);


}


編譯運行程序后,對圖2所示的正弦信號進行處理,得到的圖形如圖3:


圖3 分析后的頻域波形


4 結束語


在Visual C ++中利用多線程編程可以同時采集和顯示采集卡采集到的信號,防止采集過程中的掉點;調用Matlab Engine函數可以發揮兩者的優勢,利用Visual C++強大可視化功能,方便的對采集卡進行控制,利用Matlab Engine強大的數據處理能力,對采集到的數據進行數字信號處理,并可以方便的顯示處理后的結果。



參考文獻:


[1]David J.Kruglinski著.潘愛民,王國印譯. Visual C++技術內幕[M]. 北京:清華大學出版社,1998


[2]董長虹主編. Matlab信號處理及應用[M]. 北京:國防工業出版社,2005.1


[3] 何曉濤,于春田. VC調用Matlab的方法[J].河北科技大學學報,2003,24(1):35-39


[4] 王安紅,孫志毅. 一種VC++與Matlab混合編程的實現方法[J]. 計算機應用與軟件,2003,20(6):12-13,77


[5]高崇明. VC++6.0與Matlab混合編程技術的原理與實現[J]. 無線電工程,2000,30(2):53-56


[6]肖永韌. VC與Matlab混合編程之DLL實現方法[J]. 計算機工程與應用,2001(13):174-176


[7]4亓波. 實現VC++6.0與Matlab的混合編程[J]. 電腦編程技巧與維護,2000(12):62-64


[8] UA302/H型A/D采集器使用說明




基金項目:重慶市重點科技項目(合同號:9293)


作者簡介:李寧, 男,1980年生,重慶大學機械工程學院博士研究生,研究方向:智能測試及虛擬儀器技術






頁面功能 【我來說兩句】【字體:

登錄后免費查看全文
立即登錄
App下載
技術鄰APP
工程師必備
  • 項目客服
  • 培訓客服
  • 平臺客服

TOP