Skip to content

File det_private.h

FileList > detector > det_private.h

Go to the source code of this file

Shared internals for detector_core.c and detector2d_core.c. More...

  • #include <stdint.h>
  • #include <stdlib.h>
  • #include <string.h>
  • #include "doppler/f32_buffer/f32_buffer_core.h"
  • #include "doppler/util/util_core.h"

Classes

Type Name
struct det_peak_t

Public Types

Type Name
typedef int(* det_frame_step_fn
One frame's work for det_framed_push(): correlate frame and, on a dump that passes the gate, write ONE result at indexslot ofresult . Returns 1 if it wrote one, 0 if not never more.

Public Static Functions

Type Name
int det_cmp_f32_asc (const void * a, const void * b)
size_t det_framed_push (dp_f32_framer_t * fr, const float _Complex * in, size_t n_in, void * result, size_t max_results, det_frame_step_fn step, void * obj, size_t * consumed)
The detectors' push: any chunk in through the ring's framer, frames of n at hopn out throughstep , never a lost input.
float det_noise_chunk (const float * mag, size_t lo, size_t hi, det_noise_mode_t mode)
The per-chunk noise aggregates MEAN, MIN, MAX over bins [lo, hi], needing no scratch buffer.
float det_noise_estimate (const float * mag, size_t lo, size_t hi, float * scratch, det_noise_mode_t mode)
Aggregate |corr| over bins [lo, hi] using the selected mode.
size_t det_peak_list (const float * surf, size_t ny, size_t nx, float gate, size_t excl_rows, size_t excl_cols, uint8_t * mask, det_peak_t * out, size_t max_peaks)
The maximum of a surface, iterated with exclusion zones: every peak above a gate, strongest first, at most max_peaks of them.
size_t det_peak_scan (const float * surf, const uint8_t * mask, size_t k0, size_t k1)
One scan of det_peak_list(): the first maximum of surf over the cells[k0, k1) thatmask leaves as candidates.
void det_peak_zone (uint8_t * mask, size_t ny, size_t nx, size_t r, size_t c, size_t excl_rows, size_t excl_cols)
The exclusion zone of a pick at (r, c) , marked intomask :excl_rows either side along the rows andexcl_cols along the columns, CIRCULAR on both axes (an FFT bin axis by a circular correlation lag axis), each half-width clamped to half the axis.
dp_f32_t * det_ring_create (size_t cap_min)

Macros

Type Name
define DET_PEAK_T_DEFINED

Detailed Description

Not part of the public API. Include after the module's own header so that det_noise_mode_t is already defined via the DET_NOISE_MODE_T_DEFINED guard in detector_core.h / detector2d_core.h.

Public Types Documentation

typedef det_frame_step_fn

One frame's work for det_framed_push(): correlate frame and, on a dump that passes the gate, write ONE result at indexslot ofresult . Returns 1 if it wrote one, 0 if not never more.

typedef int(* det_frame_step_fn) (void *obj, const float _Complex *frame, void *result, size_t slot);


Public Static Functions Documentation

function det_cmp_f32_asc

static int det_cmp_f32_asc (
    const void * a,
    const void * b
) 

function det_framed_push

The detectors' push: any chunk in through the ring's framer, frames of n at hopn out throughstep , never a lost input.

static inline size_t det_framed_push (
    dp_f32_framer_t * fr,
    const float _Complex * in,
    size_t n_in,
    void * result,
    size_t max_results,
    det_frame_step_fn step,
    void * obj,
    size_t * consumed
) 

dp_detector_push() and dp_detector2d_push() are this, with their own step. Each frame yields at most one result, so the framer is fed only what completes as many WHOLE frames as result has room for, and no partial frame past them dp_f32_framer_feed_frames(), the rule acq shares and every frame fed is drained before the next feed. That makes a batch exact rather than an estimate: a batch can never write past the room (each frame takes at most one slot) or strand a whole frame in the framer (all are drained). Break either and the push overfills result or strands frames; acq breaks the first (a dump reports several peaks), which is why it has its own drain.

Once result is full and with no room it is full from the start the push takes the rest of its input only if the rest completes no frame (dp_f32_framer_feed_carry()): that rest is then the carry, taken without loss. Otherwise it takes nothing more, so a push that stops short of its input stops on a frame boundary, never part-way into a frame it cannot report. A caller that cannot resume (Python: one call per push) loses only what a push leaves, and stays frame-aligned when that is a whole number of frames. A resume loop needs room for at least one: with none, a push takes nothing that completes a frame. Input that runs out mid-frame is the carry, held for the next call.

Parameters:

  • fr The object's framer.
  • in Input samples.
  • n_in Samples in in.
  • result The caller's results, handed to step.
  • max_results Room in result.
  • step The object's per-frame work.
  • obj Handed to step.
  • consumed Set to the samples of in this push took.

Returns:

Results written.


function det_noise_chunk

The per-chunk noise aggregates MEAN, MIN, MAX over bins [lo, hi], needing no scratch buffer.

static inline float det_noise_chunk (
    const float * mag,
    size_t lo,
    size_t hi,
    det_noise_mode_t mode
) 

MEDIAN has no per-chunk form (it must sort the whole range), so it is not computed here and returns 0; use det_noise_estimate() for it. A caller that works a chunk at a time (acq's parallel tiles) calls THIS, so it cannot even ask for a median without a scratch buffer: the invariant is in the signature, not in a NULL passed to something that would dereference it.

Parameters:

  • mag Magnitude vector (length >= hi+1).
  • lo First bin, inclusive.
  • hi Last bin, inclusive.
  • mode DET_NOISE_MEAN, DET_NOISE_MIN or DET_NOISE_MAX.

Returns:

The aggregate; 0 if lo > hi or mode is DET_NOISE_MEDIAN.


function det_noise_estimate

Aggregate |corr| over bins [lo, hi] using the selected mode.

static inline float det_noise_estimate (
    const float * mag,
    size_t lo,
    size_t hi,
    float * scratch,
    det_noise_mode_t mode
) 

Returns 0 if lo > hi (empty range) — the caller maps that to test_stat=0.

Parameters:

  • mag Magnitude vector (length >= hi+1).
  • lo First bin, inclusive.
  • hi Last bin, inclusive.
  • scratch Caller-allocated buffer of length >= (hi-lo+1) floats; used only for DET_NOISE_MEDIAN (avoids a heap alloc per push).
  • mode Aggregation mode.

Returns:

Aggregated noise estimate, or 0 if lo > hi.


function det_peak_list

The maximum of a surface, iterated with exclusion zones: every peak above a gate, strongest first, at most max_peaks of them.

static inline size_t det_peak_list (
    const float * surf,
    size_t ny,
    size_t nx,
    float gate,
    size_t excl_rows,
    size_t excl_cols,
    uint8_t * mask,
    det_peak_t * out,
    size_t max_peaks
) 

The one argmax under both detectors (docs/design/async-dsss-receiver.md §7.1). Each pick is the largest unmasked cell; if it is not above gate the list ends there (the gate is eta in the surface's own units, so a second peak is another draw from the same cells against the same union bound the threshold does not change with the list). A pick's zone excl_rows either side along the rows and excl_cols along the columns, CIRCULAR on both axes, since every surface this serves is an FFT bin axis by a circular correlation lag axis is masked so the emitter just reported cannot be reported again from its own shoulders; outside the zone a second emitter has its own maximum. The zone is therefore the detector's resolution, and it is the caller's to size from the code and the dwell (one Doppler bin by one chip: the main lobe's first nulls).

mask is the caller's, ny * nx bytes, initialised by the caller: 0 for a candidate cell, non-zero for one that is never a candidate (a Doppler band the engine does not search). On return every listed peak's zone is marked as well. Nothing here allocates, and the cost is max_peaks scans of the surface plus the zones the duration rule of §5.1.

**mask may be NULL when max_peaks is 1.** The mask exists to carry a pick's zone to the next pick; with one pick there is no next, and every cell is a candidate. The call is then the classic detector's own loop one pass, one compare per cell, nothing written rather than a mask cleared over the surface and read back once per cell for a zone that is never applied. Measured (doppler#1208): the masked form at one peak cost detector2d::push 22-43%. A NULL mask with max_peaks > 1 is a caller error and lists one peak.

Parameters:

  • surf The surface, row-major ny x nx.
  • ny Its geometry.
  • gate A peak must exceed this (strictly) to be listed.
  • excl_rows Zone half-width along rows (0 = the row alone).
  • excl_cols Zone half-width along columns (0 = the column alone).
  • mask ny * nx bytes, 0 = candidate; updated in place.
  • out Receives up to max_peaks peaks, strongest first.
  • max_peaks Capacity of out.

Returns:

Peaks listed (0 when nothing exceeds the gate).


function det_peak_scan

One scan of det_peak_list(): the first maximum of surf over the cells[k0, k1) thatmask leaves as candidates.

static size_t det_peak_scan (
    const float * surf,
    const uint8_t * mask,
    size_t k0,
    size_t k1
) 

Returns the cell, or k1 when no cell in the range is a candidate. The pick is the FIRST maximum (strict >), so a caller that cuts the surface into chunks, scans each, and merges the chunks' picks in order with the same strict > makes exactly the pick one scan over the whole surface makes which is what lets the acquisition engine run the scan per tile on its pool and merge serially, bit-identical at any thread count (doppler#1243). mask may be NULL: every cell is then a candidate, and the loop is the plain argmax on purpose a four-lane unrolled form runs 4x faster in isolation but moves detector2d::push by nothing measurable (doppler#1208), so the simple one stays.


function det_peak_zone

The exclusion zone of a pick at (r, c) , marked intomask :excl_rows either side along the rows andexcl_cols along the columns, CIRCULAR on both axes (an FFT bin axis by a circular correlation lag axis), each half-width clamped to half the axis.

static void det_peak_zone (
    uint8_t * mask,
    size_t ny,
    size_t nx,
    size_t r,
    size_t c,
    size_t excl_rows,
    size_t excl_cols
) 


function det_ring_create

static inline dp_f32_t * det_ring_create (
    size_t cap_min
) 

Macro Definition Documentation

define DET_PEAK_T_DEFINED

#define DET_PEAK_T_DEFINED 


The documentation for this class was generated from the following file native/inc/doppler/detector/det_private.h