TCP/IP interface (Matlab/Octave)
Communicate with measurement instruments via Ethernet (no-toolbox-Matlab or Octave)
Purpose
Measurement automation is digital signal processing in a wider sense: Getting a digital signal from an analog world usually involves some measurement instruments, for example a spectrum analyzer.
Modern instruments, and also many off-the-shelf prototyping boards such as FPGA cards [1] or microcontrollers [2] are able to communicate via Ethernet.
Here, I provide some basic mex-functions (compiled C code) to interface directly from Matlab (Octave) on Windows.
The task itself seems rather trivial - send and receive via a TCP/IP socket - but making it work from scratch can turn into a quite time-consuming exercise. I hope that the code will be useful as a simple example.
A non-Matlab program with similar functionality can be found as lanio.c in [3] (page 131).
Pros/cons/Alternatives
Intermediate layer
The code communicates directly via the network interface. No intermediate layer such as SICL [4] or VISA is used, and no additional DLLs need to be installed.
Use of an intermediate layer integrates for example devices with legacy GPIP interface transparently. On the other hand, it requires the installation of vendor-dependent software on the host PC, and may create more problems than it actually solves.
Addressing
Devices are addressed by their IP address. If needed, the hostname could be resolved as shown in [3], but I'd assume that a typical lab network is strictly firewalled from intra-/internet, uses static IP addresses and provides no DNS service.
Timeouts
No timeouts are implemented: Keep it simple and stupid and don't worry about commands timing out because they won't. Ever.
The downside is that a protocol error (typos) will lock up the session and require a restart of Matlab / Octave. This can be inconvenient, but happens rarely if I pay attention to my code.
Too many connections
A "debugging session" in an early development stage may involve many connection attempts that aren't properly closed. This can cause problems both on instrument and PC side after a while.
If the code suddenly stops working without apparent reason, reboot.
Instrument control toolbox (Matlab)
Mathworks' "Instrument control toolbox" [5] implements similar functionality.
If it is available, consider using it instead.
Protocol
Message and reply
Typical use is to send SCPI commands (see [6] page 3) and receive responses. Example commands are *RST (reset the instrument), or *IDN? (query the identity of a device).
As is common, the application code needs to read data when it is known to be available. Usually this is the case after submitting a query-type command (ending with a question mark). If the instrument needs some time for the response, the read() command will block for as long as is needed.
ASCII and binary
ASCII data from the instrument is a single line, terminated with a newline character (number 13, \n).
Binary data may include the newline character as part of the message, therefore it needs to be prefixed by a header that encodes its length.
For example, an instrument will transmit the string abcdef in binary mode as
#70000006abcdef\n
Here,
- #as first character indicates a binary message
- 7states the length will be transmitted as seven-digit number in ASCII format
- 0000006is the length of the following binary data
- abcdefis the binary data
- \n is a newline character
#16abcdef\n would be equivalent and shorter.
The code example converts binary data to a vector of floats!
If this is not appropriate, copy instrIf_read.cc to a different name and modify the data conversion as required.
Implementation details
The contents of the SOCKET data structure in the C code are passed back to Matlab as an array of chars - this is unorthodox but conceptually sound: By fair means or foul, the contents of the data structure will be bitwise identical between invocations.
Usage
Maybe the most straightforward and robust way to use the code is to
- open a connection: s = instrIf_socket('192.168.1.1'); % example IP address assigned to an instrument
- send one single command: instrIf_write(s, ['*IDN?', 10]); % note the terminating character
- receive the reply (if applicable): r = instrIf_read(s);
- close the connection: instrIf_close(s);
- repeat for the next command
The reason not to reuse the connection is the possibility of a program error between instrument queries (the query itself is unlikely to fail): If the program aborts with an error, there won't be any open connections.
The overhead caused by the repeated opening / closing is usually negligible.
Debugging
If the instrument does not respond, open a DOS command prompt and type ping 192.168.1.1. At least typical measurement instruments should reply to "ping", and failure indicates network configuration problems.
The "telnet" program can be useful for network debugging. The default port number for SCPI commands is 5025.
Download
The functions can be downloaded below. Save them all into the Matlab (Octave) working directory, and compile each individually.
instrIf_socket.cc (compile with mex instrIf_socket.cc).
instrIf_write.cc (compile with mex instrIf_write.cc).
instrIf_read.cc (compile with mex instrIf_read.cc).
instrIf_close.cc (compile with mex instrIf_close.cc).
headers.h (required in same folder)
myUtil.cc (required in same folder)
References
[1] Altera / Terasic Stratix 4 DE4 development board
[2] MBED LPC-1768 microcontroller board
[3] Agilent signal generators programming guide
[4] Agilent SICL User's Guide for Windows
[5] Matlab Instrument Control Toolbox
[6] Agilent Technologies: N5161A/62A/81A/82A/83A MXG Signal Generators: SCPI Command Reference
Warranty
This program is provided "as is" without warranties of any kind, either expressed or implied, including, but not limited to, the implied warranties of merchantability, fitness for a particular purpose or noninfringement. in no event shall the authors or copyright holders be liable for any claim, damages or other liability, arising from, out of or in connection with the software or the use or other dealings in the software.
- Comments
- Write a Comment Select to add a comment
So Amplitude = sqrt(a²+b²) and Phase=arct(b/a).
I hope that will be usefull for you.
Best regards
Driss from Morocoo
Thank you so much for this code! I've been looking for a free alternative to the Instrument Control Toolbox and this is working great with my equipment. I have one instrument that has a 5 second delay when responding to the *IDN? query, but everything else is working great!
I remember a similar delay when the device was on a shared network with a DHCP server etc.
Try to set up an Ethernet adapter with fixed IP (i.e. 192.168.1.250), and set a fixed IP address for the instrument (i.e.192.168.1.249). Then connect with a single network cable (if no "green light" you may need a crosslink cable or hub in-between).
"ping" can be a useful tool. If the response is inconsistent, you know it's a network problem and not the instrument code.
I get errors such as "D:\temp\Matlab/instrIf_socket.cc:42: undefined reference to `_imp__socket@12'"
and only a file with '.o' extension is created. Could you point me into a direction to find a solution?
thanks in advance
I compile on windows in the following way:
----------------------
delete *.mex *.o
mkoctfile --mex -lws2_32 instrIf_close.cc myUtil.cc
mkoctfile --mex -lws2_32 instrIf_read.cc myUtil.cc
mkoctfile --mex -lws2_32 instrIf_write.cc myUtil.cc
mkoctfile --mex -lws2_32 instrIf_socket.cc myUtil.cc
----------------------
BTW, need to add #include "headers.h" as first line in myUtil.cc
Hi tafkos,
thanks for the comment.
Yes, the -lws2_32 is required as gcc ignores '#pragma comment(lib, "Ws2_32.lib")'
If you switch the order of the files (see the "mex" example in the text, e.g. mkoctfile --mex -lws2_32 myUtil.cc instrIf_close.cc) I think we don't need to add "headers.h", as it's #included from myUtil.cc
it's a linker error. It can't find the "socket" function in any library.
If you are using an Octave binary from Sourceforge, there are two alternative executable packages:
- one built with Microsoft compiler
- the other one built with gcc
The former is considerably faster, but compilation will probably not work. Try the second one.
If this doesn't solve the problem, it may be that a library - probably "winsock" - is not given to the linker as argument, or libraries are in the wrong order. These things often take some trial-and-error, unfortunately.
To post reply to a comment, click on the 'reply' button attached to each comment. To post a new comment (not a reply to a comment) check out the 'Write a Comment' tab at the top of the comments.
Please login (on the right) if you already have an account on this platform.
Otherwise, please use this form to register (free) an join one of the largest online community for Electrical/Embedded/DSP/FPGA/ML engineers: