An agile software architecture has been developed for use as a framework in the coding and execution of tests and experiments. It employs object oriented programming, makes heavy use of design patterns, and supports the agile coding methodology, valuable to the iterative development found in scientific programming. Such methodologies enable flexibility in system design and allows for adaptation to changing requirements. The framework was implemented in the LabVIEW development environment, though the design is portable to most object oriented languages. It embodies an experiment execution package, a test builder package, several graphical user interface (GUI) services and an assortment of miscellaneous classes. This paper describes only the core framework, consisting of those services relevant to the execution of an experiment. This core consists of components shown in Figure 1. These include the test module interface, the test container class, the experiment service, and concrete implementations of the test module interface.
Figure 1: Class relation diagram for core experiment components.
The experiment service is responsible for the overall execution of the experiment. It contains a queue of test containers or modules, a data passing service, and a GUI service. All such services and modules are coded using interfaces (also referred to as virtual classes or dynamic VIs) rather than concrete classes. The use of interfaces in the design has a subtle but far reaching impact. The experiment service is not bound to any specific test, so it may run any class implementing the test module interface. The data passing service, responsible for passing data between objects, can be as simple as an array or provide an interface to a SQL server when data is large or reliability is paramount. The GUI service can be changed as needed without breaking the underlying process. All of these objects can be swapped at runtime and can be applied without breaking code in other modules. This design structure embodies elements of both the strategy pattern and the template method pattern.
The experiment service is started via the runExperiment() method. Tests objects placed on its queue are executed in series as shown in Figure 2.
Figure 2: A flow diagram representing a typical experiment.
Data are communicated between different test modules and the experiment service using a data passing object. Once the test queue is iterated, the experiment will either end, or loop for another round of testing, depending on state flags present in the data passing service. Individual tests are executed by passing the test object to the runTest() method. A test module has an initialization method, a sequence of cycle methods called at each time step, and a closing method called at the end as shown in Figure 3.
Figure 3: Flow diagram of Experiment.runTest() template method.
A test object, which defines a test, is constructed by placing a set of test modules into a test container as shown in Figure 4. The Concrete test module class usually implements some discrete functionality such as control logic, data processing or signal display. When many test modules are coupled together into a test container they define a complete test object.
Figure 4: Construction of an example test object which can be extended to include prognostic algorithms as they become available.
Using this design, many different tests can be constructed using the same base module classes. The Test object functionality can also be easily extended with additional test modules. Similar to the experiment class, this component orientated approach allows for test construction and modification during runtime. All test container methods delegate method calls to those methods of the same name in contained test modules, as noted in the code snippet on Figure 1. It is worth discussing that a test container is also a test module. Complex test containers may have an object hierarchy several layers deep forming a multi-node tree, the order of leaf method execution is dictated by a preorder traversal sequence. A call to a method within a test container iterates through all children test modules’ methods in series, but when run in a sequence, as shown in Figure 8, they are considered to run in pseudo-parallel, similar to procedural coding. This deterministic execution has some advantages over true parallelism, as one avoids challenges associated with multi-threading and race conditions.
Figure 5: An example test module utilizing the strategy pattern to assign device drivers dynamically.
Concrete test modules, which implement discrete functionality, also utilize the strategy pattern. Test logic for experiment control is constructed using generic device interfaces, rather than vendor specific device drivers. At runtime, any device driver that implements the respective interface can be passed into the module. Methods will be called from the implementing class, rather than the generic interface. Most drivers can be wrapped in an adapter, allowing a great deal of compatibility. An example of this pattern is shown in Figure 5. This pattern enables separation of test logic from vendor specific equipment, limiting dependency on aging legacy devices and poorly performing instrumentation and can encourage software collaboration between researchers.
Two test objects have been thoroughly developed in the LabVIEW development environment and others are under refinement. The first test object performs a thermal degradation scenario which self-heats a transistor to a specified temperature and holds it within a temperature boundary by gate switching. All transient, thermal and steady-state signals are acquired and recorded. In the event of a failure, the experiment is ended quickly to preserve the transistor. The second test object performs thermal impedance characterization of transistor package. Transistors are self-heated to a constant temperature with a known power setting. The transistor is then switched OFF, and its temperature decay is measured and thermal impedance shifts extracted. Additional aging software under refinement performs thermal cycling, injects hot carriers and induces electrical overstress. Additional characterization software under refinement measures gate impedance, perform pulsed I-V curve measurements and extracts switching characteristics.