diff --git a/src/toolbox_scs/detectors/__init__.py b/src/toolbox_scs/detectors/__init__.py
index c4fb3265fb777370801b66c333fcb79aad98bf37..e35ca14ce62677f1cdcc22b160dd109763b1694f 100644
--- a/src/toolbox_scs/detectors/__init__.py
+++ b/src/toolbox_scs/detectors/__init__.py
@@ -4,7 +4,8 @@ from .xgm import (
 from .tim import (
     load_TIM,)
 from .digitizers import(
-    get_peaks, get_tim_peaks, get_fast_adc_peaks, find_integ_params)
+    get_peaks, get_tim_peaks, get_fast_adc_peaks, find_integ_params,
+    channel_peak_params)
 from .dssc_data import (
     save_xarray, load_xarray, get_data_formatted, save_attributes_h5)
 from .dssc_misc import (
@@ -26,6 +27,7 @@ __all__ = (
     "get_tim_peaks",
     "get_fast_adc_peaks",
     "find_integ_params",
+    "channel_peak_params",
     "load_dssc_info",
     "create_dssc_bins",
     "calc_xgm_frame_indices",
diff --git a/src/toolbox_scs/detectors/digitizers.py b/src/toolbox_scs/detectors/digitizers.py
index 50574293581eb035f4edb2e9bd2c53256169361e..25ceff5f814d4f8fd889b1ce3f91f657747ca95f 100644
--- a/src/toolbox_scs/detectors/digitizers.py
+++ b/src/toolbox_scs/detectors/digitizers.py
@@ -121,10 +121,10 @@ def get_peaks(run,
         required if data is a DataArray or None.
     key: str
         Key for digitizer data, e.g. 'digitizers.channel_1_A.raw.samples'.
-        Only required if data a DataArray or is None.
+        Only required if data is a DataArray or is None.
     digitizer: string
         name of digitizer, e.g. 'FastADC' or 'ADQ412'. Used to determine
-        the sampling rate when useRaw is True.
+        the sampling rate.
     useRaw: bool
         If True, extract peaks from raw traces. If False, uses the APD (or
         peaks) data from the digitizer.
@@ -157,13 +157,16 @@ def get_peaks(run,
         raise ValueError('At least data or source + key arguments ' +
                          'are required.')
     # load data
+    arr = None
     if data is None:
         arr = run.get_array(source, key)
-    elif isinstance(data, str):
+    if isinstance(data, str):
         arr = run.get_array(*_mnemonics[data].values())
         source = _mnemonics[data]['source']
         key = _mnemonics[data]['key']
-    else:
+    if arr is None:
+        if source is None or key is None:
+            raise ValueError('source and/or key arguments missing.')
         arr = data
     dim = [d for d in arr.dims if d != 'trainId'][0]
     # check if bunch pattern is provided
@@ -192,7 +195,7 @@ def get_peaks(run,
                                drop=True).trainId
         mask_on = mask.sel(trainId=valid_tid)
         if (mask_on == mask_on[0]).all().values is False:
-            log.debug('Pattern changed during the run!')
+            log.info('Pattern changed during the run!')
         pid = np.unique(np.where(mask_on)[1])
         npulses = len(pid)
         extra_coords = pid
@@ -202,6 +205,13 @@ def get_peaks(run,
     if extra_dim is None:
         extra_dim = 'pulseId'
 
+    # minimum pulse period, according to digitizer type
+    min_distance = 1
+    if digitizer == 'FastADC':
+        min_distance = 24
+    if digitizer == 'ADQ412':
+        min_distance = 440
+
     # 1. Use peak-integrated data from digitizer
     if useRaw is False:
         # 1.1 No bunch pattern provided
@@ -217,41 +227,26 @@ def get_peaks(run,
             return arr.sel({dim: 0}).expand_dims(extra_dim).T.assign_coords(
                 {extra_dim: extra_coords})
         # verify period used by APD and match it to pid from bunchPattern
-        if digitizer == 'FastADC':
-            adc_source = source.split(':')[0]
-            enable_key = (source.split(':')[1].split('.')[0]
-                          + '.enablePeakComputation.value')
-            if run.get_array(adc_source, enable_key)[0] is False:
-                raise ValueError('The digitizer did not record ' +
-                                 'peak-integrated data.')
-            period_key = (source.split(':')[1].split('.')[0] +
-                          '.pulsePeriod.value')
-            period = run.get_array(adc_source, period_key)[0].values/24
-        if digitizer == 'ADQ412':
-            board_source = source.split(':')[0]
-            board = key[19]
-            channel = key[21]
-            channel_to_number = {'A': 0, 'B': 1, 'C': 2, 'D': 3}
-            channel = channel_to_number[channel]
-            in_del_key = (f'board{board}.apd.channel_{channel}' +
-                          '.initialDelay.value')
-            initialDelay = run.get_array(board_source, in_del_key)[0].values
-            up_lim_key = (f'board{board}.apd.channel_{channel}' +
-                          '.upperLimit.value')
-            upperLimit = run.get_array(board_source, up_lim_key)[0].values
-            period = (upperLimit - initialDelay)/440
-        stride = (pid[1] - pid[0]) / period
-        if period < 1:
-            log.warning('Warning: the pulse period in digitizer was ' +
-                        'smaller than the separation of two pulses ' +
-                        'at 4.5 MHz.')
-            stride = 1
+        peak_params = channel_peak_params(run, source, key)
+        log.debug(f'peak_params: {peak_params}')
+        if peak_params['enable'] == 0:
+            raise ValueError('The digitizer did not record ' +
+                             'peak-integrated data.')
+        period = peak_params['period']
+        if period < min_distance:
+            log.warning(f'Warning: the pulse period ({period} samples) of '
+                        'digitizer was smaller than the pulse separation at ' +
+                        f'4.5 MHz ({min_distance} samples).')
+        step = period / min_distance
+        pid_diff = np.min(np.diff(pid))
+        stride = pid_diff / step
+        log.debug(f'dig step: {step}, pid diff: {pid_diff}, ' +
+                  f'stride: {stride}')
         if stride < 1:
-            raise ValueError('Pulse period in digitizer was too large ' +
-                             'compared to actual pulse separation. Some ' +
-                             'pulses were not recorded.')
+            raise ValueError(f'Pulse pattern in digitizer (1 out of {step} ' +
+                             'pulses @ 4.5 MHz) does not match the actual ' +
+                             'bunch pattern. Some pulses were not recorded.')
         stride = int(stride)
-        log.debug(f'period {period}, stride {stride}')
         if npulses*stride > arr.sizes[dim]:
             raise ValueError('The number of pulses recorded by digitizer ' +
                              f'that correspond to actual {pattern} pulses ' +
@@ -261,12 +256,6 @@ def get_peaks(run,
         return peaks.assign_coords({extra_dim: extra_coords})
 
     # 2. Use raw data from digitizer
-    # minimum samples between two pulses, according to digitizer type
-    min_distance = 1
-    if digitizer == 'FastADC':
-        min_distance = 24
-    if digitizer == 'ADQ412':
-        min_distance = 440
     if autoFind:
         integParams = find_integ_params(arr.mean(dim='trainId'),
                                         min_distance=min_distance)
@@ -311,6 +300,94 @@ def get_peaks(run,
     return peaks.assign_coords({extra_dim: extra_coords})
 
 
+def channel_peak_params(run, source, key=None, digitizer=None,
+                        channel=None, board=None):
+    """
+    Extract peak-integration parameters used by a channel of the digitizer.
+
+    Parameters
+    ----------
+    run: extra_data.DataCollection
+        DataCollection containing the digitizer data
+    source: str
+        ToolBox mnemonic of a digitizer data, e.g. "MCP2apd" or
+        "FastADC4peaks", or name of digitizer source, e.g.
+        'SCS_UTC1_ADQ/ADC/1:network'.
+    key: str
+        optional, used in combination of source (if source is not a ToolBox
+        mnemonics) instead of digitizer, channel and board.
+    digitizer: {"FastADC", "ADQ412"} str
+        Type of digitizer. If None, inferred from the source mnemonic.
+    channel: int or str
+        The digitizer channel for which to retrieve the parameters. If None,
+        inferred from the source mnemonic.
+    board: int
+        Board of the ADQ412. If None, inferred from the source mnemonic.
+
+    Returns
+    -------
+    dict with peak integration parameters.
+    """
+    if source in _mnemonics:
+        m = _mnemonics[source]
+        source = m['source']
+        key = m['key']
+    if key is not None:
+        if 'network' in source:
+            digitizer = 'ADQ412'
+            ch_to_int = {'A': 0, 'B': 1, 'C': 2, 'D': 3}
+            k = key.split('.')[1].split('_')
+            channel = ch_to_int[k[2]]
+            board = k[1]
+        else:
+            digitizer = 'FastADC'
+            channel = int(source.split(':')[1].split('.')[0].split('_')[1])
+    if digitizer is None:
+        raise ValueError('digitizer argument is missing.')
+    if channel is None:
+        raise ValueError('channel argument is missing.')
+    if isinstance(channel, str):
+        ch_to_int = {'A': 0, 'B': 1, 'C': 2, 'D': 3}
+        channel = ch_to_int[channel]
+    if board is None and digitizer == 'ADQ412':
+        raise ValueError('board argument is missing.')
+    keys = None
+    if digitizer == 'ADQ412':
+        baseKey = f'board{board}.apd.channel_{channel}.'
+        keys = ['baseStart', 'baseStop', 'pulseStart',
+                'pulseStop', 'initialDelay', 'upperLimit',
+                'enable']
+        keys = {k: baseKey + k + '.value' for k in keys}
+        keys['numPulses'] = f'board{board}.apd.numberOfPulses.value'
+    if digitizer == 'FastADC':
+        if ":" in source:
+            baseKey = source.split(':')[1].split('.')[0]+'.'
+        else:
+            baseKey = f'channel_{channel}.'
+        keys = ['baseStart', 'baseStop', 'initialDelay',
+                'peakSamples', 'numPulses', 'pulsePeriod',
+                'enablePeakComputation']
+        keys = {k: baseKey + k + '.value' for k in keys}
+    if ":" in source:
+        source = source.split(':')[0]
+    log.debug(f'retrieving data from source {source}, keys = ' +
+              f'{list(keys.values())}')
+    tid, data = run.select(source).train_from_index(0)
+    result = [data[source][k] for k in keys.values()]
+    result = dict(zip(keys.keys(), result))
+    if digitizer == 'ADQ412':
+        result['period'] = result.pop('upperLimit') - \
+                           result.pop('initialDelay')
+    if digitizer == 'FastADC':
+        result['period'] = result.pop('pulsePeriod')
+        result['pulseStart'] = result['initialDelay']
+        result['pulseStop'] = result.pop('initialDelay') + \
+                              result.pop('peakSamples')
+        result['enable'] = result.pop('enablePeakComputation')
+
+    return result
+
+
 def find_integ_params(trace, min_distance=1, height=None, width=1):
     """
     find integration parameters necessary for peak integration of a raw
@@ -524,7 +601,7 @@ def get_fast_adc_peaks(data=None, run=None, bunchPattern='scs_ppl',
         peaks = get_peaks(run, d,
                           source=mnemonic['source'],
                           key=mnemonic['key'],
-                          digitizer='ADQ412',
+                          digitizer='FastADC',
                           useRaw=useRaw,
                           autoFind=autoFind,
                           integParams=integParams,