BNMR: PPG compiler
bnmr and bnqr use Programmable Pulse Generator (PPG) to issue precise timing signals during a run. The timing schemes are different for each experimental mode, and may contain parameters that the user can set (e.g. how many "next bin" signals to send to the scalers, and the time between each of them). bnmr and bnqr use a system that was initially built for TITAN, where the PPG program to run is defined using ODB settings. At the heaart of this is a compiler (ppg_compiler_fe.py) that converts from these ODB settings to bytecode that can be loaded onto the PPG.
On TITAN, users directly edit the program structure using a web interface (e.g. adding/removing pulses, changing time delays etc). The PPG "building blocks" that the user can edit are documented here, but do not need to be understood by most users of the bnmr or bnqr DAQs. In brief: one can define loops, pulses, state transitions and delays, with timings relative to the start of each PPG cycle or the start/end time of any other "block".
On bnmr and bnqr, the overall structure of the program for each mode is not editable by users directly. Pre-set program structures are defined for each mode, and the user just edits a few parameters to affect the timing etc. The conversion from "questions the user answers" to "PPG program that the compiler can use" is handled by the RF calculator program.
The ppg_compiler_fe.py program simply takes the output of the RF calculator and builds the bytecode.
Both rf_calculator_fe.py and ppg_compiler_fe.py run on the host PC, while the PPG is programmed by the frontend, which runs on the VMIC. Naively the PPG compiler could write a bytecode file to disk, and the frontend could then read that file. However, NFS caching can be rather aggressive, and sometimes the frontend may get a stale file! For that reason, the frontend instead uses a midas JRPC interface to talk to the PPG compiler directly.
Therefore, at the start of a run:
- The RF calculator converts the "questions the user answers" to a "PPG program that the compiler can use", which is stored in the ODB
- The frontend calls the PPG compiler via JRPC, gets the bytecode, and loads it onto the PPG
Simulation and visualization
The PPG compiler also contains tools for simulating the program that will be run, and representing it as an interactive graph on a webpage. These are also exposed via a midas JRPC interface.
When the user wants to visualize the program on the settings webpage:
- The webpage calls the RF calculator via JRPC
- The RF calculator converts the "questions the user answers" to a "PPG program that the compiler can use"
- The RF calculator calls the PPG compiler via JRPC to compile the program, run a simulation, and return the graph as JSON
- The JSON is returned to the webpage, which uses Plotly to render and interactive graph
Comparison to legacy DAQ system
The old PPG compiler was based on template files, which were very limited. One had to specify which channels should be on, and how long to hold that pattern for. Consider the case where you have pulses on 2 channels, but the timing and width of the pulses vary. Depending on how the pulses overlap, you may need to create up to 6 different templates. This is both quite labour intensive, and can lead to copy/paste errors giving subtly different behaviour between the different versions.
The new compiler is written in python, and is more flexible and intelligent. It is based on time offsets and pulses, so the 6 different options are now all the same - you have a pulse on each channel. The new compiler figures out if the pulses are overlapping automatically, and will generate the appropriate bytecode.