R030 Signal Script Production
Outline
Signal scripts allow the users to analyze and interpret signals in many ways. Combine signals using mathematical operations, generate references, implement protocol parsers, extract statistical informations or search for conflicts automatically.
Platforms: |
|
|||
Requirements: |
|
|||
Known limitations: |
|
|||
Status: |
|
|||
Input signals: |
|
|||
Output signal: |
|
|||
Parameters: |
|
|||
Operation: |
Video
How to create a signal script ?
Signal scripts can be created either using the template menus Add->Scripting - xxx or by changing an existing configuration item into a script production, using the configuration dialogs Production combo box.
Input Signal Configuration
- Primary Source
- The primary source is the first source signal of the production. For productions with multiple inputs it can be left empty, thus the first input is taken from the "Additional" sources.
- Additional (Sources)
- If more than 1 source signal is required, add them into this table. Instead of using the table you may drag and drop (with a closed dialog) signals onto the plot item.
The production accepts 0..N input signals.
Output Signal Configuration
Productions are executed on the fly, as soon as the signal data is required for further processing, and re-executed when settings or input signal have been changed. Before executing a production, the system needs to know the source signals, the type and the domain of the signal. All these informations need to be entered into the plot configuration dialog. If you leave the configuration fields empty, impulse tries to extract the information from the sources. The fields will display this information in light gray <e.g. Derived(Float)>.
- Process type
- You may select between discrete and continuous process type.
- Signal type
- Select the output signal type of your script (Float, Text, Logic, Integer, ..).
- Signal descriptor
- The signal descriptor describes the signal type in more details (e.g the bit width of a logic vector (default<bits=16>)). See below for more details. But in most case, you will use the standard settings (default<>) - Press CTRL-Space to view content proposals.
- Domain Class/Base
- The domain base is just required if your output signal has a different domain than the source signals. If not, just don't touch these settings.
- Domain Range
- Use this field to set the domain range, so the minimum and maximum value of the domain (e.g. 0 .. 1000 Hz)
Production Configuration
- Script: Enter the signal script definition.
- Timeout[ms]: Increase the value in case of timeout events.
Enter the script into the text field or use the build-in script editor. To avoid system timeout, the timeout parameter may be set.
How to get started with scripting ?
Have a look at the script examples. Select a script that is close to your requirements, than copy script and settings into the dialog. Most script examples are also available at the template menu.
10 Signal Script Script Examples
Use the eclipse script editor
You may use the built-in script editor instead of the text field in the dialog. Click on "Edit in js editor" to open a new eclipse editor. As soon as you save the content, its signals will be updated and changes get visible in a parallel impulse viewer. If there are errors in the script, log messages will be send to the console view.
The script itself
The impulse JDK
No matter if you develop a reader, a recJs script, a search expression or a Signal Script production, impulse provides you always with the same interfaces to read, compare, analyze or generate signal data.
impulse JDK Open JavaDoc Reference
Intro
Impulse uses JavaScript as its default language (other languages might be added in future). Rhino interpreter is used up to Java 6 and above the Nashorn interpreter that uses the byte code engine of java and improves performance a lot. The available scripts are compatible for both interpreters.
The typical goal of a script is to read the content of source signals and create one output signal. A simple script looks like this:
// input: an array of all input signals // in0: primary input of type ISamplePointer,IReadableSamples // in1..: additional inputs of type ISamplePointer,IReadableSamples // out: output signal of type IFloatSamplesWriter // console: console output of type MessageConsoleStream // iter: iterator of type ISamplesIterator // progress: progess control of type IScriptProgress progress.cont(); while ( iter.hasNext()) { var current <:Long:> = iter.next(out); out.write(current, false, input[0].floatValue() + input[1].floatValue()); }
SamplesIterator instance tier allows to iterate over events of multiple source signals. 'iter.next()' returns the current domain value (e.g current time). All input variable can be accessed as signal pointers: For each event found, the iterator set the pointers to the current position, e.g. floatValue() returns the float value at that position.
Variable out represents a samples writer of the configured type (e.g.
IFloatSamplesWriter). You create the new signal by writing consecutively new values at given domain
positions (write(domainValue,conflict,value).
The IScriptProgress instance progress let
you control the execution of your script.
The line progress.cont()
in the above example handles the execution of the script when the signal is extended (when you use
a port, and data will be continuously added). If new data has been read, the script will be called
again. With the above line, the iterator item will be pointed to the position
of the previous end. If the line is not included, iter is set to the first
source sample, and the script has to run over the complete signal again.
If there is just one input and data shall not be extended, you can simply iterate in the following way. Instead of floatValue(), you use floatValueAt(eventIdx).
for (var i=0;i<in0.getCount();i++){ real[i] = in0.floatValueAt(i); }
in0,in1,...,inN and the input array
Lookin into the script example and templates, you will find input definition like "in0" and "in1" and also the variable "input". The first ones (in0,in1,..) allow you to reference inputs configured in the plot dialog (you will find on the left side of the plot dialog). "in0" refers to the primary input, in1 (and in2,..)refere to the additional inputs. The variable "input" combines all configured inputs into one array (this may include in0, if a primary input is configured, or not).
Reading the input
All input references combine the interfaces ISamplesPointer and IReadableSamples. The IReadableSamples interface defines the basic reader interface. It has methods like:
- getCount()
- valueAt(int idx)
- intValueAt(int idx)
So you can get the total number of available samples and use one of the accessor methods to get the value at a given index.
The ISamplesPointer inteface allows to modify an index and read the value at the current index. You find functions like:
- setIndex(int idx)
- goPrev()
- goNext()
- val()
- intValue();
If an input has a an additional dimension (struct members or arrays) you might read the value object and use the member accessors:
- structAt(n).intValueOf("max")
- intValueOf("max")
If you use a SamplesIterator, all pointers are updated by the iterator automatically. There is no need to use 'goNext()','goPrev()',... implicitly.
while ( iter.hasNext()) { .... in0.intValue() .... }
Writing the output
Each signal type comes with a writer interface. The integer signal uses the IIntegerSamplesWriter interface (float: IFloatSamplesWriter, ...); a simple write includes the parameters for domain position, a conflict flag and one or more parameters describing the value.
In the IIntegerSamplesWriter example, we have three write methods for three value types (mainly used in Java); and three additional method with modified names for scripting purpose.
public interface IIntegerSamplesWriter extends ISamplesWriter{ boolean write(long units, boolean conflict, int value); boolean write(long units, boolean conflict, long value); boolean write(long units, boolean conflict, BigInteger value); // scripting boolean writeInt(long units, boolean conflict, int value); boolean writeLong(long units, boolean conflict, long value); boolean writeBig(long units, boolean conflict, BigInteger value); }
The parameters have the following meaning:
- units
- Domain position as no of domain units (e.g, domain base:ns, units = 1000 -> domain position = 1us)
- conflict
- Define this sample as a conflict one.
- value
- The given value in different formats (integer/long/BigInteger)
Handling time, frequency,...
As seen before, the domain value is given as a multiple of its domain base.
The domain base of the sources and the output are pre-set by the system, in case of the output, you can override the domain base in the plot dialogue (required if there are no inputs; just do in case you know what you do). You can get the actual domain base by using the getDomainBase() method.
If you are using a SamplesIterator, the current domain position is returned by the next() method.
for (var iter <:ISamplesIterator:> = new SamplesIterator(input); iter.hasNext();) { var current <:Long:> = iter.next(out);
Please be aware that the value is returned as a Long object. This Long object is not converted into any JavaScript type (as it is done for Integer and Float values).