Skip to content

Dark count rate (DCR)

The DCR map is the per-pixel dark-count rate in counts per second: accumulated dark counts divided by the time the sensor was actually collecting.

DCR = sum(counts) / (nframes * n_files * live_per_frame)

Counting mode vs timestamping mode

What "a count" is depends on the acquisition program, so mode is not cosmetic — it decides which field of the unpacked data is read.

  • mode="count" (default) — S*C / ORC data. Each pixel has a real 9-bit photon counter per frame, and the map is its sum.
  • mode="timestamp" — S*T / ORT data. There is no counter: the chip timestamps the first hit instead, and unpack returns the low bits of the coarse timestamp in the photon_counts slot. The count is therefore the number of frames carrying a valid timestamp, (ts > 0).sum(axis=2) — the same definition hitmap_analysis uses.

Summing the counter field on *T data inflates the DCR ~40-50×

Those bits are coarse >> 1, so a fired pixel contributes a few hundred instead of 1, and the result still looks like a plausible DCR map. On real 24 V S0T data the median came out at 247 kcps — nearly twice the 125 kcps that one-hit-per-8-µs-frame physically allows. mode is cross-checked against the last letter of tag, so tag="S0T" with mode="count" is a ValueError, not a wrong number.

Saturation and pileup_correct

Timestamping records at most one count per pixel per frame, so the raw rate is really an occupancy and it saturates at 1 / open_shutter_time_s — 125 kcps at an 8 µs shutter. It under-reports well before the ceiling: at 50 % occupancy it reads ~30 % low.

pileup_correct=True inverts the censoring under Poisson statistics, since a frame fires with probability p = 1 - exp(-r·w):

r = -ln(1 - hits/total_frames) / open_shutter_time_s

It is off by default — the raw occupancy rate is what the sensor measured — and the drivers print a warning naming the ceiling whenever the hottest pixel gets within 5 % of it. Counting mode has no such ceiling and ignores the flag.

Live time is not frame time

The normalisation uses the live time per frame, which depends on the firmware — see core.timing.resolve_live_time.

  • short_window (current firmware, the default) — each ~9 µs frame is mostly readout and only the user-set open_shutter_time_s (e.g. 200e-9 s) is photon-sensitive. You must pass open_shutter_time_s; compute_dcr_32 raises without it rather than guessing.
  • full_window (legacy) — the whole frame is live, so the per-frame time comes from resolve_frame_time: explicit exp_time_s + 9 µs overhead, else frame_rate_cnt.txt, else the 9 µs free-running fallback.

Under the legacy firmware the exposure argument passed to Kelpie_v2.exe maps to an actual frame period with 9 µs of overhead: 0 → 9 µs, 10 µs → 19 µs.

Quadrants and the full sensor

compute_dcr_32 handles one SPAD quadrant tag — S0C...S3C in counting mode, S0T...S3T in timestamping mode. compute_dcr_64 unpacks all four and interleaves them onto the full (64, 64) sensor — each tag reads one micropixel per 2×2 macropixel, so the quadrant maps interleave rather than tile.

The SPAD indices run clockwise (S0 S1 / S3 S2), not row-major; the layout is documented under cross-talk and enforced by tests/test_spad_geometry.py.

Quadrant tags are matched with a leading underscore

DCR globs *_S0C*.bin, not *S0C*.bin, so a tag cannot match a filename that merely happens to contain those characters. This is the require_separator=True argument to core.io.find_bin_files.

Pixel masking

Hot/warm pixel masking is not implemented yet. When per-board mask files become available, masked pixels will read as NaN — which is why every statistic in core.plots is already NaN-aware. Plain np.median / np.percentile propagate NaN, and a single masked pixel would otherwise turn vmax into NaN and flatten the entire heatmap to one colour with no error raised.

API

dcr_analysis

Dark count rate (DCR) maps, per quadrant and full-sensor.

DCR is accumulated dark counts divided by the time the sensor was actually collecting. That live time is NOT the frame period: under the current short_window firmware only the user-set open_shutter_time_s of each ~9 us frame is photon-sensitive, so open_shutter_time_s is required.

What counts as "a count" depends on the acquisition program, exactly as in 'hitmap_analysis':

* ``mode="count"`` (``S*C`` / ``ORC``) - the per-pixel photon counter is
  summed over frames.
* ``mode="timestamp"`` (``S*T`` / ``ORT``) - the counter field does **not**
  exist; 'unpack' returns the low bits of the coarse timestamp in its place
  (see the note in 'unpack'). Summing it gives a number tens of times too
  large. Here the count is the number of frames carrying a valid timestamp,
  ``(ts > 0).sum(axis=2)``.

In timestamp mode only the first dark count of a frame is recorded, so the occupancy saturates at one per open_shutter_time_s (125 kcps at an 8 µs window) and under-reports below it. pileup_correct=True inverts that censoring under Poisson statistics; see 'compute_dcr_32'.

See docs/guide/dcr.md.

compute_dcr_32

compute_dcr_32(folder: str, nframes: int, exp_time_s: float | None = None, tag: str = '', *, mode: str = 'count', pileup_correct: bool = False, firmware_version: str = 'short_window', open_shutter_time_s: float | None = 5e-07) -> ndarray

Unpack the binary data and compute the (32, 32) DCR map.

Normalised by the live time per frame, which depends on the firmware (see 'core.timing.resolve_live_time'): 'short_window' counts only open_shutter_time_s as live, 'full_window' the whole frame.

Parameters:

Name Type Description Default
folder str

Path to the folder with the '.bin' data files.

required
nframes int

Number of frames stored in each '.bin' file.

required
exp_time_s float | None

Legacy exposure time in seconds (firmware_version='full_window' only): 0 → 9 µs actual, 10e-6 → 19 µs. If None, the 9 µs free-running base is used. The default is None.

None
tag str

SPAD quadrant tag - 'S0C'...'S3C' in counting mode, 'S0T'...'S3T' (or 'ORT') in timestamping mode. The default is "", which matches every '.bin' file in the folder.

''
mode str

'count' (default) sums the per-pixel photon counter; use 'timestamp' for S*T/ORT data, where that field holds coarse-timestamp bits instead and the count is the number of frames that fired. A tag whose letter contradicts mode is an error.

'count'
pileup_correct bool

'timestamp' mode only. Timestamp mode records at most one count per frame, so the raw rate saturates at 1 / open_shutter_time_s (125 kcps at an 8 µs window) and under-reports well before that. With True the Poisson censoring is inverted, r = -ln(1 - p) / open_shutter_time_s. The default is False, which reports the raw occupancy rate.

False
firmware_version str

'short_window' (default) or 'full_window'; see 'resolve_live_time'.

'short_window'
open_shutter_time_s float | None

Photon-sensitive window per frame, in seconds (required for firmware_version='short_window'). The default is 500e-9 (500 ns).

5e-07

Returns:

Type Description
ndarray

The (32, 32) dark count rate map, in counts per second.

Raises:

Type Description
ValueError

Raised when firmware_version='short_window' but no open_shutter_time_s is given, or when mode is unknown or contradicts tag.

Source code in src/dapkel/functions/dcr_analysis.py
def compute_dcr_32(
    folder: str,
    nframes: int,
    exp_time_s: float | None = None,
    tag: str = "",
    *,
    mode: str = "count",
    pileup_correct: bool = False,
    firmware_version: str = "short_window",
    open_shutter_time_s: float | None = 500e-9,
) -> np.ndarray:
    """Unpack the binary data and compute the (32, 32) DCR map.

    Normalised by the *live* time per frame, which depends on the firmware
    (see 'core.timing.resolve_live_time'): ``'short_window'`` counts only
    ``open_shutter_time_s`` as live, ``'full_window'`` the whole frame.

    Parameters
    ----------
    folder : str
        Path to the folder with the '.bin' data files.
    nframes : int
        Number of frames stored in each '.bin' file.
    exp_time_s : float | None, optional
        Legacy exposure time in seconds (``firmware_version='full_window'``
        only): 0 → 9 µs actual, 10e-6 → 19 µs. If None, the 9 µs
        free-running base is used. The default is None.
    tag : str, optional
        SPAD quadrant tag - 'S0C'...'S3C' in counting mode, 'S0T'...'S3T' (or
        'ORT') in timestamping mode. The default is "", which matches every
        '.bin' file in the folder.
    mode : str, optional
        ``'count'`` (default) sums the per-pixel photon counter; use
        ``'timestamp'`` for ``S*T``/``ORT`` data, where that field holds
        coarse-timestamp bits instead and the count is the number of frames
        that fired. A tag whose letter contradicts ``mode`` is an error.
    pileup_correct : bool, optional
        ``'timestamp'`` mode only. Timestamp mode records at most one count per
        frame, so the raw rate saturates at ``1 / open_shutter_time_s`` (125 kcps at an
        8 µs window) and under-reports well before that. With True the Poisson
        censoring is inverted, ``r = -ln(1 - p) / open_shutter_time_s``. The default is
        False, which reports the raw occupancy rate.
    firmware_version : str, optional
        ``'short_window'`` (default) or ``'full_window'``; see
        'resolve_live_time'.
    open_shutter_time_s : float | None, optional
        Photon-sensitive window per frame, in seconds (required for
        ``firmware_version='short_window'``). The default is ``500e-9``
        (500 ns).

    Returns
    -------
    np.ndarray
        The (32, 32) dark count rate map, in counts per second.

    Raises
    ------
    ValueError
        Raised when ``firmware_version='short_window'`` but no ``open_shutter_time_s``
        is given, or when ``mode`` is unknown or contradicts ``tag``.
    """
    _check_mode(mode, tag)
    live, _ = timing.resolve_live_time(
        firmware_version, nframes,
        open_shutter_time_s=open_shutter_time_s, exp_time_s=exp_time_s,
    )
    if live is None:
        raise ValueError(
            "firmware_version='short_window' needs open_shutter_time_s (the "
            "photon-sensitive window per frame, in seconds, e.g. 200e-9)."
        )
    # The DCR quadrant tags are matched with a leading underscore ('*_S0C*')
    # so a tag cannot match a filename that merely contains those characters.
    files = io.find_bin_files(folder, tag, require_separator=True)
    return _accumulate_dcr(
        files, nframes, live,
        mode=mode, pileup_correct=pileup_correct, label=tag,
    )

compute_dcr_64

compute_dcr_64(folder: str, nframes: int, exp_time_s: float | None = None, *, mode: str = 'count', pileup_correct: bool = False, firmware_version: str = 'short_window', open_shutter_time_s: float | None = 5e-07) -> ndarray

Unpack the binary data and compute the (64, 64) DCR map.

Interleaves the four quadrant maps onto the full sensor. Normalised by the live time per frame; see 'compute_dcr_32'.

Parameters:

Name Type Description Default
folder str

Path to the folder with the '.bin' data files.

required
nframes int

Number of frames stored in each '.bin' file.

required
exp_time_s float | None

Legacy exposure time in seconds (firmware_version='full_window' only). If None, the 9 µs free-running base is used. The default is None.

None
mode str

'count' (default, S*C files) or 'timestamp' (S*T files); see 'compute_dcr_32'. The mode also selects which quadrant files are looked for.

'count'
pileup_correct bool

'timestamp' mode only; see 'compute_dcr_32'. The default is False.

False
firmware_version str

'short_window' (default) or 'full_window'; see 'resolve_live_time'.

'short_window'
open_shutter_time_s float | None

Photon-sensitive window per frame, in seconds (required for firmware_version='short_window'). The default is 500e-9 (500 ns).

5e-07

Returns:

Type Description
ndarray

The (64, 64) dark count rate map, in counts per second.

Raises:

Type Description
FileNotFoundError

Raised when no '.bin' files for any of the four SPAD tags are found in the folder.

ValueError

Raised when firmware_version='short_window' but no open_shutter_time_s is given, or when mode is unknown.

Source code in src/dapkel/functions/dcr_analysis.py
def compute_dcr_64(
    folder: str,
    nframes: int,
    exp_time_s: float | None = None,
    *,
    mode: str = "count",
    pileup_correct: bool = False,
    firmware_version: str = "short_window",
    open_shutter_time_s: float | None = 500e-9,
) -> np.ndarray:
    """Unpack the binary data and compute the (64, 64) DCR map.

    Interleaves the four quadrant maps onto the full sensor. Normalised by
    the live time per frame; see 'compute_dcr_32'.

    Parameters
    ----------
    folder : str
        Path to the folder with the '.bin' data files.
    nframes : int
        Number of frames stored in each '.bin' file.
    exp_time_s : float | None, optional
        Legacy exposure time in seconds (``firmware_version='full_window'``
        only). If None, the 9 µs free-running base is used. The default
        is None.
    mode : str, optional
        ``'count'`` (default, ``S*C`` files) or ``'timestamp'`` (``S*T``
        files); see 'compute_dcr_32'. The mode also selects which quadrant
        files are looked for.
    pileup_correct : bool, optional
        ``'timestamp'`` mode only; see 'compute_dcr_32'. The default is False.
    firmware_version : str, optional
        ``'short_window'`` (default) or ``'full_window'``; see
        'resolve_live_time'.
    open_shutter_time_s : float | None, optional
        Photon-sensitive window per frame, in seconds (required for
        ``firmware_version='short_window'``). The default is ``500e-9``
        (500 ns).

    Returns
    -------
    np.ndarray
        The (64, 64) dark count rate map, in counts per second.

    Raises
    ------
    FileNotFoundError
        Raised when no '.bin' files for any of the four SPAD tags are
        found in the folder.
    ValueError
        Raised when ``firmware_version='short_window'`` but no ``open_shutter_time_s``
        is given, or when ``mode`` is unknown.
    """
    _check_mode(mode)
    live, _ = timing.resolve_live_time(
        firmware_version, nframes,
        open_shutter_time_s=open_shutter_time_s, exp_time_s=exp_time_s,
    )
    if live is None:
        raise ValueError(
            "firmware_version='short_window' needs open_shutter_time_s (the "
            "photon-sensitive window per frame, in seconds, e.g. 200e-9)."
        )
    frame_time_s = live

    # The layout is keyed by the counting-mode tags; timestamping writes the
    # same four quadrants as 'S0T'...'S3T'.
    tag_files = {}
    for tag in _SPAD_LAYOUT:
        files = glob.glob(
            os.path.join(folder, f"*_{_quadrant_tag(tag, mode)}*.bin")
        )
        if files:
            tag_files[tag] = sorted(
                files,
                key=lambda fp: int(
                    "".join(filter(str.isdigit, os.path.basename(fp))) or "0"
                ),
            )
    if not tag_files:
        letter = _MODE_TAG_LETTER[mode]
        raise FileNotFoundError(
            f"No S0{letter}/S1{letter}/S2{letter}/S3{letter} .bin files "
            f"found in:\n  {folder}"
        )

    quadrants = {
        tag: _accumulate_dcr(
            files, nframes, frame_time_s,
            mode=mode, pileup_correct=pileup_correct,
            label=_quadrant_tag(tag, mode),
        )
        for tag, files in tag_files.items()
    }
    return reduce.assemble_64(quadrants, _SPAD_LAYOUT)

plot_heatmap

plot_heatmap(dcr: ndarray, cmap: str | None = None) -> Figure

Plot a dark count rate map as a 2D heatmap.

Parameters:

Name Type Description Default
dcr ndarray

Dark count rate map, e.g. from 'compute_dcr_32'/'compute_dcr_64'.

required
cmap str | None

Matplotlib colormap name. The default is None — use the active style's image.cmap.

None

Returns:

Type Description
Figure

The generated figure.

Source code in src/dapkel/functions/dcr_analysis.py
def plot_heatmap(dcr: np.ndarray, cmap: str | None = None) -> plt.Figure:
    """Plot a dark count rate map as a 2D heatmap.

    Parameters
    ----------
    dcr : np.ndarray
        Dark count rate map, e.g. from 'compute_dcr_32'/'compute_dcr_64'.
    cmap : str | None, optional
        Matplotlib colormap name. The default is None — use the active
        style's ``image.cmap``.

    Returns
    -------
    plt.Figure
        The generated figure.
    """
    rows, cols = dcr.shape
    median, maximum, _ = plots.map_stats(dcr)
    return plots.sensor_map(
        dcr,
        title=(
            f"DCR map  {rows}×{cols} SPADs\n"
            f"median {median:.0f}  max {maximum:.0f}  cps"
        ),
        cmap=cmap,
    )

plot_distribution

plot_distribution(dcr: ndarray) -> Figure

Plot the sorted per-pixel dark count rate distribution.

Parameters:

Name Type Description Default
dcr ndarray

Dark count rate map, e.g. from 'compute_dcr_32'/'compute_dcr_64'.

required

Returns:

Type Description
Figure

The generated figure.

Source code in src/dapkel/functions/dcr_analysis.py
def plot_distribution(dcr: np.ndarray) -> plt.Figure:
    """Plot the sorted per-pixel dark count rate distribution.

    Parameters
    ----------
    dcr : np.ndarray
        Dark count rate map, e.g. from 'compute_dcr_32'/'compute_dcr_64'.

    Returns
    -------
    plt.Figure
        The generated figure.
    """
    return plots.sorted_distribution(
        dcr,
        ylabel="DCR  (cps)",
        title="Sorted DCR distribution",
        logy=True,  # DCR spans decades
        fmt=".0f",
        unit="cps",
    )

compute_and_save_dcr_32

compute_and_save_dcr_32(path: str, nframes: int, exp_time_s: float | None = None, tag: str = '', *, mode: str = 'count', pileup_correct: bool = False, firmware_version: str = 'short_window', open_shutter_time_s: float | None = 5e-07) -> str

Compute the (32, 32) DCR map and save it under processed/.

The stage-1 half of the DCR analysis: unpack once, write the array plus a '.meta.json' sidecar, and return the path. 'collect_and_plot_dcr_32' can then replot it with from_saved=True without re-unpacking.

Parameters:

Name Type Description Default
path str

Path to the folder with the '.bin' data files.

required
nframes int

Number of frames stored in each '.bin' file.

required
exp_time_s float | None

Value passed to Kelpie_v2.exe, in seconds. The default is None.

None
tag str

SPAD quadrant tag ('S0C'...'S3C', or 'S0T'...'S3T'/'ORT' in timestamping mode). The default is "".

''
mode str

'count' (default) or 'timestamp'; see 'compute_dcr_32'.

'count'
pileup_correct bool

'timestamp' mode only; see 'compute_dcr_32'. The default is False.

False
firmware_version str

'short_window' (default) or 'full_window'.

'short_window'
open_shutter_time_s float | None

Photon-sensitive window per frame, in seconds. The default is 500e-9 (500 ns).

5e-07

Returns:

Type Description
str

Path to the saved '.npy'.

Source code in src/dapkel/functions/dcr_analysis.py
def compute_and_save_dcr_32(
    path: str,
    nframes: int,
    exp_time_s: float | None = None,
    tag: str = "",
    *,
    mode: str = "count",
    pileup_correct: bool = False,
    firmware_version: str = "short_window",
    open_shutter_time_s: float | None = 500e-9,
) -> str:
    """Compute the (32, 32) DCR map and save it under ``processed/``.

    The stage-1 half of the DCR analysis: unpack once, write the array plus a
    '.meta.json' sidecar, and return the path. 'collect_and_plot_dcr_32' can
    then replot it with ``from_saved=True`` without re-unpacking.

    Parameters
    ----------
    path : str
        Path to the folder with the '.bin' data files.
    nframes : int
        Number of frames stored in each '.bin' file.
    exp_time_s : float | None, optional
        Value passed to Kelpie_v2.exe, in seconds. The default is None.
    tag : str, optional
        SPAD quadrant tag ('S0C'...'S3C', or 'S0T'...'S3T'/'ORT' in
        timestamping mode). The default is "".
    mode : str, optional
        ``'count'`` (default) or ``'timestamp'``; see 'compute_dcr_32'.
    pileup_correct : bool, optional
        ``'timestamp'`` mode only; see 'compute_dcr_32'. The default is False.
    firmware_version : str, optional
        ``'short_window'`` (default) or ``'full_window'``.
    open_shutter_time_s : float | None, optional
        Photon-sensitive window per frame, in seconds. The default is
        ``500e-9`` (500 ns).

    Returns
    -------
    str
        Path to the saved '.npy'.
    """
    dcr = compute_dcr_32(
        path, nframes, exp_time_s, tag,
        mode=mode, pileup_correct=pileup_correct,
        firmware_version=firmware_version, open_shutter_time_s=open_shutter_time_s,
    )
    return store.save_map(
        dcr,
        path,
        kind=_KIND,
        tag=tag,
        meta=_dcr_meta(
            path, nframes, tag, exp_time_s, firmware_version, open_shutter_time_s,
            mode, pileup_correct,
        ),
    )

compute_and_save_dcr_64

compute_and_save_dcr_64(path: str, nframes: int, exp_time_s: float | None = None, *, mode: str = 'count', pileup_correct: bool = False, firmware_version: str = 'short_window', open_shutter_time_s: float | None = 5e-07) -> str

Assemble the (64, 64) full-sensor DCR map and save it.

Parameters:

Name Type Description Default
path str

Path to the folder with the four SPAD quadrants' '.bin' files.

required
nframes int

Number of frames stored in each '.bin' file.

required
exp_time_s float | None

Value passed to Kelpie_v2.exe, in seconds. The default is None.

None
mode str

'count' (default) or 'timestamp'; see 'compute_dcr_32'.

'count'
pileup_correct bool

'timestamp' mode only; see 'compute_dcr_32'. The default is False.

False
firmware_version str

'short_window' (default) or 'full_window'.

'short_window'
open_shutter_time_s float | None

Photon-sensitive window per frame, in seconds. The default is 500e-9 (500 ns).

5e-07

Returns:

Type Description
str

Path to the saved '.npy'.

Source code in src/dapkel/functions/dcr_analysis.py
def compute_and_save_dcr_64(
    path: str,
    nframes: int,
    exp_time_s: float | None = None,
    *,
    mode: str = "count",
    pileup_correct: bool = False,
    firmware_version: str = "short_window",
    open_shutter_time_s: float | None = 500e-9,
) -> str:
    """Assemble the (64, 64) full-sensor DCR map and save it.

    Parameters
    ----------
    path : str
        Path to the folder with the four SPAD quadrants' '.bin' files.
    nframes : int
        Number of frames stored in each '.bin' file.
    exp_time_s : float | None, optional
        Value passed to Kelpie_v2.exe, in seconds. The default is None.
    mode : str, optional
        ``'count'`` (default) or ``'timestamp'``; see 'compute_dcr_32'.
    pileup_correct : bool, optional
        ``'timestamp'`` mode only; see 'compute_dcr_32'. The default is False.
    firmware_version : str, optional
        ``'short_window'`` (default) or ``'full_window'``.
    open_shutter_time_s : float | None, optional
        Photon-sensitive window per frame, in seconds. The default is
        ``500e-9`` (500 ns).

    Returns
    -------
    str
        Path to the saved '.npy'.
    """
    dcr = compute_dcr_64(
        path, nframes, exp_time_s,
        mode=mode, pileup_correct=pileup_correct,
        firmware_version=firmware_version, open_shutter_time_s=open_shutter_time_s,
    )
    return store.save_map(
        dcr,
        path,
        kind=_KIND,
        tag="64",
        meta=_dcr_meta(
            path, nframes, "64", exp_time_s, firmware_version, open_shutter_time_s,
            mode, pileup_correct,
        ),
    )

collect_and_plot_dcr_32

collect_and_plot_dcr_32(path: str, nframes: int, exp_time_s: float | None = None, tag: str = '', daughterboard_number: str | None = None, motherboard_number: str | None = None, cmap: str | None = None, *, mode: str = 'count', pileup_correct: bool = False, firmware_version: str = 'short_window', open_shutter_time_s: float | None = 5e-07, from_saved: bool = False) -> ndarray

Unpack, compute, and plot the (32, 32) DCR map for a SPAD tag.

Computes (and saves) the map, then writes both the heatmap and the sorted distribution to results/dcr.

Parameters:

Name Type Description Default
path str

Path to the folder with the '.bin' data files.

required
nframes int

Number of frames stored in each '.bin' file.

required
exp_time_s float | None

Value passed to Kelpie_v2.exe, in seconds. See 'compute_dcr_32' for details. The default is None.

None
tag str

SPAD quadrant tag ('S0C'...'S3C', or 'S0T'...'S3T'/'ORT' in timestamping mode). The default is "", which matches every '.bin' file in the folder.

''
daughterboard_number str | None

Camera daughterboard number, used to look up the hot/warm pixel mask. Mask support is not implemented yet. The default is None.

None
motherboard_number str | None

Camera motherboard number, used together with 'daughterboard_number' to look up the hot/warm pixel mask. Mask support is not implemented yet. The default is None.

None
cmap str | None

Matplotlib colormap name for the heatmap. The default is None — use the active style's image.cmap.

None
mode str

'count' (default) or 'timestamp'; see 'compute_dcr_32'.

'count'
pileup_correct bool

'timestamp' mode only; see 'compute_dcr_32'. The default is False.

False
firmware_version str

'short_window' (default) or 'full_window'; see 'resolve_live_time'.

'short_window'
open_shutter_time_s float | None

Photon-sensitive window per frame, in seconds (required for firmware_version='short_window'). The default is 500e-9 (500 ns).

5e-07
from_saved bool

Load the map saved by 'compute_and_save_dcr_32' instead of re-unpacking the '.bin' files - use this to retry a colormap. The default is False, which computes and then saves the array.

False

Returns:

Type Description
ndarray

The (32, 32) dark count rate map, in counts per second.

Source code in src/dapkel/functions/dcr_analysis.py
def collect_and_plot_dcr_32(
    path: str,
    nframes: int,
    exp_time_s: float | None = None,
    tag: str = "",
    daughterboard_number: str | None = None,
    motherboard_number: str | None = None,
    cmap: str | None = None,
    *,
    mode: str = "count",
    pileup_correct: bool = False,
    firmware_version: str = "short_window",
    open_shutter_time_s: float | None = 500e-9,
    from_saved: bool = False,
) -> np.ndarray:
    """Unpack, compute, and plot the (32, 32) DCR map for a SPAD tag.

    Computes (and saves) the map, then writes both the heatmap and the
    sorted distribution to ``results/dcr``.

    Parameters
    ----------
    path : str
        Path to the folder with the '.bin' data files.
    nframes : int
        Number of frames stored in each '.bin' file.
    exp_time_s : float | None, optional
        Value passed to Kelpie_v2.exe, in seconds. See
        'compute_dcr_32' for details. The default is None.
    tag : str, optional
        SPAD quadrant tag ('S0C'...'S3C', or 'S0T'...'S3T'/'ORT' in
        timestamping mode). The default is "", which matches every '.bin'
        file in the folder.
    daughterboard_number : str | None, optional
        Camera daughterboard number, used to look up the hot/warm
        pixel mask. Mask support is not implemented yet. The default
        is None.
    motherboard_number : str | None, optional
        Camera motherboard number, used together with
        'daughterboard_number' to look up the hot/warm pixel mask.
        Mask support is not implemented yet. The default is None.
    cmap : str | None, optional
        Matplotlib colormap name for the heatmap. The default is None —
        use the active style's ``image.cmap``.
    mode : str, optional
        ``'count'`` (default) or ``'timestamp'``; see 'compute_dcr_32'.
    pileup_correct : bool, optional
        ``'timestamp'`` mode only; see 'compute_dcr_32'. The default is False.
    firmware_version : str, optional
        ``'short_window'`` (default) or ``'full_window'``; see
        'resolve_live_time'.
    open_shutter_time_s : float | None, optional
        Photon-sensitive window per frame, in seconds (required for
        ``firmware_version='short_window'``). The default is ``500e-9``
        (500 ns).
    from_saved : bool, optional
        Load the map saved by 'compute_and_save_dcr_32' instead of
        re-unpacking the '.bin' files - use this to retry a colormap. The
        default is False, which computes and then saves the array.

    Returns
    -------
    np.ndarray
        The (32, 32) dark count rate map, in counts per second.

    """
    # TODO: once per-board hot/warm pixel mask files are available,
    # use daughterboard_number/motherboard_number to load and apply
    # the mask here (see daplis.functions.utils.apply_mask).

    print(
        f"\n> > > Collecting DCR data for tag '{tag or 'all'}' "
        f"(mode='{mode}') and plotting the heatmap and distribution < < <\n"
    )

    if from_saved:
        dcr, _ = store.load_map(path, kind=_KIND, tag=tag)
    else:
        dcr = compute_dcr_32(
            path, nframes, exp_time_s, tag,
            mode=mode, pileup_correct=pileup_correct,
            firmware_version=firmware_version, open_shutter_time_s=open_shutter_time_s,
        )
        store.save_map(
            dcr,
            path,
            kind=_KIND,
            tag=tag,
            meta=_dcr_meta(
                path, nframes, tag, exp_time_s, firmware_version, open_shutter_time_s,
                mode, pileup_correct,
            ),
            quiet=True,
        )
        _warn_if_saturated(dcr, mode, pileup_correct, open_shutter_time_s)

    name = os.path.basename(os.path.normpath(path))
    tag_suffix = tag if tag else "dcr"
    results_dir = store.results_dir(path, _KIND, create=False)

    fig_heatmap = plot_heatmap(dcr, cmap=cmap)
    store.save_figure(fig_heatmap, results_dir, f"{name}_{tag_suffix}_heatmap.png")
    plt.close(fig_heatmap)

    fig_distribution = plot_distribution(dcr)
    store.save_figure(
        fig_distribution,
        results_dir,
        f"{name}_{tag_suffix}_distribution.png",
    )
    plt.close(fig_distribution)

    return dcr

collect_and_plot_dcr_64

collect_and_plot_dcr_64(path: str, nframes: int, exp_time_s: float | None = None, daughterboard_number: str | None = None, motherboard_number: str | None = None, cmap: str | None = None, *, mode: str = 'count', pileup_correct: bool = False, firmware_version: str = 'short_window', open_shutter_time_s: float | None = 5e-07, from_saved: bool = False) -> ndarray

Unpack, compute, and plot the (64, 64) full sensor DCR map.

Computes (and saves) the map, then writes both the heatmap and the sorted distribution to results/dcr.

Parameters:

Name Type Description Default
path str

Path to the folder with the '.bin' data files.

required
nframes int

Number of frames stored in each '.bin' file.

required
exp_time_s float | None

Value passed to Kelpie_v2.exe, in seconds. See 'compute_dcr_64' for details. The default is None.

None
daughterboard_number str | None

Camera daughterboard number, used to look up the hot/warm pixel mask. Mask support is not implemented yet. The default is None.

None
motherboard_number str | None

Camera motherboard number, used together with 'daughterboard_number' to look up the hot/warm pixel mask. Mask support is not implemented yet. The default is None.

None
cmap str | None

Matplotlib colormap name for the heatmap. The default is None — use the active style's image.cmap.

None
mode str

'count' (default) or 'timestamp'; see 'compute_dcr_32'.

'count'
pileup_correct bool

'timestamp' mode only; see 'compute_dcr_32'. The default is False.

False
firmware_version str

'short_window' (default) or 'full_window'; see 'resolve_live_time'.

'short_window'
open_shutter_time_s float | None

Photon-sensitive window per frame, in seconds (required for firmware_version='short_window'). The default is 500e-9 (500 ns).

5e-07
from_saved bool

Load the map saved by 'compute_and_save_dcr_64' instead of re-unpacking the '.bin' files. The default is False, which computes and then saves the array.

False

Returns:

Type Description
ndarray

The (64, 64) dark count rate map, in counts per second.

Source code in src/dapkel/functions/dcr_analysis.py
def collect_and_plot_dcr_64(
    path: str,
    nframes: int,
    exp_time_s: float | None = None,
    daughterboard_number: str | None = None,
    motherboard_number: str | None = None,
    cmap: str | None = None,
    *,
    mode: str = "count",
    pileup_correct: bool = False,
    firmware_version: str = "short_window",
    open_shutter_time_s: float | None = 500e-9,
    from_saved: bool = False,
) -> np.ndarray:
    """Unpack, compute, and plot the (64, 64) full sensor DCR map.

    Computes (and saves) the map, then writes both the heatmap and the
    sorted distribution to ``results/dcr``.

    Parameters
    ----------
    path : str
        Path to the folder with the '.bin' data files.
    nframes : int
        Number of frames stored in each '.bin' file.
    exp_time_s : float | None, optional
        Value passed to Kelpie_v2.exe, in seconds. See
        'compute_dcr_64' for details. The default is None.
    daughterboard_number : str | None, optional
        Camera daughterboard number, used to look up the hot/warm
        pixel mask. Mask support is not implemented yet. The default
        is None.
    motherboard_number : str | None, optional
        Camera motherboard number, used together with
        'daughterboard_number' to look up the hot/warm pixel mask.
        Mask support is not implemented yet. The default is None.

    cmap : str | None, optional
        Matplotlib colormap name for the heatmap. The default is None —
        use the active style's ``image.cmap``.
    mode : str, optional
        ``'count'`` (default) or ``'timestamp'``; see 'compute_dcr_32'.
    pileup_correct : bool, optional
        ``'timestamp'`` mode only; see 'compute_dcr_32'. The default is False.
    firmware_version : str, optional
        ``'short_window'`` (default) or ``'full_window'``; see
        'resolve_live_time'.
    open_shutter_time_s : float | None, optional
        Photon-sensitive window per frame, in seconds (required for
        ``firmware_version='short_window'``). The default is ``500e-9``
        (500 ns).
    from_saved : bool, optional
        Load the map saved by 'compute_and_save_dcr_64' instead of
        re-unpacking the '.bin' files. The default is False, which computes
        and then saves the array.

    Returns
    -------
    np.ndarray
        The (64, 64) dark count rate map, in counts per second.


    """
    # TODO: once per-board hot/warm pixel mask files are available,
    # use daughterboard_number/motherboard_number to load and apply
    # the mask here (see daplis.functions.utils.apply_mask).

    print(
        f"\n> > > Collecting DCR data for the full sensor (mode='{mode}') "
        "and plotting the heatmap and distribution < < <\n"
    )

    if from_saved:
        dcr, _ = store.load_map(path, kind=_KIND, tag="64")
    else:
        dcr = compute_dcr_64(
            path, nframes, exp_time_s,
            mode=mode, pileup_correct=pileup_correct,
            firmware_version=firmware_version, open_shutter_time_s=open_shutter_time_s,
        )
        store.save_map(
            dcr,
            path,
            kind=_KIND,
            tag="64",
            meta=_dcr_meta(
                path, nframes, "64", exp_time_s, firmware_version, open_shutter_time_s,
                mode, pileup_correct,
            ),
            quiet=True,
        )
        _warn_if_saturated(dcr, mode, pileup_correct, open_shutter_time_s)

    name = os.path.basename(os.path.normpath(path))
    results_dir = store.results_dir(path, _KIND, create=False)

    fig_heatmap = plot_heatmap(dcr, cmap=cmap)
    store.save_figure(
        fig_heatmap,
        results_dir,
        f"{name}_full_heatmap.png",
    )

    fig_distribution = plot_distribution(dcr)
    store.save_figure(
        fig_distribution,
        results_dir,
        f"{name}_full_distribution.png",
    )

    return dcr