Xilinx
HLS
Block Preview

Introduction

The Peak PSD HLS block integrates the charge of a pulse over two gates, measures the peak amplitude of the same pulse, and forms a discrimination ratio as

$$ \mathrm{PSD} = \frac{\mathrm{PEAK}}{Q_{short}} $$

This is what separates it from the QDC/PSD HLS block, where the ratio is formed between two charges. Here the numerator is the height of the pulse and the denominator is the charge of a gate that can be delayed with respect to the trigger, so the ratio compares the prompt amplitude against the charge of the tail.

The block provides, for every accepted event:

  • Qlong: charge integrated over the long gate, raw (32 bit) and scaled (16 bit)
  • Qshort: charge integrated over the delayed short gate, raw and scaled
  • PEAK: the maximum sample of the pulse, baseline subtracted
  • PSD: the peak-over-Qshort ratio in fixed point
  • TIMESTAMP: the value of TIMETAG latched at the end of the long gate

The core is written in Xilinx HLS and runs at II = 1: it accepts one sample per clock and never back-pressures.

Pin Description

AN In Input 16 bit BIT VECTOR
16-bit sample stream from the ADC, one sample per clock. Connect it to the detector chain output (directly, or after a shaper / filter).
Default: Must be connected
TRIGGER IN Input 1 bit BIT
Trigger input. The block starts on the rising edge, so a level that stays high triggers once, not continuously. A trigger that arrives while INIB is high is counted as a rejection.
Default: Must be connected
BASELINE IN Input 16 bit BIT VECTOR
16-bit baseline subtracted from every input sample before anything else happens. Connect it to a baseline restorer, or tie it to 0 if the signal is already centred. The subtraction is done on 17 signed bits, so samples below the baseline stay negative.
PRE INT Input 16 bit BIT VECTOR
Pre-trigger depth in samples: how far back in the delay line every gate starts. 0 bypasses the delay line and works on the live sample. Must stay below 256, the depth of the delay line. Typical values: 5 to 50 samples, enough to contain the leading edge of the pulse.
QLONG TIME Input 16 bit BIT VECTOR
Length of the long gate in samples, counted from the pre-trigger point. It should cover the whole pulse including its slow component. It is also the dead time of the block: a pile-up reloads this counter in full.
QSHORT TIME Input 16 bit BIT VECTOR
Length of the short gate in samples. Together with QSHORT DELAY it selects which part of the pulse ends up in the denominator of the PSD ratio.
QSHORT DELAY Input 16 bit BIT VECTOR
Delay, in samples, between the start of the gates and the opening of the short gate. 0 makes the short gate a prompt gate; a non zero value makes it a tail gate that skips the leading edge. Declared stable in the HLS core: do not change it while the block is acquiring.
PEAK WINDOW Input 16 bit BIT VECTOR
Number of samples, from the pre-trigger point, over which the maximum is searched. It must be long enough to contain the peak of the pulse and short enough not to pick up a later, unrelated excursion. Negative samples are clamped to zero before the comparison. Declared stable in the HLS core: do not change it while the block is acquiring.
POST INIB Input 16 bit BIT VECTOR
Extra dead time in samples after the long gate closes. A trigger inside this window raises REJ and reloads the full dead time.
GAIN Input 16 bit BIT VECTOR
Scaling factor applied to the 32-bit charges to produce the 16-bit ones, with 16 fractional bits: Q16 = (Q32 * GAIN) >> 16. 65535 is approximately unity gain, 32768 halves, 6554 divides by ten. The result saturates at 65535 and is clamped to 0 when the charge is negative.
TIMETAG Input 64 bit BIT VECTOR
64-bit free running time counter, sampled at the end of the long gate and presented on TIMESTAMP. Connect it to a Timestamp Generator block.
RST_STAT Input 1 bit BIT
While high, clears the two rejection counters REJ_CNT and DREJ_CNT. The measurement itself is not affected.
CLK Input 1 bit BIT
Clock input. Connected to the global acquisition clock if left unconnected.
Default: Default Board Clock
RESET Input 1 bit BIT
Reset input. Connected to the global reset if left unconnected.
Default: Default Board Reset
DATA_OUT Output 16 bit BIT VECTOR
The sample the block is actually working on: baseline subtracted and delayed by PRE INT. Probe it to verify baseline and pre-trigger before trusting the charges.
DATA_VALID Output 1 bit BIT
One clock pulse at the end of the long gate, only for events with no pile-up. Use it to qualify every other output. A spoiled event updates the outputs but produces no pulse here, so downstream blocks never see it.
QLONG_32 Output 32 bit BIT VECTOR
Long gate charge, 32 signed bits, unscaled. This output is live: it follows the accumulator while the gate is open. Sample it with DATA_VALID.
QSHORT_32 Output 32 bit BIT VECTOR
Short gate charge, 32 signed bits, unscaled and live, like QLONG_32. It is the denominator of the PSD ratio.
QLONG_16 Output 16 bit BIT VECTOR
Long gate charge scaled by GAIN and saturated to 16 bits, latched at the end of the gate. Meant to feed a spectrum block directly.
QSHORT_16 Output 16 bit BIT VECTOR
Short gate charge scaled by GAIN and saturated to 16 bits, latched at the end of the gate.
QLONG_GATE Output 1 bit BIT
High for the clock cycles in which the long accumulator is being fed. Useful to verify gate placement on a logic analyser.
QSHORT_GATE Output 1 bit BIT
High for the clock cycles in which the short accumulator is being fed, that is after QSHORT DELAY and for QSHORT TIME samples.
PEAK Output 16 bit BIT VECTOR
Maximum baseline-subtracted sample found inside PEAK WINDOW, latched at the end of the long gate and held until the next accepted event.
PSD Output 32 bit BIT VECTOR
The discrimination ratio PEAK / Qshort in fixed point with 16 fractional bits: divide by 65536 to read it as a real number. Forced to 0 when Qshort is zero or negative.
TIMESTAMP Output 64 bit BIT VECTOR
TIMETAG latched at the end of the long gate, 64 bits.
INIB Output 1 bit BIT
Busy flag: high for the whole long gate, the tail computation and the post inhibit window. Fan it out to the trigger logic to suppress triggers the block cannot accept.
REJ Output 1 bit BIT
One clock pulse for every trigger rejected after the event was already spoiled, or during the post inhibit window.
DREJ Output 1 bit BIT
One clock pulse when the first pile-up hits an event still inside its long gate, that is a genuine double pulse.
REJ_CNT Output 32 bit BIT VECTOR
Free running 32-bit count of the REJ pulses. Cleared by RST_STAT.
DREJ_CNT Output 32 bit BIT VECTOR
Free running 32-bit count of the DREJ pulses, that is of the events lost to double pulses. Compare it with the accepted count to estimate the pile-up fraction. Cleared by RST_STAT.

Functional description

Baseline subtraction and pre-trigger

Every incoming sample is baseline subtracted first, on 17 signed bits, so a sample below the baseline stays negative instead of wrapping:

  sample = AN_In - BASELINE_In
  

The result goes into a 256-position delay line. PRE INT selects how far back the block reads from that line, which is what lets every gate start before the trigger arrives and capture the leading edge of the pulse. With PRE INT = 0 the delay line is bypassed entirely and the block works on the live sample.

The delay line is 256 deep: PRE INT must stay below 256. A larger value wraps the read pointer and returns a sample from the wrong position.

Everything downstream - the long gate, the short gate and the peak search - works on this delayed, baseline-subtracted sample, never on the raw input. DATA_OUT brings it out so you can probe exactly what the block is integrating.

The three measurements

On the rising edge of TRIGGER IN the block loads its counters and starts. The three measurements run in parallel and all of them are referenced to the pre-trigger point, not to the trigger itself:

Measurement Starts at Lasts Accumulates
Qlong pre-trigger point QLONG TIME samples every sample
Qshort pre-trigger point + QSHORT DELAY QSHORT TIME samples every sample
Peak pre-trigger point PEAK WINDOW samples the maximum

QSHORT DELAY is what makes this block different from a plain dual-gate QDC. With a delay of zero the short gate is the usual prompt gate; with a non zero delay the short gate skips the leading edge and integrates only the tail of the pulse, which is the part whose weight depends on the particle type in an organic scintillator.

The peak search clamps negative samples to zero before comparing, so undershoot before the pulse can never win the maximum. PEAK holds the value of the last completed event until the next one replaces it.

QLONG_GATE and QSHORT_GATE are the two gates brought out as digital signals: they are high exactly for the clock cycles in which the corresponding accumulator is being fed. They are the fastest way to check, on a scope or a logic analyser, that the gates land where you think they do.

The PSD ratio

At the end of the long gate the ratio is computed as

$$ \mathrm{PSD} = \left\lfloor \frac{\mathrm{PEAK} \cdot 2^{16}}{Q_{short}} \right\rfloor $$

so the 32-bit PSD output carries 16 fractional bits: divide it by 65536 to read the ratio as a real number. When Qshort is zero or negative the output is forced to 0 instead of producing a division by zero.

Output scaling

QLONG_32 and QSHORT_32 are the raw accumulators, on 32 signed bits, and they are live: they follow the integration while the gate is open. The 16-bit twins are computed once at the end of the long gate as

  Qn_16 = (Qn_32 * GAIN) >> 16        saturated to 0xFFFF, clamped to 0 if negative
  

GAIN is therefore a fractional multiplier with 16 fractional bits: 65535 is a gain of approximately 1.0, 32768 halves the value, 6554 divides it by ten. Use it to bring the integral of your typical pulse into the range of a 16-bit spectrum without adding a separate scaling block.

If you need the exact charge, read the 32-bit outputs and sample them with DATA_VALID. The 16-bit ones are meant to feed a histogram directly.

Pile-up and dead time

The block is paralysable: a trigger that arrives while the block is busy does not just spoil the current event, it restarts the full long-gate countdown. Under a high rate the block therefore stays busy rather than producing corrupted events.

The two rejection causes are separated because they mean different things:

Output Counter Fires when
DREJ DREJ_CNT the first pile-up hits an event still inside its long gate
REJ REJ_CNT any further trigger while the block is already spoiled, or a trigger during the post-inhibit window

DREJ counts events lost to genuine double pulses; REJ counts the extra triggers that arrive while the block is already recovering. In a clean spectrum DREJ_CNT is the number you want to compare against the accepted count to estimate the pile-up fraction.

INIB is high for the whole busy period - long gate, tail computation and post inhibit - and is meant to be fanned out to whatever generates your trigger, so it can be held off.

After the long gate closes the block waits POST INIB further samples before arming again. A trigger inside that window is rejected and, again, reloads the dead time.

DATA_VALID pulses for one clock only if the event survived: if any pile-up occurred, the outputs are still updated but no DATA_VALID is produced, so a downstream list or spectrum block simply never sees the spoiled event.

RST_STAT clears REJ_CNT and DREJ_CNT while it is high; the two counters are free running otherwise and wrap at 2^32.

Timing

 

QSHORT_GATE opens QSHORT DELAY samples after the gates start and stays open for QSHORT TIME samples. DATA_VALID fires when the long gate closes, INIB stays high for POST INIB samples more.

Item Value
Throughput 1 sample per clock (II = 1)
Latency 13 clock cycles
Pre-trigger depth 0 to 255 samples
Dead time per event QLONG TIME + POST INIB samples, reloaded on every pile-up

QSHORT DELAY and PEAK WINDOW are declared stable in the HLS interface: the core assumes they do not change while it is running. Drive them from a register or a constant and change them only with the acquisition stopped. All the other timing inputs may be changed between events.

Typical use cases

  • Neutron / gamma discrimination with organic scintillators (EJ-301, stilbene) where the amplitude-to-tail ratio separates better than charge-to-charge
  • Alpha / gamma separation in CsI(Tl) and other scintillators with a particle-dependent decay constant
  • Pulse quality cuts: events whose peak is inconsistent with their charge are usually pile-up or noise and can be cut on the PSD output alone
  • Combined amplitude and charge spectroscopy from a single block, without a separate peak detector
  • Rate and pile-up monitoring through REJ_CNT and DREJ_CNT