LabVIEW and Accelerator Control Systems
Graphical Versus Traditional Programming
Our teams develop full-stack control systems using the usual programming languages in the domain, such as VHDL, C++, C# and Java, but we also leverage the unique capabilities of LabVIEW.
The latter is a system-design tool and development environment for visual programming from NI. The environment has a graphical language and runs on Microsoft Windows, Unix, Linux, and macOS. Engineers typically use LabVIEW for instrument control, data acquisition, and industrial automation. Specific customers that rely heavily on NI hardware, for example, in the accelerator community, stipulate the use of LabVIEW for their device and systems integrating, so we comply — and in other cases may even advise it ourselves. In some instances, whole accelerator control systems are built with LabVIEW.
Relatively simple basic visual programming concepts of LabVIEW allows non-programmers to build programs by dragging and dropping virtual representations of simple laboratory devices. Advanced LabVIEW shops, however, employ more demanding LabVIEW programming for creating larger, distributed and self-sufficient applications using LabVIEW object-oriented programming (LVOOP) and other more complex programming concepts.
A Typical Cosylab Accelerator Control System
We usually design accelerator control systems with a three-tier architecture:
- Presentation tier – presents and handles user interaction;
- Service tier – is composed of services, such as alarm handling, archiving;
- Equipment tier – integrates devices and subsystems (in our example, based on LabVIEW);
The Equipment tier is comprised of a set of distributed services responsible for the integration of devices and subsystems. It takes care of both business logic as well as the communication of disparate subsystems and devices.
The Old Way of Creating God Classes
We typically observe in our integration projects, also where we use LabVIEW, that we can continually improve, refactor and optimise our development approach, replacing past practice.
In the past, we would usually create one big (god) class per device/subsystem type, whose methods represent values in the system (data points), such as set_voltage, set_acceleration, get_voltage, get_alarm, clear_alarm.
For example, as seen by the operator, the voltage must be limited to a range, multiplied by a factor, and added an offset before it is written to a register on the device.
In this case, we need additional parameters or class properties — or the original methods need extra parameters, for example, set_max_voltage, set_min_voltage, set_acceleration_scale …
The list can get long, and a lot of parameters require more or less similar processing.
Since some subsystems/devices possess many control parameters, even more than a hundred, such required functionality results in plenty of almost duplicated coding, which is prone to errors and lowers the maintainability.
The New Solution: Device Parameters as Objects
Even in LabVIEW we can use object oriented concepts as in other traditional programming languages to avoid this mostly duplicated coding. Let’s think of device parameters as objects, identify types of variables on the control system and preparing a class for each of them! One of the simplest and most commonly used is the real value:
class Double() {
write(double)
double get()
set_max(double)
set_min(double)
set_scale(double)
set_offset(double)
}
Note: For clarity of examples, we use C++ like pseudo code to represent ideas implemented with LabVIEW graphical programming.
Such a class aims to transform the variable from the CS representation to the device/subsystem controller representation (and vice versa).
In the simple example above, solely scaling and limiting is enabled. Still, we can apply the same principle to more complex parameters, where the CS variable requires interaction with multiple device registers to perform an action.
A simple example of more complex variables is the device’s state.
The transition of the state requires multiple steps and interaction with multiple device registers:
- check multiple parameters whether the transition is possible;
- go to state;
- check whether the transition is ok;
We can then represent each of the variables as an object of its respective class:
Double voltage,
Double acceleration,
State powerSupplyState;
With a collection of these objects, we can describe a device. In a trivial case, the objects can be simply indexed by the control system variable handles (names); thus, the code can mostly be agnostic of the actual variables.
But Wait, God Class is not Yet Gone
Class Double is still somewhat of a god class. The functionalities of the class are still exposed as methods.
In the next step, we can modify the actions that are performed on the variables —
min, max, linear scaling.
Note; these actions are reusable regardless of which device type we’re dealing with.
We introduce a family of decorator classes whose responsibility is to modify the values of the control system.
class Decorator {
variant Update(variant)
}
The decorator has an update method that takes input and transforms it, then returns the transformed input.
Example:
class LinearScaler<–Decorator { void Init(double k, double n)
variant Update(variant var) {
return k * var + n;
}
}
class Min<–Decorator { void Init(double min)
double Update(variant var) {
variant scale * var;
}
}
Conclusion: LabVIEW Has its Place in a Modern Accelerator Control System
Some software developers who use traditional programming are convinced that visual programming is ineffectual, too simplistic and not deserving of their time.
Years ago, we, too, held such beliefs. But then we started using LabVIEW in complex setups, as required by several of our customers. Namely, the latter were already using LabVIEW at a large scale for controlling their extensive NI hardware infrastructure. It was not long that we realised the potential of system building with LabVIEW. We started using it in ways that taxed ourselves and elevated the LabView potential to its highest level of useability and performance.
There are three general skills that a sound software engineer must possess — but they also play a central role in a visual programming environment, such as LabVIEW:
- using logic to solve a problem,
- realising an efficient solution efficiently and
- applying the solution in a way that is both understandable and maintainable.
We believe that with thoughtful design and planning, the benefits of using LabVIEW applications can be increased.
As with other programming environments, it also holds for LabVIEW. Thoughtful planning at the very onset of development, such as creating a clean architecture, can help us significantly streamline the development of a control system and achieve better dependability and maintenance.