A real life example of using SVG in data acquisition and control system domain. The system is currently being used by various airline and engine maintenance companies around the world, including N3 Engine Overhaul Services in Germany as the first customer. The major challenges involve:
GUI component creation using SVG.
GUI editor supporting SVG component.
Fast SVG rendering with continuously data updating (>20HZ)
Real-time enhancement on JFreeChart.
Table of Contents
Cenco International is recognized as a market leader in the design and supply of jet engine testing facilities and equipment. Cenco possesses both experience and expertise in working with all types of turbine engines from the largest high bypass aero engines to auxiliary power units (APU). Cenco's customer list consists of more than 150 airlines, airmotives, engine manufacturers and government organizations. Cenco has worked on jet engine test cell projects of every scale, all over the world for the past 50 years.
One key factor of its success is its highly customizable and flexible data acquisition and control system, designed to cater the unique needs and demands of the jet engine test cell. Usually, the system is built around existing or specially required hardware by customer. User interface and system control logic are greatly affected by the hardware selection and test cell design itself. The result is that different customer might have quite different look-n-feel for their systems even though they are designed to test the same type of engine.
Because the system's software is highly coupled with hardware design, it is often required to be field-programmable during system installation. This highly customizable nature essentially prohibits making separate software release for each installation because the associated cost can easily eat away the profitability of the entire operation. In 1990's, Cenco introduced a data acquisition and control system, CERES, with X window based user interface. The system is highly configurable on hardware configuration, control logic, calculating engine test data and user interface using TestBuilder.
In late 2003, Cenco started a project to build its next generation engine test software system, particularly, replace its aging X window based user interface with appealing, still field-programmable, web based user interface while maintain the rich functionality of the existing system. Also, the ability of remotely monitoring and controlling test system through web with live real-time test data updating at least 10 frames/second on multi-OS platform was determined to be one of the major features and product selling points.
In order to achieve speed to market, the strategy is to make best use of existing system and replace those matter the most to customers. It was achieved by creating a web service layer to turn traditional data acquisition and control system into an open platform and give user interface developer freedom to plug-in any presentation unit using the latest technologies, especially, SVG. It becomes possible to massive produce user configurable displays at very low cost.
Figure 3, “Overall Architecture” depicts the overall system architecture. Two lower layers, Device Driver Layer and Data Processing and Control Layer, already exists in the existing system and can be reused.
Device Driver Layer has a collection of drivers and new drivers are continuously added in per customers' request. Some typical device drivers are:
Fanuc PLC driver: is used to control GE Fanuc PLC as relay and digital I/O for facility and engine control. The driver directly talks to PLC using SRTP protocol via TCP/IP. It also supports analog I/O with calibration capability and improved scan rate. A low cost data acquisition and control system can be built mainly based on PLC for testing APUs.
External Controller driver: is used to communicate with Cenco's proprietary data acquisition unit.
Data Processing and Control Layer takes data gathered by device drivers and performs predefined calculations continuously. It also takes user input command and delegates it to specific device driver to perform a certain action. All raw data and calculated data are recorded continuously into external data log. Engine performance data are stored in to Oracle database for generating test report later.
Device driver layer and data processing and control layer reside on the same host computer. Shared memory is used for inter-process communication. The new system adds two branded new upper layers: Web Service Layer on the same host computer of the two lower layers and Client Layer on remote client computers. A typical test cell configuration needs at least 4 computers for different client layer applications: facility control, engine control, critical display and test report.
There are many different ways to delivery information over the internet. Server side technologies, such as: J2EE and .NET, focus on generating whole page on the server side and then deliver it to client side. Any client side action would trigger the whole page reload, which is bad for performance and user experience. Adding some client side technologies like AJAX to get partial page reload or only some elements updated could improve performance substantially.
However, each Jet engine test configuration has thousands of parameters. Each display page could easily has over 50 parameters and associated parameter limit information. During engine run, each parameter is displayed in real-time with at least 10 frames/second refreshing rate. Because lots of parameters are tight to analog signal, they are changing all the time. Generating new page and reload simply doesn't work. Therefore, our solution is to let all rendering happen on client side only. Once client application is loaded, it only exchangers data with server.
Web service layer is very thin and lightweight. It provides different type of web services: engine test and calibration, test report and plot analysis, and streaming data.
During engine test or system calibration, user needs to send a set of basic commands to start/stop test, turn on/off switches, set parameter to a certain value, etc. SOAP web service is chosen for this purpose and it is made interoperable between .NET and Java client.
Test report usually needs to retrieve stored test data and sometimes stored display images from database. Plot analysis needs to retrieve values for a set of parameters from external data logging. All of them get large amount of data in a single shot. It makes more sense for client to simply send HTTP GET request and server side gets data then sends them back in their native format instead of packaging them into SOAP messages with attachment.
User often captures some display images and wants to store those images back into database. The client application uses HTTP POST to send binary image data to back end server.
When massive amount of data needs to be delivered continuously, streaming data in binary format is the most efficient approach. Any other format, especially XML, simply creates too much overhead. Although there might be thousands of parameters, there are only a few hundreds of parameters need to be displayed at any moment. When the client opens a page, it issues a HTTP POST request with a list of parameters to be displayed. Then, the data streamer on the server side continuously takes data for those parameters from shared memory and streams them out over the internet.
Client layer has the following types of applications.
Excel reporting system: is a test report design and generation system built on the top of Microsoft Excel. It is consumer of test report web service.
Standard displays in Java: are some non-configurable displays or standalone applications, such: signal list, plot analysis, etc. Similar to real time stock quote, Signal list display needs updating large amount of data in relatively simple format in real time. In plot analysis, user can select a set of parameters and plot them against other parameter or time span. They are consumer for streaming data and report service.
.NET application for DVR playback: is used to playback test data in-sync with multi-channel video recording on the engine test process.
User configurable displays in SVG: are displays specially ordered by customer and they can be changed in the field or even during the engine test in progress.
Because of the uniqueness of this industry, large amount of displays are user configurable, which is also very important revenue source for the company. Therefore, lower the cost of massively producing those displays can improve company's bottom line. This is the main driver for us to adopt SVG. We have gone through a long journey finding the best approach of using SVG in our industry.
We started developing some sample pages (Figure 2, “Sample displays for Cenco's next generation data acquisition and control system”) using both Adobe Illustrator and Notepad. Later, a working prototype was developed and debuted at Paris Air Show 2005.
The container page is a HTML page and it gets load by regular URL.
Then, Java Applet gets loaded and stays idle.
Then, start loading SVG display.
Java applet starts remote data streamer and spawns a thread for handling streaming data. It also manages an internal cache for those parameters.
There will be no page reload unless user hits the refresh button.
Figure 5, “A typical engine control display” shows engine control display for CFM56 engine. There are on average over 20 custom displays for just one engine type. The development and testing effort would be enormous if we hadn't chosen the right technology.
Our approach is to create an application framework to support custom GUI components and let display designers directly use very simple configuration tool to assemble GUI components without even a single line of coding.
Although SVG defines rich set of graphic operations to describe complex graph, those operations are defined at a low level and developing SVG solution from scratch is still not a trivial job. In order to build a large scale application, reusable user interface component, class library and supporting tools are needed.
Take the display on Figure 5, “A typical engine control display” as an example. It has a few static cosmetic components, like background image, display title, and some decorative elements. Custom GUI components are put in foreground, including but not limited to:
Output Objects: An Output Object changes in response to underneath parameter value change.
Digital Objects: A Digital Object displays the value of a numerical parameter.
Text Label Objects : A Text Label Object can do one of two things: it can display the string contained in a string parameter or it can display a string based on the value of a numerical parameter (selection index value).
Status Indicator Objects: A Status Indicator Object displays a string based upon the value of a numerical parameter.. The color of the box and the text can change to indicate various conditions.
Bar Objects : A Bar Object draws a bar gauge that changes to indicate the magnitude of a numerical parameter.
Gauge Objects: A Gauge Object draws a needle gauge that changes to indicate the magnitude of a numerical parameter.
Plot Objects: A Plot Object draws an x-y graph based up the value of one x parameter and one or a group of y parameter(s). The plot type could be static plot, real time plot and real time scrolling plot.
Bitfield Objects: A Bitfield Object displays a parameter's value in binary format (bit-by-bit).
Input Objects: An Input Object converts keyboard, touchscreen or mouse actions into changes in parameter values or action command to the data processing layer.
Button Objects: include Push Button, Momentary Push Button, Toggle Button.
Radio Button Objects : Radio buttons have multiple states. When the user selects on the particular portion of the radio button, corresponding to a certain state, the action associated with that state performed. Also, numerical value of the parameter changes.
There are several different approaches to create GUI components in SVG:
Reusable components can be defined as symbol elements and put together inside a component library. SVG use element can refer to external symbol element as template and this is how SVG component gets reused.
Define new SVG tag for reusable component.
Using symbol element does have its limitation. Especially, it cannot encapsulate event handler inside symbol definition. The direct impact of this limitation is that there is no way to plug common behavior (event handling code) into component template and event wiring has to be done on each component instance.
Use SVG “g” tag is similar to what today's AJAX library does. Those libraries are easy to use but hard to make. Usually, each component must have some configuration information associated with it. It would be hard to design a XML schema to get those XML fragment validated.
Our approach is to use custom self-explanatory SVG tag to describe GUI component. Each custom tag definition has all event handlers and necessary functionality into one place. It communicates with outside world through its parameter node and some attributes, such as: enabled, visible. It can be positioned or scaled by setting the transform matrix. Here is the code snippets for defining a momentary button on Figure 5, “A typical engine control display”.
<ui:momentarybutton enabled="1" height="70" icon="" id="ui:momentarybutton315" set_value="1" tooltiptext=>"Momentary Push Button" transform="matrix(1 0 0 1 472.52470204846236 -9)" value="0" visible="1" width="75" x="174" y="583" buttonStyle="3"> <parameter name="IDGDisc_MB" value="0"/> <text_style font="Arial" fontstyle="bold" font-size="14"/> <label_config> <offlabel color="green" label="IDG\nDisconnect" text-color="black"/> <onlabel color="orange" label="IDG\nDisconnect" text-color="black"/> </label_config> <interlock>lockexp</interlock> <waitforcondition>waitexp</waitforcondition> </ui:momentarybutton>
By the time we were debating the technical direction, there are some similar technologies, like: SVG 1.2-RCC (Render Custom Content), XBL, XAML, etc. We found Adobe SVG Viewer 6.0 (ASV6) has by far the greater functionalities and the best graphic quality at that time to support creating custom component. It takes minimal effort to convert GUI component library from SVG 1.1 to SVG 1.2, and vice versus. However, we did realize some risks of going with SVG 1.2 approach:
SVG 1.2 specification was still at draft stage. Even as of today, only SVG Tiny 1.2 has became W3C recommendation.
Adobe SVG Viewer 6.0 was only a pre-release and it actually never gets released. Later, with Adobe's acquisition of Macromedia, Adobe eventually abandoned SVG in favor of Flash.
There wasn't any SVG authoring tool supporting SVG 1.2 yet.
Those risks could be fatal. There are some bright spots and alternatives:
Go SVG 1.2 costs only a fraction of other alternative approaches.
Other SVG viewers, like RENESIS player, could be emerged and support SVG 1.2 with better performance.
SVG 1.2 contents can be translated back into SVG 1.1 on the fly and let ASV3 or browsers with native SVG support to render its result.
Develop a SVG player with limited SVG 1.2 feature support.
Develop a special purpose GUI editor supporting SVG component.
Each GUI component has one or more data objects (parameters), representing the component data value, attributes, etc. Action on any Input Objects could change its internal state by changing the value of the parameter inside the parameter node, which fires a SOAP command to change the corresponding parameter value inside global data objects. On the remote site, data processing engine continuously executes pre-defined calculations at steady pace. The data is then streamed back to client displays and gets displayed mainly on Output Objects but it could affect behavior of Input Objects as well.
The application framework takes care of issuing SOAP command and distributing streaming data to GUI components. The client side developer only needs to take care of assembling GUI component and parameter mapping. This is very similar to the web development without AJAX. The only difference is that data binding is performed by on the client side. The application framework automatically syncs local data cache with global data objects via SOAP and streaming data. There are two special features on some GUI components:
Wait For Condition: is a boolean expression. When its evaluated value is false, the GUI component is in a unstable state and waiting for something. Therefore, The GUI component keeps blinking at steady pace until the condition is satisfied.
Interlock: is used to disable any GUI component when condition is satisfied. It is a boolean expression and applies to Input Objects only.
The boolean expression could be something like “paramA > paramB”, or simply as “paramC”etc. Those expressions can be configured to be evaluated either locally at client side or preferably at server side by data processing engine because the expression can be shared by multiple client displays.
The behavior of data processing engine is configured in a way similar to PLC's ladder logic using VB like language. Because the data processing is performed at steady pace continuously, no loop statement is even needed.
Even until now, there isn't any commercial off-the-shelf or open source SVG editor supporting SVG 1.2, especially with custom component. Due to the complexity of SVG 1.2, it is not wise to implement a SVG editor from scratch. A feasible choice is to add custom component feature on the top of existing SVG editor and there are some open source editors available as well:
Because implementing SVG with custom component is not a trivial job, the simplest approach is to make the best use of Adobe SVG Viewer 6.0, which has most of SVG 1.2 supports already. We recognize the superiority of Adobe Illustrator in creating static SVG part. Our SVG based GUI editor targets mainly on assembling SVG custom components, data binding configuration, and simple SVG editing. That editor could be developed using SVG language itself, just like SVG Draw from Adobe. In fact, SVG Draw itself can be used to edit SVG custom content already even without any change if we use ASV6 instead of ASV3 plugin .
SVG graph itself is a XML file and can be accessed through SVG DOM. The content of a SVG graph can be dynamically updated by changing specific XML node, just like today's AJAX libraries. If SVG Draw is run under ASV6, just adding custom component node into a grouping element “g” and it will be rendered appropriately. We learned a great deal of SVG editing technique from SVG Draw and came out with our solution.
Although Adobe SVG plug-in could be used as ActiveX control directly or through IE control into a .NET application, we took the browser based approach. The whole editor is put inside a web browser, Java Script is used to manipulate SVG content through SVG DOM, and Java Applet is used to implement standard menus, toolbars and configuration dialogs. The display editor consists of the following four major parts:
Menu bar, Tool Bar and Attribute configuration dialogs are implemented in Java.
Java Script is the main part of the editor. It consists of some event handlers to control the display drawing process. It also serves as a delegate to let Java component be able to manipulate SVG.
Toolbox is a tabbed panel listing customized reusable components from the library.
Drawing area is a SVG panel.
Similar to using Microsoft Visio, selecting a GUI component from toolbox panel, then drag-n-drop it into the drawing area. Each component item's property can be further configured through item property dialog by clicking on “Item Property” icon on the toolbar. The most important configuration is to wire the component with parameter to define data binding.
However, the pure browser based SVG application does have some performance issues no matter whether it uses plugin like ASV or uses browser with native SVG support. When lots of data come in at high speed, the CPU usage of the client computer can easily reach 100% because lots of computing power is consumed to update SVG DOM and SVG rendering. That is one of the reasons we added an invisible Java Applet (Figure 4, “SVG based displays using Adobe SVG Viewer”) in the browser based web client to reduce the frequency of SVG DOM updating by filter out data with only insignificant change. This approach works very well especially for displays with data coming from digital signals, such as: displays with lots of status indicator, buttons etc. However, for displays with lots of gauge, bar and digital objects, it doesn't help much because data for those objects come from analog signal, which changes all the time.
We had put lots of effort in improving the code efficiency of component library. Even after replacing SVG filter with gradient or just simply using solid color, the performance hasn't been improved much. We also found grouping custom components together inside a new “g” tag can improve performance but it is just not good enough. Our test result shows the maximum refreshing rate can only achieve 5 frames per second with only one display page opened. However, the refreshing rate of 10 frames per second with multiple displays is typically required by customer.
Unfortunately, Adobe abandoned the development on SVG and didn't open source its SVG Viewer. The release of RENESIS player had been delayed many times and we never got chance to use it. Later, we did some tests on Firefox with native SVG support but its functionality and performance was not nearly as good as ASV3 or ASV6. Unless there are some breakthrough on browser performance supporting SVG, fully depended on external resource to render SVG simply can not satisfy the performance needs in real time data acquisition. Therefore, we need to build our own SVG rendering engine.
On the section called “Custom GUI Components”, custom components are put on foreground while static cosmetic components are in background and in the separated grouping “g” tag. Therefore, the background components for any display, no matter how complex they are, can be rendered into one image buffer just once and stored. Unless the screen is resized, the stored image can be reused. The foreground custom components need to be rendered when its binding data changes. However, a smaller buffer can also be used to improve performance.
Based on this concept, we started creating our own SVG rendering engine using Batik SVG Toolkit. The Batik modules are of one of three types: application modules, core modules and low level modules. The core modules are mostly used to manipulate, generate, render and view SVG content. Using Transcoder API, the static SVG part is rasterized into an image. Using Batik Swing components module, each custom SVG component (translated back to SVG 1.1 already) definition in the component library is used as a resource file to create a JSVGCanvas object, which is rooted from JComponent. The process of rendering a display can be summarized as:
Give the whole display content to Transcoder API to rasterize into image and use it as background image for JPanel. Because Batik only understands SVG 1.1 part, the custom components are ignored.
Parse the display content again and only look for the place referring to custom components. For each custom component referring, find the SVG definition for that component in the component library and create a JSVGCanvas object.
Add JSVGCanvas object into JPanel to get it displayed.
This could be a quick and easy way to render SVG custom component but it lacks of desirable performance. Our experiment shows:
It takes a while for Transcoder API to rasterize a SVG image.
Using JSVGCanvas to load custom SVG component is quite slow. When creating multiple JSVGCanvas objects, sometime some complex objects cannot be displayed appropriately. It could take 10 minutes to load a display like Figure 5, “A typical engine control display”.
It uses lots of memory.
Therefore, we need to dive deeper to try Low Level Modules for better performance. In fact, we developed a very simple and efficient SVG rendering library to create a collection of Java2D objects from any SVG graph with some basic SVG elements, including: circle, ellipse, image, line, path, polygon, polyline, rect, text, linear and radial gradient, and symbol. It can be directly used to render SVG static content in the background of any display.
Most of custom component type could find a surrogate host from Java standard GUI component to manage its state and event handling. Take custom button object as an example. No matter how fancy it might look, it behaves just like any other standard buttons. The following is the SVG part of a custom button definition.
<svg xmlns="http://www.w3.org/2000/svg" width="100%" height="100%"> <g> <g id="button_Down" transform="translate(0 -470.9) scale(1.33 2.802)"> <g> <polygon style="fill:#AFAFAF;" points="71,199 75,203 0,203 4,199"/> <polygon style="fill:#6F6F6F;" points="75,203 75,168 70,172 70,199"/> <polygon style="fill:#6F6F6F;" points="0,168 4,172 70,172 75,168"/> <polygon style="fill:#AFAFAF;" points="4,172 0,168 0,203 4,199 "/> <rect x="4" y="172" style="fill:#7F7F7F;" width="66" height="27"/> </g> <rect id="Down_Color" fill-opacity="0.5" x="0" y="168.16" width="75" height="35.62" style="fill:lightgrey;"/> <text id="Down_Label" x="37.529" y="186" text-anchor="middle"> <tspan> </tspan> </text> </g> <g id="button_Up" transform="translate(0 -470.9) scale(1.33 2.802)"> <g> <polygon style="fill:#AFAFAF;" points="4,172 0,168 75,168 70,172"/> <polygon style="fill:#6F6F6F;" points="0,168 0,203 4,199 4,172"/> <polygon style="fill:#6F6F6F;" points="75,203 70,199 4,199 0,203"/> <polygon style="fill:#AFAFAF;" points="70,199 75,203 75,168 70,172"/> <rect x="4" y="172" style="fill:#7F7F7F;" width="66" height="27"/> </g> <rect id="Up_Color" fill-opacity="0.5" x="0" y="168.16" width="75" height="35.62" style="fill:lightgrey;"/> <text id="Up_Label" x="37.529" y="186" text-anchor="middle"> <tspan> </tspan> </text> </g> </g> </svg>
It defines Up and Down states and their corresponding look. Other button appearance, such as: mouseover or hover, could also be defined. Then, the remaining task is creating a custom UI delegate for JButton but using SVG rendering engine to paint for each state. Jon Lipsky has an excellent blog on how to do custom UI delegate. Using SVG, the appearance for each state can be developed using graphic design tool, such as: Illustrator, instead of coding directly in Java2D.
Other type of custom component without corresponding standard component as surrogate host has to be handled on case by case basis. A good example is “Plot Objects”.
There are many different types of plot objects used in Jet engine testing, such as: performance plot, real-time plot and real-time scrolling plot. Due to the complexity of those plots, implementing them even in SVG is not easy. Therefore, they are implemented using JFreeChart package directly without corresponding SVG implementation in the component library. JFreeChart is a free Java chart library and supports wide variety of chart types. Here is an example of a combined chart created using JFreeChart.
Create a chart like this still need some coding even when using JFreeChart. We have to at least define dataset and then create several chart objects and combine them together. Just like other custom GUI component, we provide a custom tag for plot object and use it to configure the chart behavior without coding in Java. However, the more difficult and important task is to find a way to enhance JFreeChart by adding real-time charting capability.
Although JFreeChart is excellent in creating large variety and high quality chart, it doesn't support real-time charting. In many cases, real-time charting is a very important feature to have, for example: intra-day stock chart for financial applications. Data acquisition system in Jet engine testing requires data refreshing rate at least 10 times per second for real-time plots, which is impossible for JFreeChart to handle. The primary reason is that JFreeChart does a complete chart repaint, including chart border, title, Axis, etc, whenever dataset is updated.
The idea of implementing real-time charting is actually very simple: Just let JFreeChart to use chart buffer and draw point incrementally into the chart buffer instead of adding new point into dataset. To be more specific, the dataset should have a maximum size and be implemented as a ring buffer. For any real time point, only the draw the latest two points because previous points have been drawn into chart buffer already. Only when chart gets resized, chart buffer will be refreshed and all points in dataset have to be redrawn. This change makes JFreeChart can draw real-time chart easily over 30 times per second. For more information, please check my post on JFreeChart Forum.
The choice of turning a traditional data acquisition and control system into an open platform and building a presentation framework based on SVG has been proven to be successful. Until now, Cenco's new data acquisition and control system has been installed and in production use in Germany, India, Saudi Arabia, Egypt, China and growing.
In order to achieve better performance, the current system is implemented based on SVG and Java. It could be implemented based on SVG and .NET. When data updating rate is much lower, pure browser based approach with native SVG support, such as: Firefox and Google Chrome, could be used as a much simpler alternative.
We hope there will be some AJAX libraries specific for SVG in the future, which could be a major boost for SVG.