Signal Processing Nodes

Triggering Nodes

class pyacq.dsp.AnalogTrigger(parent=None, **kargs)[source]

No so efficient but quite robust trigger on analogsignal.

This act like a standart trigger with a threshold and a front. The channel can be selected among all.

All params can be set online via AnalogTrigger.params[‘XXX’] = …

The main feature is the debounce mode combinated with debounce_time:
  • ‘no-debounce’ all crossing threshold is a trigger
  • ‘after-stable’ when interval between a series of triggers is too short, the lastet one is taken is account.
  • ‘before-stable’ when interval between a series of triggers is too short, the first one is taken is account.
check_input_specs()[source]

This method is called during Node.initialize() and may be reimplemented by subclasses to ensure that inputs are correctly configured before the node is started.

In case of misconfiguration, this method must raise an exception.

class pyacq.dsp.DigitalTrigger(parent=None, **kargs)[source]
check_input_specs()[source]

This method is called during Node.initialize() and may be reimplemented by subclasses to ensure that inputs are correctly configured before the node is started.

In case of misconfiguration, this method must raise an exception.

class pyacq.dsp.TriggerAccumulator(parent=None, **kargs)[source]

Node that accumulate in a ring buffer chunk of a multi signals on trigger events.

This Node have no output because the stack size of signals chunks is online configurable. sharred memory is difficult because shape can change.

The internal self.stack have 3 dims:
0 - trigger 1 - nb channel 2 - times

The self.total_trig indicate the number of triggers since the last reset_stack().

TriggerAccumulator.params[‘stask_size’] control the number of event in the stack. Note the stask behave as a ring buffer along the axis 0. So if self.total_trig>stask_size you need to play with modulo to acces the last event.

On each new chunk this new_chunk is emmited. Note that this do not occurs on new trigger but a bit after when the right_sweep is reached on signals stream.

after_input_connect(inputname)[source]

This method is called when one of the Node’s inputs has been connected.

It may be reimplemented by subclasses.

Filtering nodes

class pyacq.dsp.OverlapFiltfilt(parent=None, **kargs)[source]

Node for filtering with forward-backward method (filtfilt) using second order (sos) coefficient and a sliding, overlapping window.

Because the signal is filtered piecewise, the result will differ slightly from the ideal case, in which the entire signal would be filtered over all time at once. To ensure accurate results, the chunksize and overlapsize parameters must be chosen carefully: a small chunksize will affect low frequencies, and a small overlapsize may result in transients at the border between chunks. We recommend comparing the output of this node to an ideal offline filter to ensure that the residuals are acceptably small.

The chunksize need to be fixed. For overlapsize there are 2 cases:

  1. overlapsize < chunksize/2 : natural case; each chunk partially overlaps. The overlapping regions are on the ends of each chunk, whereas the central part of the chunk has no overlap.
  2. overlapsize>chunksize/2 : chunks are fully overlapping; there is no central part.

In the 2 cases, for each arrival of a new chunk at [-chunksize:], the computed chunk at [-(chunksize+overlapsize):-overlapsize] is released.

The coefficients.shape must be (nb_section, 6).

If pyopencl is avaible you can use SosFilter.configure(engine='opencl'). In that case the coefficients.shape can also be (nb_channel, nb_section, 6) this helps for having different filters on each channel.

The opencl engine inernally requires data to be in (channel, sample) order. If the input data does not have this order, then it must be copied and performance will be affected.

after_input_connect(inputname)[source]

This method is called when one of the Node’s inputs has been connected.

It may be reimplemented by subclasses.

class pyacq.dsp.SosFilter(parent=None, **kargs)[source]

Node for filtering multi channel signals. This uses a second order filter, it is a casde of IIR filter of order 2.

Example:

dev = NumpyDeviceBuffer()
dev.configure(...)
dev.output.configure(...)
dev.initialize(...)

f1, f2 = 40., 60.
coefficients = scipy.signal.iirfilter(7, [f1/sample_rate*2, f2/sample_rate*2],
            btype='bandpass', ftype='butter', output='sos')
filter = SosFilter()
filter.configure(coefficients=coefficients)
filter.input.connect(dev.output)
filter.output.configure(...)
filter.initialize()

The coefficients.shape must be (nb_section, 6).

If pyopencl is avaible you can use SosFilter.configure(engine='opencl'). In that case the coefficients.shape can also be (nb_channel, nb_section, 6) this helps for having different filters on each channel.

The opencl engine inernally requires data to be in (channel, sample) order. If the input data does not have this order, then it must be copied and performance will be affected.

after_input_connect(inputname)[source]

This method is called when one of the Node’s inputs has been connected.

It may be reimplemented by subclasses.