置頂?

事件紀錄

1-java ()
FP-tree (ok and 改ing)
剖悉樹

1.5 運動計畫制訂

2-PHP? JSP? (尚未決定)
書籍閱讀maybe

2010年3月31日 星期三

Calling Matlab from Java

Calling Matlab from Java



Calling Matlab from Java

Mathworks supports calling and using Java objects from Matlab but not calling Matlab commands from Java. This page provides techniques to call Matlab commands from Java

Option #1: MatlabControl JMI Wrapper

[Feb 8, 2010] Joshua Kaplan from Brown University "essentially.. wrote a Java RMI.. wrapper around [the MatlabControl code described below] so that a Java program running in a different JVM than MATLAB can launch and then control a MATLAB session without any user intervention. (While not applicable to [their] situation, the code is actually capable of controlling any number of MATLAB sessions simultaneously.)
The source code, documentation, support jar, and a demo jar are all available at http://matlabcontrol.googlecode.com/ "

Option #2: The MatlabJava Server

[Sept 15, 2005] Bowen Hui has written a MatlabJava Server which you start from within matlab. It then starts a server that allows other other apps to connect to and control the Matlab session. These other apps can be started outside of matlab (ie. in their own virtual machine).

Option #3: MatlabControl

[Circa 2002] The two solutions above are based on the MatlabControl.java class, which allows you to call Matlab commands from Java: MatlabControl.java. This class has three main functions:

  1. MatlabControl.eval(String command) is used to evaluate strings as if you were executing them at the Matlab command prompt. These can be matlab scripts, commands, or functions that take no arguments.

  2. MatlabControl.feval(String command, Object[] args) is used to evaluate functions as if you were executing them at the Matlab command prompt, where args is the list of arguments. If the function takes n arguments, args should be an array of size n

  3. Object[] MatlabControl.blockingFeval(String command, Object[] args) is used to evaluate functions using feval just like MatlabControl.feval, but blockingFeval waits for the return values and passes them back to the caller as an Object[].
(If you are using Matlab R14, the JMI interface has changed and MatlabControl.java won't compile. You need to apply this patch. Many people are still using this code as of 2010, but if you are using Matlab versions later than R14 and the MatlabControl.java class does not work for you, you might consider using Options #1 or #2 above, which are much more recent. )
The following example is Java code that uses all three functions. First, instantiate a MatlabControl object
    ... MatlabControl mc = new MatlabControl();
Then, evaluate a string or two using the "eval()" function
    mc.eval(new String("help")); mc.eval(new String("help(plot)")); mc.eval(new String("x=5")); mc.eval(new String("x=5;")); mc.eval(new String("sqrt(x)")); mc.eval(new String("myScript"));
Now, evaluate a few functions that takes arguments using the "feval()" function. To pass no arguments, use null.
    mc.feval(new String("help"),null); Object[] args = new Object[2]; args[0]=new String("plot"); args[1]=new String("axis"); mc.feval(new String("help"), args);
Finally, evaluate a function that gives return arguments using the "blockingFeval()" function.
    args = new Object[1]; args[0]=new Double(5); Double returnVals = (Double)mc.blockingFeval(new String("sqrt"), args); System.out.println(returnVals.toString());

How to Make it Work

To compile MatlabControl, make sure that "MATLAB_ROOT\java\jar\jmi.jar" is in your classpath, where MATLAB_ROOT is the root installation directory of Matlab. To use the class, make sure it is in your matlab classpath. Change your matlab classpath by typing "edit classpath.txt" at the matlab prompt.
There are three things snags that people usually hit when trying to run this:
Snag 1: MatlabControl objects must be instantiated from within your Matlab session! (or by other java objects that were instantiated by your matlab session). This is because Matlab runs its own JVM, and you need to run MatlabControl in the same JVM that matlab is using. (this is why you need to make sure that MatlabControl is in your matlab classpath.) More specifically, if your program is defined in "mypackage/MyClass.java", you need to type
mypackage.MyClass.main({'param1','param2',...})
at the Matlab command prompt. If the object does not have a "main" function, you can just instantiate it but you must call the constructor manually, as follows:
obj = mypackage.MyClass
obj.MyClass(param1, param2,...)
Snag 2: Matlab is single-threaded. This means that if you try to eval or feval from within a Java function that was called directly from a Matlab function, it will hang waiting for the first matlab function to terminate. To solve this problem, you must call MatlabControl functions from a new thread! This can be any thread, as long as it is not the Matlab thread of execution. As an example, I have created a test function that properly spawns a new thread and calls the eval, feval, and blockingFeval functions so that the test functions can be called directly from Matlab. Type the following into your matlab prompt to make sure you get similar behavior:

    >> mc=MatlabControl; >> mc.testEval('x = 5') x = 5 >> mc.testFeval('help',{'sqrt'}) SQRT Square root. SQRT(X) is the square root of the elements of X. Complex results are produced if X is not positive. See also SQRTM. Overloaded methods help sym/sqrt.m >> mc.testBlockingFeval('sqrt',{x}) 2.2361
In summary of the first two snags, this should always be the standard order of execution:
  1. instantiate Java object from within Matlab
  2. spawn new thread in Java
  3. call Matlab functions from new Java thread
Snag 3: There is a little documentation in the MatlabControl source code that you might want to look at. Also, there are some more advanced features, including more advanced objects like MatlabEvalCommand and MatlabFevalCommand within MatlabControl. These support the use of a callback function called matlabControlcb.m that you must create, and will become useful when you realize that matlab cell arrays and such are not really converted into java objects but only their handles are converted into java objects, so you need to do all manipulation of them in matlab. When you get to that point, try looking at the souce code and experimenting.

Matlab Timer Objects

Matlab R13 (6.5) has a timer object supported. However, I have found it really useful to use this version, which has a GUI that allows you to change the period and start, stop the timer. This is especially useful if you are using an older version of Matlab. You can also replace the timer.jar file that came with matlab with this one, which is the same as the normal matlab timer but adds a gui interface to each one that you instantiate.
The main advantage to using timer objects is that you can wait by using a timer instead of using the matlab "wait" command. The "wait" command basically does a spinning wait, so matlab cannot run any other commands. This is a problem if you have a java object that is trying to run a matlab command. It is useful in general for event-based programming in matlab, which you might be doing if you are using matlab to interact with anything, like Java apps or the real world via the serial port.


If you still need more info

There is a lot more info on my help page pertaining to the TinyOS project at UC Berkeley that you will probably find useful after you filter out some of the tinyos help stuff. Look especially at the end of the page and follow some of those links for good clues..
A lot of people (including myself) have been trying to figure out how to call Matlab commands from Java but Mathworks has not wanted to support it or even give out much information, as people on the newsgroups (also) know. The most information they release is in the following URL and email.
If you want to know more about using Matlab from Java, however, look at the files in the .jar files in the matlab\java\jar directory. You can use introspection to find out what methods the classes have, etc. For example, you can type methodsview com.mathworks.jmi.Matlab at your Matlab command prompt to see the Matlab class (which is the one I used for MatlabCommand.java). This class also has functions such as mtGet() and mtSet() that I believe allow you to read and write to the Matlab workspace from Java. It also has versions of eval and feval that return the return values of your matlab commands back to your Java object.
Of course, sometimes the function signatures aren't enough to figure out how to use them. You might consider using Gnu JODE to decompile the .class files back into .java files (but this might go against some license agreement).
If you want to know more about using Java from Matlab (a feature which IS supported by mathworks) read the matlab documentation on "Java/Matlab Interface".
Copyright © 2002 Kamin Whitehouse

沒有留言:

張貼留言