File detector_core.h¶
FileList > detector > detector_core.h
Go to the source code of this file
1-D streaming signal detector with FFT-based correlation, integrate-and-dump, and configurable noise-referenced threshold. More...
#include "doppler/corr/corr_core.h"#include "doppler/dp_state.h"#include "doppler/f32_buffer/f32_buffer_core.h"
Classes¶
| Type | Name |
|---|---|
| struct | det_result_t Detection event returned by dp_detector_push() . |
| struct | dp_detector_state_t 1-D signal detector state. |
Public Types¶
| Type | Name |
|---|---|
| enum | det_noise_mode_t |
Public Functions¶
| Type | Name |
|---|---|
| size_t | dp_detector_consumed (const dp_detector_state_t * state) Input samples the last dp_detector_push() took. |
| dp_detector_state_t * | dp_detector_create (const float _Complex * ref, size_t ref_len, size_t dwell, size_t noise_lo, size_t noise_hi, det_noise_mode_t noise_mode, float threshold, int nthreads) Allocate a 1-D streaming signal detector backed by an FFT correlator. Combines a dp_corr_state_t with a double-mapped ring buffer so that arbitrary chunk sizes can be pushed. After every int-dump the peak-to-noise test statistic is compared against threshold ; adet_result_t is emitted when it passes. Settingthreshold to 0.0 unconditionally fires on every dump. The ring capacity is next_pow_two(max(n, 512)) complex samples. |
| void | dp_detector_destroy (dp_detector_state_t * state) Destroy and free a detector instance. |
| void | dp_detector_get_state (const dp_detector_state_t * state, void * blob) |
| size_t | dp_detector_push (dp_detector_state_t * state, const float _Complex * in, size_t n_in, det_result_t * result, size_t max_results) Stream an arbitrary-length CF32 chunk through the detector pipeline. Takes the input in order, runs each complete n-sample frame through the correlator, and on every int-dump computes the test statistic peak_mag / noise_est. Detections that pass the threshold are appended to the Python return list as (lag, peak_mag, noise_est, test_stat) tuples. In Python the result is always a list, even when empty. |
| void | dp_detector_reset (dp_detector_state_t * state) Reset the correlator, the carry, and last-corr flag. Discards any partial frame carried between pushes and zeroes the coherent accumulator. Equivalent to starting fresh from the same reference without rebuilding any internal object. |
| void | dp_detector_set_ref (dp_detector_state_t * state, const float _Complex * ref) Replace the reference signal and recompute conj(FFT(ref)). |
| int | dp_detector_set_state (dp_detector_state_t * state, const void * blob) |
| void | dp_detector_set_threshold (dp_detector_state_t * state, float threshold) Change the threshold without rebuilding the object. |
| size_t | dp_detector_state_bytes (const dp_detector_state_t * state) |
Macros¶
| Type | Name |
|---|---|
| define | DETECTOR_STATE_MAGIC [**DP\_FOURCC**](dp__state_8h.md#define-dp_fourcc) ('D','E','T','1') |
| define | DETECTOR_STATE_VERSION 2u |
| define | DET_NOISE_MODE_T_DEFINED Selects how noise power is estimated from the correlation magnitude vector over bins [noise_lo, noise_hi]. |
Detailed Description¶
Wraps a dp_corr_state_t (FFT correlator + coherent int-dump) behind the ring's framed face (DECLARE_DP_BUFFER_FRAMES) so that arbitrary-length sample streams can be fed in any chunk size: the detections are a function of the input stream, not of how it was split into calls. After every int-dump a test statistic is computed:
test_stat = peak_mag / noise_est
where peak_mag = max|R[τ]| and noise_est is an aggregate (mean, median, min, or max) of |R[τ]| over a user-supplied bin range [noise_lo, noise_hi]. A detection event is emitted when test_stat > threshold (or whenever threshold == 0.0, which means "always fire").
The detector operates as a single-threaded object; do not call dp_detector_push() concurrently from multiple threads.
Lifecycle:
float _Complex ref[N] = { ... };
dp_detector_state_t *det = dp_detector_create(ref, N, 1,
1, N-1, DET_NOISE_MEAN, 0.0f, 1);
det_result_t results[64];
// stream loop: a full results[] stops a push, and the input it did not
// take is offered again -- dp_detector_consumed(det) says where it stopped
while (recv(chunk, CHUNK_SZ)) {
for (size_t off = 0; off < CHUNK_SZ; off += dp_detector_consumed(det)) {
size_t n = dp_detector_push(det, chunk + off, CHUNK_SZ - off,
results, 64);
for (size_t i = 0; i < n; i++)
printf("lag=%zu stat=%.2f\n", results[i].lag,
results[i].test_stat);
}
}
dp_detector_destroy(det);
Public Types Documentation¶
enum det_noise_mode_t¶
enum det_noise_mode_t {
DET_NOISE_MEAN = 0,
DET_NOISE_MEDIAN = 1,
DET_NOISE_MIN = 2,
DET_NOISE_MAX = 3
};
Public Functions Documentation¶
function dp_detector_consumed¶
Input samples the last dp_detector_push() took.
Equal to its n_in unless result filled up; then the caller resumes at in + consumed. 0 after create, reset and set_state.
Parameters:
stateMust be non-NULL.
function dp_detector_create¶
Allocate a 1-D streaming signal detector backed by an FFT correlator. Combines a dp_corr_state_t with a double-mapped ring buffer so that arbitrary chunk sizes can be pushed. After every int-dump the peak-to-noise test statistic is compared againstthreshold ; adet_result_t is emitted when it passes. Settingthreshold to 0.0 unconditionally fires on every dump. The ring capacity is next_pow_two(max(n, 512)) complex samples.
dp_detector_state_t * dp_detector_create (
const float _Complex * ref,
size_t ref_len,
size_t dwell,
size_t noise_lo,
size_t noise_hi,
det_noise_mode_t noise_mode,
float threshold,
int nthreads
)
Parameters:
refReference signal, CF32 ndarray of length ref_len.ref_lenReference / FFT length in complex samples.dwellInt-dump depth; must be >= 1.noise_loLower noise bin index (inclusive, 0-based).noise_hiUpper noise bin index (inclusive, < n). A value at or beyond the window clamps to n - 1, so the default sentinel selects the full window.noise_modeNoise aggregation: "mean", "median", "min", or "max".thresholdTest-stat gate; 0.0 = always emit.nthreadsAccepted for API compatibility; ignored.
Returns:
Heap-allocated state, or NULL on allocation failure.
>>> from doppler.spectral import CorrDetector
>>> import numpy as np
>>> ref = np.zeros(8, dtype=np.complex64); ref[0] = 1.0
>>> det = CorrDetector(ref=ref, dwell=1, noise_lo=1, noise_hi=7,
... noise_mode="mean", threshold=0.0)
>>> det.n, det.dwell, det.ring_cap
(8, 1, 512)
function dp_detector_destroy¶
Destroy and free a detector instance.
Parameters:
stateMay be NULL.
function dp_detector_get_state¶
function dp_detector_push¶
Stream an arbitrary-length CF32 chunk through the detector pipeline. Takes the input in order, runs each complete n-sample frame through the correlator, and on every int-dump computes the test statistic peak_mag / noise_est. Detections that pass the threshold are appended to the Python return list as (lag, peak_mag, noise_est, test_stat) tuples. In Python the result is always a list, even when empty.
size_t dp_detector_push (
dp_detector_state_t * state,
const float _Complex * in,
size_t n_in,
det_result_t * result,
size_t max_results
)
Python's push() has room for 1024 detections a call, so a push that completes at most 1024 frames, counting the carry, loses nothing. One that fills the room loses the rest of its input, every later frame whether or not it would have made a detection, unless the rest is shorter than a frame: that is kept as the carry. The next push stays on the frame grid only when what was lost is a whole number of frames; otherwise its lags are off by the remainder. Before v0.66 the room was 64, and a push past it kept up to ring_cap/n - 1 of those frames for the next call and dropped the rest. #1992 and just-buildit/just-makeit#2184 track sizing the list to the call.
Parameters:
stateAllocated detector (non-NULL).inCF32 input chunk of arbitrary length.n_inNumber of input samples inin.resultCaller-supplied array of at leastmax_resultsdet_result_t structs; filled on return.max_resultsCapacity ofresult(maximum detections to emit). A fullresultnever loses input: a frame yields at most one detection, and onceresultis full the push takes the rest of its input only if the rest completes no frame (it is then the carry); otherwise it takes nothing more, stopping on the boundary of its last frame. dp_detector_consumed() says how many samples it took, and the caller offers the rest again. Input that runs out mid-frame is the carry, held inside (fewer than n samples). With room 0 the push is full from the start, so a resume loop needs room for at least one; with that, a push of any input takes at least one sample.
Returns:
Number of det_result_t entries written to result.
>>> from doppler.spectral import CorrDetector
>>> import numpy as np
>>> ref = np.zeros(8, dtype=np.complex64); ref[0] = 1.0
>>> det = CorrDetector(ref=ref, dwell=1, noise_lo=1, noise_hi=7,
... noise_mode="mean", threshold=0.0)
>>> results = det.push(np.ones(8, dtype=np.complex64))
>>> len(results)
1
>>> lag, peak, noise, stat = results[0]
>>> lag, round(peak, 4), round(noise, 4), round(stat, 4)
(0, 1.0, 1.0, 1.0)
function dp_detector_reset¶
Reset the correlator, the carry, and last-corr flag. Discards any partial frame carried between pushes and zeroes the coherent accumulator. Equivalent to starting fresh from the same reference without rebuilding any internal object.
>>> from doppler.spectral import CorrDetector
>>> import numpy as np
>>> ref = np.zeros(8, dtype=np.complex64); ref[0] = 1.0
>>> det = CorrDetector(ref=ref, dwell=1, noise_lo=1, noise_hi=7,
... noise_mode="mean", threshold=0.0)
>>> _ = det.push(np.ones(8, dtype=np.complex64))
>>> det.reset()
>>> det.count
0
function dp_detector_set_ref¶
Replace the reference signal and recompute conj(FFT(ref)).
Also resets (see dp_detector_reset()). The new reference must have the same length n that was passed to dp_detector_create().
Parameters:
stateMust be non-NULL.refNew reference, CF32, length state->n.
function dp_detector_set_state¶
function dp_detector_set_threshold¶
Change the threshold without rebuilding the object.
Parameters:
stateMust be non-NULL.thresholdNew threshold; 0.0 = always fire.
function dp_detector_state_bytes¶
Macro Definition Documentation¶
define DETECTOR_STATE_MAGIC¶
define DETECTOR_STATE_VERSION¶
define DET_NOISE_MODE_T_DEFINED¶
Selects how noise power is estimated from the correlation magnitude vector over bins [noise_lo, noise_hi].
The test statistic is peak_mag / noise_est. A zero noise_est (e.g., when all bins in the range are zero) yields test_stat = 0.
The documentation for this class was generated from the following file native/inc/doppler/detector/detector_core.h