Real-time Signal Analysis with RTLinux/Pro: Part 1 ... · Real-time Signal Analysis with...

16
Real-time Signal Analysis with RTLinux/Pro: Part 1, Integrating Real-time Data with Java Matt Sherer FSMLabs, Inc. Socorro, NM 87801 [email protected] Abstract Hard real-time systems need to intercept, analyse, and act on signals, immediately and without fail. These days, it’s rare that this is all the system has to do - it probably has to report on progress and allow operators or other software to direct future activity. In this article we’ll demonstrate how to do hard real-time signal acquisition while controlling it from a normal Java ap- plication. Part 2 and 3 will add a hard real-time digital filter and demonstrate how to integrate MATLAB with RTLinux/Pro. 1 Background Real-time control systems usually need to acquire a signal, process or transform it in some manner, filter it, and either act on the result or push back through some D/A device. Hard real-time systems must do this every time, without fail, even

Transcript of Real-time Signal Analysis with RTLinux/Pro: Part 1 ... · Real-time Signal Analysis with...

Page 1: Real-time Signal Analysis with RTLinux/Pro: Part 1 ... · Real-time Signal Analysis with RTLinux/Pro: ... Integrating Real-time Data with Java Matt Sherer ... real-time processing

Real-time Signal Analysis with RTLinux/Pro: Part 1,Integrating Real-time Data with Java

Matt Sherer

FSMLabs, Inc.Socorro, NM 87801

[email protected]

Abstract

Hard real-time systems need to intercept, analyse, and act on signals,immediately and without fail. These days, it’s rare that this is all the systemhas to do - it probably has to report on progress and allow operators or othersoftware to direct future activity. In this article we’ll demonstrate how to dohard real-time signal acquisition while controlling it from a normal Java ap-plication. Part 2 and 3 will add a hard real-time digital filter and demonstratehow to integrate MATLAB with RTLinux/Pro.

1 Background

Real-time control systems usually need to acquire a signal, process or transformit in some manner, filter it, and either act on the result or push back through someD/A device. Hard real-time systems must do this every time, without fail, even

Page 2: Real-time Signal Analysis with RTLinux/Pro: Part 1 ... · Real-time Signal Analysis with RTLinux/Pro: ... Integrating Real-time Data with Java Matt Sherer ... real-time processing

under the worst possible conditions. Throughout this process, it is helpful to pro-vide some means of analyzing the data and the system, and to provide user-levelcontrols to direct the real-time activities.

If real-time applications have to contend with management and non real-timeapplications for resources, the result is a complex system with conflicting de-mands. RTLinux avoids this by enforcing a strict boundary between real-timecomponents and those with no timing demands by using a small, verifiable, anddeterministic hard real-time operating system running a non real-time system asan application server. This means that real-time code runs in real-time system, andnon-real-time code runs in the general purpose operating system, such as Linuxor NetBSD.1

This article is concerned with simulating a real-world A/D application - wewill simulate an incoming analog signal and sample it with a digital component.Java will be used to both control and visualize both the incoming analog signalgeneration and the sampling mechanism. In part 2, we will add components fromFSMLabs’ Controls Kit so that we can selectively filter signal components basedon direction received from our Java controls. In part 3, we will demonstrate howto let MATLAB directly interoperate with our real-time system.

2 Digital Acquisition

Usually, some piece of hardware provides an A/D bridge to discretize a continuoussignal. This device, depending on its capabilities, can safely oversample a signaland keep a predetermined amount of backlogged data in storage until the operatingsystem has time to log the samples.

With a general purpose OS only interested in logging data, this may be suffi-cient, as long as the buffer is sufficient to handle the worst case delays as deter-mined by the operating system (which may be unbounded). However, an aber-ration in a power signal might mean that recovery and other operations must oc-cur immediately, rather than sometime after the logging process catches up onthe backlog. If analysis and reaction must happen deterministically and provablywithout fail, a hard real-time system is needed.

Some simple systems have improved the ability to get an interrupt in Linuxquickly, but there are no further facilities - either pend the data down to Linux forlater processing (and go back to the broken logging example) or do all of your

1In RTLinux/Pro, threads can be run in separate address spaces by running within the contextof a host process. However, we will not be using that method here.

2

Page 3: Real-time Signal Analysis with RTLinux/Pro: Part 1 ... · Real-time Signal Analysis with RTLinux/Pro: ... Integrating Real-time Data with Java Matt Sherer ... real-time processing

real-time processing and action in the context of the interrupt handler. This is outof the question for all but the simplest of applications. RTLinux provides a fullhard real-time operating system in which to deterministically process all of yourreal-time data, while still having the broad power of Linux within reach.

Or example creates the signal in a high frequency thread with sufficient granu-larity to make a precise waveform made up of several frequency components. Thisis sampled by a lower frequency thread, acting as an A/D acquisition mechanism.By varying the parameters from our control system, we can change the incomingwave characteristics and the sampling parameters.

3 Processing

First, we’ll analyze the code involved in generating the real-time signal, samplingit, and making the resulting information available to the rest of the world (I.E.,our Java tool.). There are several components - we have some initialization andcleanup code that handles the creation of the devices and threads. Secondly, thereare some event handlers on the real-time side that trigger when our control GUIwants to interact with the system. And lastly, there are the real-time threads them-selves - one that is generating the signal and one that samples it.

3.1 Initialization

Let’s look at the initialization code:

struct command{int signal hz;int noise hz;int samplehz;

};

static pthreadt signal gen t;static pthreadt samplert;

static int sampledfd; 10

static int signal fd;static int control to rtl fd;static int control from rtl fd;

int init module(void) {

3

Page 4: Real-time Signal Analysis with RTLinux/Pro: Part 1 ... · Real-time Signal Analysis with RTLinux/Pro: ... Integrating Real-time Data with Java Matt Sherer ... real-time processing

pthreadattr t attr;struct rtl sigaction sigactr;struct rtl sigaction sigactw;

20

mkfifo("/pure_signal" ,0777);signal fd = open("/pure_signal" , O RDWR|O NONBLOCK);ftruncate(signal fd, sizeof(int )*10);

mkfifo("/sampled_signal" ,0777);sampledfd = open("/sampled_signal" , O RDWR|O NONBLOCK);ftruncate(sampledfd, sizeof(int )*10);

mkfifo("/control_to_rtl" , 0777);control to rtl fd = open("/control_to_rtl" , O RDWR|O NONBLOCK); 30

ftruncate(control to rtl fd, sizeof(struct command));sigact r.sa sigaction = control to rtl handler;sigact r.sa fd = control to rtl fd;sigact r.sa flags = RTL SA WRONLY | RTL SA SIGINFO;rtl sigaction(RTL SIGPOLL, &sigact r, NULL );

mkfifo("/control_from_rtl" , 0777);control from rtl fd = open("/control_from_rtl" , O RDWR|O NONBLOCK);ftruncate(control from rtl fd, sizeof(struct command));sigact w.sa sigaction = control from rtl handler; 40

sigact w.sa fd = control from rtl fd;sigact w.sa flags = RTL SA RDONLY | RTL SA SIGINFO;rtl sigaction(RTL SIGPOLL, &sigact w, NULL );

pthreadattr init(&attr);pthreadattr setfp np(&attr,1);

pthreadcreate(&signal gen t, &attr, signal gen, 0);pthreadcreate(&samplert, &attr, sampler, 0);return 0; 50

}

For those who worked with RTLinux in the pre-POSIX days, this may be alittle different, but it shouldn’t be difficult for anyone used to standard UNIX pro-gramming. We are going to need 4 communication channels for now - one foruserspace to see the raw signal, one for the sampled version, and two so that wecan shuttle commands back and forth between RTLinux and Java. Note that thenames are purely user-defined now, rather than having to use/dev/rtf* forall devices. Rather than having to remember that/dev/rtf16 is sampled data

4

Page 5: Real-time Signal Analysis with RTLinux/Pro: Part 1 ... · Real-time Signal Analysis with RTLinux/Pro: ... Integrating Real-time Data with Java Matt Sherer ... real-time processing

and /dev/rtf23 is the pure signal, we can just callmkfifo() with /sam-pled signal and /pure signal respectively. RTLinux/Pro[1] makes surethat the nodes are created appropriately in the Linux filesystem as needed basedon the permission bits.

sigaction() is used for the two command FIFOs. For the signal FIFOs,we can just dump the data and continue on in real-time, but in order to receivecommands efficiently,sigaction() is recommended. The alternative is toconstantly poll the device for possible input, which is inefficient. Withsigac-tion() , we tell RTLinux what events we are interested in being called for, andour handlers are only executed when those events happen.

In addition to the newmkfifo() , sigaction() , and other POSIX callssuch asopen() andread() , RTLinux/Pro also usesftruncate() in orderto size the device, rather than customioctl() calls that have been used in thepast. In this example, we create the signal FIFOs with room for a 10 samplebacklog, and the command FIFOs with a structure size that we haven’t looked atyet. This will be used to push commands between our real-time code and Javaprograms.

At the end of this initialization, we have 4 FIFOs, two of which are hookedto event handlers, and we’ve spawned 2 threads - one for the pure signal, andone that will sample it. Note that we allow the threads to use the FPU withthe pthread attr setfp np() call. With this minor exception, this is allPOSIX-based, and there are no real surprises.

3.2 Signal generation and sampling

Now for the signal generating thread that has just been spawned:

void *signal gen(void *arg) {#define THREAD PERIOD 5000000#define SAMPLE FRACTION 1000000000/THREAD PERIOD

struct timespec next;float x1 = 0;float x2 = 1.5;float incr1;float incr2;float cur1;float cur2; 10

int icur;

clock gettime(CLOCK REALTIME, &next);

5

Page 6: Real-time Signal Analysis with RTLinux/Pro: Part 1 ... · Real-time Signal Analysis with RTLinux/Pro: ... Integrating Real-time Data with Java Matt Sherer ... real-time processing

while (1) {timespecadd ns(&next, THREAD PERIOD);clock nanosleep(CLOCK REALTIME, TIMER ABSTIME,

&next, NULL );

incr1 = 2*PI / (SAMPLE FRACTION / signal hz);x1 += incr1; 20

cur1 = (float)sin(x1);

incr2 = 2*PI / (SAMPLE FRACTION / noise hz);x2 += incr2;cur2 = (float)sin(x2);

cur signal = cur1 + (0.5*cur2);icur = (int )(cur signal * 10000);icur = htonl(icur);write(signal fd,&icur,sizeof(int )); 30

}return 0;

}

As with any normal thread, this function starts, enters a loop, and in our case,generates a core signal with a noise component. The loop executes and sleeps ona 5ms (200Hz) interval, stepping the wave components at each point. After eachloop iteration, it writes the output to the FIFO we had set up previously. Duringinitialization, we had allocated space for 10 samples, but it could have easily been100, if it turned out that the userspace application can’t keep up with the output.For low throughput like this, 10 samples is enough, but one can easily see thebenefit of doing this in software, rather than being bound to a hardware-definedFIFO size.

One might question why we are casting the sample to an int, multiplying by10000, and callinghtonl() on it before writing to the FIFO. The answer issimple but important when using Java: This example assumes it is being run onan x86 machine, which runs little-endian. Java has always taken the network-centric approach and always runs big-endian. In order to keep things simple,we’re reversing the byte order here so we don’t have to do it in the Java code. Thedata type used is a float, so we scale it up such that it can be useful as an integerapproximation. A more exact method could be used, but this is done in order tokeep the demo simple.

6

Page 7: Real-time Signal Analysis with RTLinux/Pro: Part 1 ... · Real-time Signal Analysis with RTLinux/Pro: ... Integrating Real-time Data with Java Matt Sherer ... real-time processing

As with the initializing code, this is POSIX-based, and there are no real sur-prises.clock gettime() is important, though - it is commonly misused. It isimportant to sample the clock outside of the execution loop, and within the looponly add your time delay and sleep. Callingclock gettime() as part of theloop occurs in the same context as the rest of your code, and the sampling over-head may induce low-order jitter over long periods. Making the call once outsideof the main loop and always adding to that value ensures that you avoid any drift.

void *sampler(void *arg) {struct timespec next;float sample;int isample;int iperiod;

clock gettime(CLOCK REALTIME, &next);while (1) {

iperiod = (int )(1000000000/samplehz);timespecadd ns(&next, iperiod); 10

clock nanosleep(CLOCK REALTIME, TIMER ABSTIME,&next, NULL );

sample= cur signal;

isample = (int )(sample* 10000);isample = htonl(isample);write(sampledfd,&isample,sizeof(int ));

}return 0; 20

}

This is all we need to do in order to sample the signal in real-time. We start upa looping thread that operates at a given hertz. (We’ll see how this is set shortly.)At each wakeup, we just get the latest value that our signal generating functionhas left for us. If this were a real A/D situation, we wouldn’t have the other thread,but would rather get the sample value directly from the hardware device.

3.3 Shuttling commands

We’ve covered most of the real-time code already, and only have one piece left:There needs to be something that sends and receives control commands to andfrom Java. In this portion of the example, we need to send and receive a few

7

Page 8: Real-time Signal Analysis with RTLinux/Pro: Part 1 ... · Real-time Signal Analysis with RTLinux/Pro: ... Integrating Real-time Data with Java Matt Sherer ... real-time processing

values - the hertz rate of our core signal, a hertz rate of the noise component, andthe sampling rate of our slower sampling thread. With these calls, we can let ourJava control program direct the activities of our real-time code. The devices andevents were set up during initialization, so now we just need to look at the handlersthemselves:

void control from rtl handler(int sig, rtl siginfo t *siginfo, void *v) {

int ret;struct command com;

com.signal hz = htonl(signal hz);com.noise hz = htonl(noise hz);com.samplehz = htonl(samplehz);ret = write(siginfo−>rtl si fd, &com, sizeof(struct command));

} 10

static int count = 0;static unsigned char readdata[sizeof(struct command)];static char *ptr = readdata;void control to rtl handler(int sig, rtl siginfo t *siginfo, void *v) {

int ret;struct command com;

ret = read(siginfo−>rtl si fd, ptr, sizeof(unsigned char)); 20

count += ret;ptr += ret;if (count >= sizeof(struct command)) {

memcpy(&com, readdata, sizeof(struct command));signal hz = ntohl(com.signal hz);noise hz = ntohl(com.noise hz);samplehz = ntohl(com.samplehz);count = 0; ptr = readdata;

}} 30

Here you see two functions:control from rtl handler() andcon-trol to rtl handler() . As their names imply, the first writes informationto a FIFO, and the second reads commands in. If you refer back to the initial-ization,sigaction() hooks these calls to their inverse activities - this can beconfusing to those who are new tosigaction() .

8

Page 9: Real-time Signal Analysis with RTLinux/Pro: Part 1 ... · Real-time Signal Analysis with RTLinux/Pro: ... Integrating Real-time Data with Java Matt Sherer ... real-time processing

In the case ofcontrol from rtl handler() , it responds toread ac-tions on the other end of the FIFO, so it performs awrite() in order to ser-vice that request. Likewise,control to rtl handler() is connected towrite() events from userspace, which means that someone has submitted datato beread .

There is very little work involved in each of these calls. In the case that weneed to do a write, we set up a structure that defines the data to be sent. We fill itout, and then send it down the FIFO viawrite() as you would with any otherfile. Again, we do byte reordering in order to simplify the Java example. Forread() activities, we need to handle the case where not all of the data is writtenbefore userspace is preempted, so we fill the read data into a structure, and whenwe’ve seen the whole thing, we pull the command data out and apply it.

3.4 Shutting down

The real-time code also needs to shut down cleanly, as otherwise it would runinfinitely. With pure POSIX semantics, this is very simple in RTLinux:

void cleanupmodule(void) {pthreadcancel(signal gen t);pthreadjoin(signal gen t, NULL );

pthreadcancel(samplert);pthreadjoin(samplert, NULL );

close(signal fd);unlink("/pure_signal" );

10

close(sampledfd);unlink("/sampled_signal" );

close(control to rtl fd);unlink("/control_to_rtl" );

close(control from rtl fd);unlink("/control_from_rtl" );

}20

We have two threads that must be safely stopped - this is done the normalway by cancelling the thread and joining its resources. For the FIFO devices we

9

Page 10: Real-time Signal Analysis with RTLinux/Pro: Part 1 ... · Real-time Signal Analysis with RTLinux/Pro: ... Integrating Real-time Data with Java Matt Sherer ... real-time processing

created, RTLinux/Pro supports theunlink() call, which will also take care ofremoving the node from RTLinux and the host filesystem. So for each FIFO, weclose() it normally,unlink() it, and we’re done.unlink() call will takecare of removing the Linux filesystem entry if needed.

4 Java Control Software

We’ve covered all of the real-time signal generation, now it’s time for the Javaintegration and visualization of the data. For this example, we’re keeping our sig-nal rates low, so that we can easily visualize both the pure signal and the sampledversion.

As with most GUI programs, much of the code is concerned with managingthe visual components. In the interest of brevity, we will only cover the pieces ofJava that directly interact with the RTLinux FIFOs. First, let’s look at the objectcode that sends and receives commands:

class SignalCommand{private int signal hz;private int noise hz;private int samplehz;private DataInputStream dis;private DataOutputStream dos;private String write fifo, read fifo;

public SignalCommand(String write fifo, String readfifo) {this.write fifo = write fifo; 10

this.read fifo = read fifo;try {

dis = new DataInputStream(new FileInputStream(read fifo));

dos = new DataOutputStream(new FileOutputStream(write fifo));

} catch (Exception e) {System.out.println("Could not open FIFO: " + e);

}} 20

public void setSignalHz(int signal hz) {this.signal hz = signal hz;

}public void setNoiseHz(int noise hz) {

this.noise hz = noise hz;

10

Page 11: Real-time Signal Analysis with RTLinux/Pro: Part 1 ... · Real-time Signal Analysis with RTLinux/Pro: ... Integrating Real-time Data with Java Matt Sherer ... real-time processing

}public void setSampleHz(int samplehz) {

this.samplehz = samplehz;} 30

public int getSignalHz() { return this .signal hz; }public int getNoiseHz() { return this .noise hz; }public int getSampleHz() { return this .samplehz; }

public void receiveCommand() {try {

signal hz = dis.readInt();noise hz = dis.readInt();samplehz = dis.readInt(); 40

} catch (Exception e) {System.out.println("Error reading commands: " + e);

}}

public void sendCommand() {Process proc;try {

dos.writeInt(signal hz);dos.writeInt(noise hz); 50

dos.writeInt(samplehz);} catch (Exception e) {

System.out.println("Error writing commands: " + e);}

}}

For those who are familiar with Java, this should come as no surprise. Theclass contains all of the local variables needed to fill out our command structure,and the constructor opens up the FIFO as directed by the caller. It opens thedevices as data streams so that writing primitives such as ints will be simpler.

Two calls are of interest to us here:receiveCommand() andsendCom-mand() . These write integers out or read them in from the correct device in orderto exchange data with the real-time system. Since we handle the endian conver-sion on the other end of the FIFO, there is no other work that needs to be donehere. This object just plugs into our simple graphical application, as shown inFig. 1. The details of the GUI code is beyond the scope of this article, but source

11

Page 12: Real-time Signal Analysis with RTLinux/Pro: Part 1 ... · Real-time Signal Analysis with RTLinux/Pro: ... Integrating Real-time Data with Java Matt Sherer ... real-time processing

is provided on request. It is no different than any other Java GUI - in the maincode, we just instantiate this object with:

SignalCommand sc = new SignalCommand("/control_to_rtl","/control_from_rtl");

From there, we can operate on the object just like any other.

Figure 1: Our simple control GUI in Java

As you can see from the figure, this is a straightforward GUI - we can getinformation from the real-time side, or set and send values for our core signal,noise, and sampling rate. But this doesn’t do much good unless we can see whatthe real-time side is doing with its data. As with the previous example, we won’tbore you with the details of controlling Java GUI components - instead, here isthe class that reads the signal data from the real-time FIFO:

class Readerextends Thread{

DataInputStream dis;

12

Page 13: Real-time Signal Analysis with RTLinux/Pro: Part 1 ... · Real-time Signal Analysis with RTLinux/Pro: ... Integrating Real-time Data with Java Matt Sherer ... real-time processing

XYSeries series;JLabel lab;

public Reader(String device, XYSeries series, JLabel lab) {this.series= series;this.lab = lab;try { 10

dis = new DataInputStream(new FileInputStream(device));

} catch (Exception e) {System.out.println("Failed open: " + e);

}}

final static int area len = 200;public void run() {

int i = 0; 20

int count = 0;int newval = 0;int zerval = 0;

for (i = 0; i < area len; i++) {series.add(i,0);

}while (true) {

try {i = dis.readInt()/100; 30

} catch (Exception e) {System.out.println("Failed: " + e);

}try {

count++;newval = count % area len;zerval = newval − (int )(area len * .95);if (zerval < 0)

zerval = area len + zerval;series.update(newval, new Integer(i)); 40

series.update(zerval, new Integer(0));lab.setText((new Date()).toString());

} catch (Exception ee) {}

}}

}

13

Page 14: Real-time Signal Analysis with RTLinux/Pro: Part 1 ... · Real-time Signal Analysis with RTLinux/Pro: ... Integrating Real-time Data with Java Matt Sherer ... real-time processing

We will instantiate this code twice - once on the device that provides the puresignal, and once on the sampled output. Again, the byte ordering is done on theother end of the FIFO, so we don’t have to worry about that here. We just read oursample points in and plot them into an XYSeries object, which is a component inour visualization tool. The visualization is done with the JFreeChart[2] project,which provides many means of visualizing data. The XYSeries object simplyplaces the points in a collection such that they can be viewed in a very simplechart.

For the default values in our system, the output is shown in Fig.2, with thepure signal on the top, and the sampled output on the bottom. As you can see,we’re short of the Nyquist rate of the highest frequency component and are gettingsignal aliasing in our sampled data. Note that the pure signal output is ’stretched’ -this signal is being incremented at 200Hz, so it fills the chart every second, havingthe effect of zooming in on the signal. Our sampled graph is only 10 samples persecond, so it doesn’t fill the graph quickly, and offers a zoomed out perspective.In Fig. 2, we are filling 10 data points per second, and you can see that most ofthe signal energy is the 1Hz wave, advancing slowly across our 200 point graph.

Let’s switch to a good sampling rate so that we can capture all of the signalinformation in our sampled output - this can be seen in Fig.3, again with the puresignal on the top and the sampled output on the bottom. You can see that sincewe are sampling at a higher rate, the view zooms in and we capture all of theinformation in the signal. The result is a 1Hz wave with a 14Hz component whichis captured cleanly in the sampled output. Keep in mind that these visualizationsare arbitrary, and only done here as a demonstration - you can easily plug thisdata into any other visualization tool you might have on hand. In part 3, we’lllet MATLAB directly talk to our real-time threads and perform power spectralanalysis on the output, rather than visually inspecting the output.

5 Conclusion

In this example, we’ve run the whole gamut from generating a real-time signalwith a noise component, to downsampling that signal properly, to interacting withuserspace with the new RTLinux/Pro POSIX APIs, to controlling the real-timesignals with a GUI, and finally visualizing the signal output with Java. In the nextinstallment, we’ll demonstrate how to selectively filter this signal with FSMLabs’

14

Page 15: Real-time Signal Analysis with RTLinux/Pro: Part 1 ... · Real-time Signal Analysis with RTLinux/Pro: ... Integrating Real-time Data with Java Matt Sherer ... real-time processing

Figure 2: Undersampling the signal in real-time

Controls Kit, followed by another piece detailing how to analyze the signal andeasily integrate simulation and analysis with MATLAB.

References

[1] FSMLabs Inc.http://www.fsmlabs.com/products/ .

[2] The JFreeChart Project. http://www.object-refinery.com/jfreechart/ .

15

Page 16: Real-time Signal Analysis with RTLinux/Pro: Part 1 ... · Real-time Signal Analysis with RTLinux/Pro: ... Integrating Real-time Data with Java Matt Sherer ... real-time processing

Figure 3: Properly sampling the signal, with a 1Hz wave, 14Hz noise, samplingat 53Hz

16