100Mb/s glassfibre to my home

In our Nijmegen area glassfibre has recently been installed. Last weekend the new connection to our home was activated. According to the specification the speed should be 100Mbps both ways, i.e. up and down. That is the same speed that I (and most people probably) have on my desk at the university. I have done some preliminary tests that I want to report on.

According to http://speedtest.net, the down speed is ~95Mbps and the up speed is ~60Mbps. I have repeated that a couple of times, and the throughput varies over the day. These numbers are the best ones observed.

I have also tested using ftp, sending/receiving a 100MB file to/from the ftp server of the Donders Centre for Cognitive Neuroimaging. This results in 7.22MB/s or 60Mbps upstream and 7.77MB/s or 65Mbps downstream (see below for details).

The same test from my PowerBook G4, which is connected over 802.11g wireless to an Airport Extreme router, resulted in 2.5MB/s or ~20Mbps upstream and 1.56MB/s or 13Mbps downstream. The bottleneck here clearly is the wireless connection, and not the glassfibre.


ftp> put testfile.bin
local: testfile.bin remote: testfile.bin
200 PORT command successful. Consider using PASV.
150 Ok to send data.
100% |*************************************| 100 MB 7.23 MB/s 00:00 ETA
226 File receive OK.
104857600 bytes sent in 00:13 (7.22 MB/s)

ftp> get testfile.bin
local: testfile.bin remote: testfile.bin
200 PORT command successful. Consider using PASV.
150 Opening BINARY mode data connection for testfile.bin (104857600 bytes).
100% |*************************************| 100 MB 7.79 MB/s 00:00 ETA
226 File send OK.
104857600 bytes received in 00:12 (7.77 MB/s)

Overall I am pretty happy with these initial results of 60Mbps up and downstream in a realistic test, i.e. 60% of the theoretical throughput. I am not sure whether I have been able to connect to a server that does not introduce a bottleneck itself, and there is some variance in the tests itself that is due to other traffic over the network. I might post some more tests later.

More information can be found on http://www.glazenkamp.nl

Moved homepage

UPDATED on 28 October 2012.

My personal homepage has moved to a new webserver and can now be found at http://robertoostenveld.nl.

Some other and older homepage addresses that over the years have disappeared, or that hopefully would refer you to the most up-to-date location of my homepage are:

  • http://sccn.ucsd.edu/~roberto
  • http://www.mbfys.kun.nl/~roberto
  • http://www.mbfys.ru.nl/~roberto
  • http://miba.auc.dk/~roberto
  • http://smi.auc.dk/~roberto
  • http://oase.uci.ru.nl
  • http://robertoostenveld.ruhosting.nl
  • http://oostenveld.net
  • http://oostenveld.org

Multithreading in a MATLAB mex file

Together with colleagues from the F.C. Donders Centre and the NICI, I am currently working on a project on real-time analysis of EEG and MEG data for Brain-Computer Interfacing (BCI). Since we already have a lot of relevant code in MATLAB and since a lot of the target end-users are familiar with it, we would like to do the real-time processing in MATLAB.

The idea is to read the data that is streaming from the EEG amplifier, do the computation on the data (e.g. spatial filtering, spectral decomposition and classification) and then continue with the next section of the data. The challenge is not to lose any of the streaming EEG data while MATLAB is busy with the computation. A potential solution would be to implement the reading/acquisition of the data into matlab in a mex file which is multi-threaded.

For this purpose I wrote some code for testing the multithreading in MATLAB. The test code below demonstrates that it works, and shows how easy it actually is.

I am working on an Apple PowerBook G4 with OS X 10.4.11 and with MATLAB Version 7.4 (R2007a). The example code uses the POSIX Pthread libraries and I would expect the same code to work on most Unix and Linux systems. It will not work on a windows system, but might work with pthreads-win32.

Put the following code in a file with the name threads.c

#include < pthread.h > /* for threading */
#include < unistd.h > /* for sleep */
#include "mex.h"
#include "matrix.h"

void *do_thread(void *threadid)
{
int tid;
tid = (int)threadid;
mexPrintf("In thread: just started thread #%dn", tid);
sleep(4); /* pretend that the code is busy for a few seconds */
mexPrintf("In thread: about to exit from thread #%dn", tid);
pthread_exit(NULL);
}

void mexFunction (int nlhs, mxArray * plhs[], int nrhs, const mxArray * prhs[])
{
int num;

if (nrhs<1)
mexErrMsgTxt("not enough input arguments");
else
num = mxGetScalar(prhs[0]);

pthread_t threads[num];
int rc, t;
for(t=0; t < num ; t++){ mexPrintf("In main: creating thread %dn", t); rc = pthread_create(&threads[t], NULL, do_thread, (void *)t); if (rc){ mexErrMsgTxt("problem with return code from pthread_create()"); } sleep(1); /* wait some time before making the next thread */ } return; }

Subsequently, in MATLAB you should compile the mex file using the following command:

>> mex threads.c -lpthread

After that, you can run the mex function. It takes a single argument, corresponding to the number of threads to create. Each thread will live for three seconds (pretending that it is busy for some time), and the time between threads being created is one second. Some example output is below.

>> threads(6)
In main: creating thread 0
In thread: just started thread #0
In main: creating thread 1
In thread: just started thread #1
In main: creating thread 2
In thread: just started thread #2
In main: creating thread 3
In thread: just started thread #3
In thread: about to exit from thread #0
In main: creating thread 4
In thread: just started thread #4
In thread: about to exit from thread #1
In main: creating thread 5
In thread: just started thread #5
In thread: about to exit from thread #2
>> In thread: about to exit from thread #3
In thread: about to exit from thread #4
In thread: about to exit from thread #5
>>

You can see each thread starting and stopping. The last threads stop after the control has been returned to the MATLAB prompt.

Here you can find some comments from Mathworks, including some windows specific example code. Important to note is that MATLAB itself is single-threaded, and not thread safe. Hence you should take care in interfacing your threaded c-code in the mex file with the MATLAB core.

I would appreciate it to get some feedback on this. Please leave a comment below if you tested it successfully or if it does not work for you, with some details on your configuration (like operating system and MATLAB version).

Mac Mini with EyeTV

After a long period of doubt, last December I finaly decided to buy a Mac Mini as home entertainment system. It arrived soon and sofar it completely lives up to my expectations. I am using it together with a NEC LCD screen at the moment (which will be replaced by a 23″ Apple Cinema Display soon) and Elgato EyeTV. The EyeTV software can be controlled with the Apple remote, and resembles the FrontRow interface. However, EyeTV is not completely integrated with FrontRow: the two full-screen menus are seperate from each other. A small nuisance is that pressing the “menu” button on the remove short opens FrontRow, pressing it long opens the full-screen EyeTV menu interface opens. When watching TV, I sometimes accidentally press short instead of long, resulting in the FrontRow menu opening instead of the EyeTV menu.

I am using EyeTV together with a Plextor M402U Convert-X tuner. The Plextor tuner is one of few tuners that connects through USB and that is also compatible with both Linux and Mac OS X. I originally bought the tuner to be used with my old Dell laptop and Linux PVR software like MythTV. After fiddling around for multiple evenings, I got it to work but I found the software not of sufficient quality. The Dell laptop works fine with linux, but it did not convince me to be usefull on a daily basis. I did not even dare to try to convince my girlfriend . What a difference when I installed Elgato EyeTV op my Apple PowerBook: just plug-and-play and it works like a charm. Also the electronic program guide in EyeTV (using tvtv) works well. Actually, I consider this EPG to be quite important for serious PVR use.

To test out the dual tuner support in EyeTV, I borrowed a second tuner from a German friend: a Miglia TV-Mini. It is a DVB-T tuner for digital through-the-air broadcasts. In the Netherlands these broadcasts are carried out by Digitenne. I had previously read somewhere on the internet that Digitenne would not work at all with such a device, since all all stations (including Nederland 1, 2 and 3) would be scrambled. However, after doing the auto-setup, it did find a list of ~30 TV and ~20 radio channels! It gives a very sharp picture and has less of a delay than the Plextor tuner. So also digital trough-the-air TV works fine with the MacMini/EyeTV setup. Note that most of the channels are actually scrambled, only the public stations (Nederland 1, 2, 3 and TV Gelderland) are not scrambled. Regarding radio, the same applies: only Radio 1-5, the Concertzender and Radio Gelderland are available unscrambled. The others are listed with a “$” sign behind them, but this is already more that I had expected. To decode the scrambled signals you probably have to get a Digitenne subscription for the smartcard. This Miglia TVMini is a USB-stick sized decoder and cannot be used with a smartcard for decoding, but there are other tuners that can (e.g. Elgato 410).

To conclude, I am very happy with my Mac Mini. It works great for watching movies and listening to music (both using FrontRow) and for watching and recording TV using EyeTV and the Plextor tuner. The dual tuner support is still in beta stage (I am using EyeTV version 2.3.1) but the first impression is OK. I only hope that Apple will open up the FrontRow interface so that other high-quality products like EyeTV can be integrated in it, which would even improve the user experience as a “audio-visual media appliance” instead of as computer.

Average reference for dipole fitting

Here is a question that I get asked occasionally. I have slightly edited the question and my answer to it, which both were posted to the EEGLAB email discussion list.

Question: I’m using EEGLAB-DIPFIT to localize independent components using the spherical head model. Apparently the software requires the data to use the average reference. Why is this?

Answer: In principle you could use an arbitrary reference in your source reconstruction. The practical reason to use an average reference over the sampled electrodes in source estimation is that this prevents the solution to be biassed due to forward modelling errors at the reference electrode. Let me give a partially intuitive, partially mathematical explanation.

Assume that you would use left mastoid as reference. That would mean that the measured value “V” at each electrode “x” is V_x, so the list of all measured values in the N channels is

V_C3-V_M1
V_Cz-V_M1
V_C4-V_M1
...
V_M1-V_M1 (this is zero)
V_M2-V_M1

Those values can be modeled using the source model and the volume condution model. Now, lets assume a spherical volume conduction model. That is especially inaccurate for low electrodes, and the bony structure of the mastoid is definitely not modelled appropriately in a spherical model. So for the model potential “P” we would have the value at each of the N electrode also referenced to the model mastoid
electrode:

P_C3-P_M1
P_Cz-P_M1
P_C4-P_M1
...
P_M1-P_M1 (this is zero)
P_M2-P_M1

The source estimation algorithm tries to minimize the quadratic error between model potential distribution and the measurement, so the error term to be minimized is

Total_Error
= sum of quadratic error over all channels
= [(V_C3-V_M1)-(P_C3-P_M1)]^2 + ....
= [(V_C3-P_C3)-(V_M1-P_M1)]^2 + .... (here the terms are re-ordered)

So for each channel the error term consists of a part that corresponds to the potential at the electrode of interest, plus a part that corresponds to the reference electrode. The error term corresponding to the reference electrode is identical over all channels (i.e., repeats in each channel), hence for each channel you are adding some error term for the reference electrode. Therefore, the minimum error (“minimum norm”) solution will be one that especially tries to minimize the model error at the reference electrode (since that is included N times). In the case of a mastoid reference we know that there is a large volume conductor model error at M1, hence the source solution would mainly try to minimize that error term. The result would be that the source solution would be biassed, because it tries to reduce the (systematic) error at the reference.

The solution is to use an average reference (average over all measured electrodes). That implicitely assumes that the model error over all electrodes is on average zero, hence the minimum norm solution is not biassed towards a specific reference electrode.

P.S. The maths in my explanation above are rather sloppy, but the argument still holds for a more elaborate mathematical derivation which would assume the forward model inaccuracies are uncorrelated over electrode sites.

High-density EEG electrode placement

Some time ago we wrote an article on electrode placement for high-resolution EEG measurement (referred to as the 5% article). After its apearance I have noticed that there is a demand for a concise and methodological overview of electrode placement systems. With this page I want to share some of my knowledge on this subject. This page contains non-technical comments on the different standards for electrode placement. Continue reading

EEProbe

EEProbe is a Linux software package for EEG acquisition and analysis that was originally develloped at the Max Planck Institute in Leipzig, Germany (there known as EEP), and that is now further developed as a commercial product by ANT Software in Enschede, The Netherlands.

EEProbe stores its continuous data in a file with the extension *.cnt (not to be confused with the Neuroscan *.cnt format). The *.cnt file is a binary file and the data in it is compressed, which makes reading the data in your own software quite difficult. The file format for averaged ERPs (*.avr) is also binary, but not compressed. Furthermore there are files that contain event information such as triggers (*.trg), rejection marks (*.rej) and some others.

ANT has released a library with c-code (cntopenlib) to its customers, containing functions to read the header, the binary data and to decompress the data. I have used that library to make two mex files to import the binary data into Matlab, you can download those functions here. Furthermore, at the bottom of this page you can also download the source code of the mex files.

Note: since the release of EEProbe 3.2.4 in March 2004 the binary format of the *.avg files has been slightly changed (they now also contain history information). No new version of cntopenlib has yet been released, and therefore the mex function cannot always read the averages properly. You can use the “avrstrip” program from EEProbe to remove the history information, the resulting file can be read into Matlab.

Plain Matlab functions:

Mex files for Mac OS X (created using Matlab 6.5):

Mex files for Solaris (created using Matlab 6.1):

Mex files for Linux (created using Matlab 6.1):

Mex files for Windows (created using Matlab 6.1):

Source code of the mex files, released under the BSD license:

Or you can download them all together in a single package here.

Prevent spam when giving your email address

There are a couple of usefull web services that I want to share with you.

http://www.spamgourmet.com. Create disposable email addresses on the fly. You only have to create an account once on the Spamgourmet website, and from then on you can create disposable email addresses whenever needed. E.g. when you have to register on a website and are required to give your email address for a confirmation mail, you can at that moment think of and fill in a new email address. The confirmation email that is sent to your spamgourmet account will then be forwarded to your real account. The sender never sees your real address and after a ceirtain number of emails (that you specify), further undesirable email (spam) from that sender will be blocked.

http://www.mailinator.com. Create disposable email addresses on the fly. You can read the emails on the Mailinator website, no mail is forwarded to your real account. Your temporary email account will be automatically deleted after a few hours. It usage is similar to Spamgourmet, except that you do not have to register. The difference is also that anyone who can guess your temporary email address is able to read it (no passwords) and that mail is deleted after a few hours, whereas Spamgourmet forwards it to your real mail account.

http://www.yousendit.com. Share large (up to 1GB) files with other people. No passwords to share, no software to install, no accounts to create, and no full mailboxes. Your file is uploaded to their website and the recipient gets an email address with the obfuscated link where he/she can dowload your file.

EEGLAB workshop

From 17-19 September 2005, the second EEGLAB workshop will be held in Porto, Portugal. I will be giving a lecture on the use of the DIPFIT plugin (i.e., dipole analysis of ICA components). The new version 2 of the DIPFIT plugin will be introduced during he workshop, which means that the link between FieldTrip and EEGLAB is finally official.

For more information about the workshop, you can look here. For more information about the relation between FieldTrip and EEGLAB, you can look here and here.