Click here to Skip to main content
15,881,588 members
Articles / Programming Languages / C#

1..2..3 ways of integrating MATLAB with the .NET

Rate me:
Please Sign up or sign in to vote.
4.82/5 (62 votes)
18 Nov 20037 min read 563K   26.1K   127  
A library to access MATLAB from .NET and a comparision of three possible methods to implement it.
// Matlab Interface Library
// by Emanuele Ruffaldi 2002
// http://www.sssup.it/~pit/
// mailto:pit@sssup.it
//
// Description: DDE Matlab Library
using System;
using System.Text;

namespace DDEMATLib
{
	/// <summary>
	/// Specialized Support class for MATLAB DDE
	/// - get/set matrix as string or as double [,] vectors
	/// - evaluate with/without string result
	/// 	
	/// </summary>
	public class DDEMatlab : DDELibrary.DDEClient, MATLibrary.MATAccess
	{
		/// <summary>
		/// Construct a default DDE connection that uses XLTABLE
		/// </summary>
		public DDEMatlab() : this(false, true)
		{
		
		}

		/// <summary>
		/// Construct a MATLAB DDE connection letting choose the
		/// format and the write mode
		/// </summary>
		/// <param name="usePOKE"></param>
		/// <param name="useXLTABLE"></param>
		public DDEMatlab(bool usePOKE, bool useXLTABLE)
		{
			this.usePOKE = usePOKE;
			this.useXLTABLE = useXLTABLE;
			Open();
			itemEval = CreateStringItem("EngEvalString");
			itemEvalResult = CreateStringItem("EngStringResult");
		}

		/// <summary>
		/// Open the connection
		/// </summary>
		/// <returns></returns>
		public bool Open()
		{
			if(IsOpen) return true;
			channel = OpenChannel("Matlab", "Engine");
			if(channel == null) return false;
			channel.Timeout = 15000;
			return true;
		}

		/// <summary>
		/// Gets a matrix variable 
		/// </summary>
		/// <param name="name">name of the matrix</param>
		/// <param name="data">the matrix, preallocated or not</param>
		/// <returns></returns>
		public bool GetMatrix(string name, ref double [,] mtx)
		{
			if(!IsOpen) return false;
			
			if(!useXLTABLE)
			{			
				string s = GetVariable(name);
				if(s == null) return false;
				return StringToMatrix(s, ref mtx);
			}
			else
			{
				// get variable as XLTable
				byte [] x;
				DDELibrary.DDEItem di = CreateStringItem(name);
				bool r;
				r = Channel.RequestXL(di, out x, Channel.Timeout);
				DestroyStringItem(di);				
				if(r && x != null) 				
				{
					if(BuggedMATLABXLTable)
						return BytesToMatrix(x, ref mtx);
					else
						return DDELibrary.XLTable.BytesToMatrix(x, ref mtx);
				}
				else
					return false;
			}
		}

		/// <summary>
		/// Gets a variable in string format
		/// </summary>
		/// <param name="name"></param>
		/// <returns></returns>
		public string GetVariable(string name)
		{
			string r;
			if(!IsOpen) return null;
			if(Channel.Request(name, out r))
			{
				return r;
			}
			else
				return null;
		}

		/// <summary>
		/// Puts a variable value using POKE
		/// </summary>
		/// <param name="name"></param>
		/// <param name="data"></param>
		/// <returns></returns>
		public bool PutVariable(string name, string data)
		{
			if(!IsOpen) return false;
			return Channel.Poke(name, data);
		}

		/// <summary>
		/// Sets a Matrix variable
		/// </summary>
		/// <param name="name"></param>
		/// <param name="data"></param>
		/// <returns></returns>
		public bool PutMatrix(string name, double [,] mtx)
		{
			if(!IsOpen) return false;
			if(usePOKE) 
			{
				if(useXLTABLE)
				{
					byte [] q;
					bool r;
					DDELibrary.DDEItem di = CreateStringItem(name);
					DDELibrary.XLTable.MatrixToBytes(mtx, out q);
					r = Channel.PokeXL(di, q, Channel.Timeout);
					DestroyStringItem(di);
					return r;
				}
				else
					return Channel.Poke(name, MatrixToString(mtx));
			}			
			else				
				return EvaluateNoResult(name+"="+MatrixToString(mtx, true)+";");						
		}


		/// <summary>
		/// Evaluates an expression without getting the result text
		/// </summary>
		/// <param name="s"></param>
		/// <returns></returns>
		public bool EvaluateNoResult(string s)
		{
			return IsOpen && Channel.Execute(s, itemEval, channel.Timeout);
		}

		/// <summary>
		/// Evaluates an expresion returning a string
		/// </summary>
		/// <param name="s"></param>
		/// <returns></returns>
		public string EvaluateAsString(string s)
		{
			if(!IsOpen) return null;
			if(Channel.Execute(s, itemEval, channel.Timeout)) 
			{
				string r;
				if(Channel.Request(itemEvalResult, out r, channel.Timeout))
					return r;
				else
					return null;
			}
			else
				return null;
		}

		/// <summary>
		/// Convert a double[,] matrix into a string for MATLAB textual
		/// transfer
		/// </summary>
		/// <param name="m"></param>
		/// <returns></returns>
		public static string MatrixToString(double [,] m)
		{
			return MatrixToString(m, false);
		}

		/// <summary>
		/// Same as MatrixToString but uses prefixes, suffixes and separators
		/// </summary>
		/// <param name="m"></param>
		/// <returns></returns>
		public static string MatrixToString(double [,] m, bool asEval)
		{
			string rowsep = asEval ? ";" : "\r\n";
			char colsep = asEval ? ',' : '\t';

			StringBuilder sb = new StringBuilder(100);
			int n1 = m.GetLength(0);
			int n2 = m.GetLength(1);
			if(asEval) 
				sb.Append('[');
			for(int i = 0; i < n1; i++)
			{
				sb.Append(m[i,0]);
				for(int j = 1; j < n2; j++)
				{
					sb.Append(colsep);
					sb.Append(m[i,j]);
				}
				sb.Append(rowsep);
			}
			if(asEval)
				sb.Append(']');
			return sb.ToString();
		}

		/// <summary>
		/// Convert a double[] array considering it as a matrix with
		/// the specified number of columns
		/// </summary>
		/// <param name="m"></param>
		/// <param name="cols"></param>
		/// <returns></returns>
		public static string MatrixToString(double [] m, int cols)
		{
			StringBuilder sb = new StringBuilder(100);
			int n1 = cols;
			int n2 = m.Length / n1;
			int k = 0;
			for(int i = 0; i < n2; i++)
			{
				sb.Append(m[k++]);
				for(int j = 1; j < n1; j++)
				{
					sb.Append('\t');
					sb.Append(m[k++]);
				}
				sb.Append("\r\n");
				if(i == 0)
				{
					sb.EnsureCapacity(sb.Length*n2);
				}
			}
			return sb.ToString();
		}

		/// <summary>
		/// Transforms back a string into a double[,]
		/// </summary>
		/// <param name="s"></param>
		/// <returns></returns>
		public static double [,] StringToMatrix(string s)
		{
			double [,] p = null;
			StringToMatrix(s, ref p);
			return p;
		}

		/// <summary>
		/// Transforms back a string into a double[,]
		/// </summary>
		/// <param name="s"></param>
		/// <param name="q"></param>
		/// <returns></returns>
		public static bool StringToMatrix(string s, ref double[,] q)
		{
			// first examine find the number of columns
			// then the number of rows
			int rows = 0;
			int cols = 0;
			string [] aa;
			int idx;
			char [] sep = {'\x9'};

			// count columns
			idx = s.IndexOf('\r');
			if(idx == -1) return false;
			aa = s.Substring(0,idx).Split(sep);
			cols = aa.Length;
			if(cols < 1) return false;

			// count rows (number of 
			idx = 0;
			rows = 0;
			while((idx = s.IndexOf('\r', idx)) != -1)
			{
				idx++;
				rows++;
			}

			if(q == null || q.GetLength(0) != rows || q.GetLength(1) != cols)
			{
				q = new double[rows,cols];
			}

			idx = 0;
			for(int i = 0; i < rows; i++)
			{
				// get a line and split
				int newidx = s.IndexOf('\r', idx);
				aa = s.Substring(idx, newidx-idx).Split(sep, cols);
				if(s[newidx+1] == '\n')
					idx = newidx+2;
				else
					idx = newidx+1;
				for(int j = 0; j < cols; j++)
				{
					q[i,j] = Double.Parse(aa[j]);
				}
			}
			return true;			
		}

		DDELibrary.DDEChannel Channel
		{
			get { return channel; }
		}

		/// <summary>
		/// Tells if the connection is open
		/// </summary>
		public bool IsOpen
		{
			get { return Channel != null; }
		}

		protected override void Dispose(bool disp)
		{
			if(Active)
			{
				DestroyStringItem(itemEval);
				DestroyStringItem(itemEvalResult);

				itemEval = new DDELibrary.DDEItem();
				itemEvalResult = itemEval;

				if(channel != null)
				{
					channel.Disconnect();
					channel = null;
				}

				base.Dispose(disp);
			}
		}

		/// <summary>
		/// Say if the MATLAB window is visible
		/// </summary>
		/// <returns></returns>
		public bool IsVisible()
		{
			// TODO
			return true;
		}

		/// <summary>
		/// Evaluate MAT access
		/// </summary>
		/// <param name="s"></param>
		/// <returns></returns>
		public bool Evaluate(string s)
		{
			string r = EvaluateAsString(s);
			return r != null;
		}

		/// <summary>
		/// Fixes the MATLAB windows visibility
		/// </summary>
		/// <param name="b"></param>
		public void SetVisible(bool b)
		{
			// TODO
		}
				
		/// <summary>
		/// Sets a matrix variable
		/// </summary>
		/// <param name="name"></param>
		/// <param name="data"></param>
		/// <returns></returns>
		public bool SetMatrix(string name, double [,] data)
		{
			return this.PutMatrix(name, data);
		}

		/// <summary>
		/// Support functions that transform a block of bytes in XLTable
		/// format into a double[,] matrix. It's specialized form MATLAB
		/// because in R12 it's broken for data blocks greater than 64K
		/// </summary>
		/// <param name="tab"></param>
		/// <param name="mtx"></param>
		/// <returns></returns>
		public static bool BytesToMatrix(byte [] tab, ref double [,] mtx)
		{
			DDELibrary.XLTable xt = new DDELibrary.XLTable(tab);
			int nr = xt.Rows;
			int nc = xt.Columns;
		
			// check data type
			if(xt.NextBlock() != DDELibrary.XLTable.Type.Float)
				return false;

			// check data size
			if(tab.Length < nr*nc*8+8+4)
				return false;

			// allocate matrix
			if(mtx == null || xt.Rows != mtx.GetLength(0) || xt.Columns != mtx.GetLength(1))
				mtx = new double[xt.Rows, xt.Columns];

			System.IO.BinaryReader br = xt.Stream;

			// now get the whole array ignoring the block
			try 
			{
				for(int i = 0; i < nr; i++)
					for(int j = 0; j < nc; j++)
						mtx[i,j] = br.ReadDouble();
			}
			catch(Exception )
			{
				return false;
			}
			return true;
		}


		DDELibrary.DDEChannel channel;
		DDELibrary.DDEItem    itemEvalResult, itemEval;
		bool usePOKE;
		bool useXLTABLE;
		/// <summary>
		/// Option to fix XLTable to Matrix convertion method
		/// </summary>
		public static bool BuggedMATLABXLTable = true;
	}
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


Written By
Software Developer (Senior) Scuola Superiore S.Anna
Italy Italy
Assistant Professor in Applied Mechanics working in Virtual Reality, Robotics and having fun with Programming

Comments and Discussions