File spectrogram_core.h¶
FileList > doppler > spectrogram > spectrogram_core.h
Go to the source code of this file
Streaming spectrogram: a stream of any-size chunks in, rows of nfft-bin spectra out, one row every hop samples. More...
#include "doppler/clib_common.h"#include "doppler/dp_state.h"#include "doppler/f32_buffer/f32_buffer_core.h"#include "doppler/psd/psd_core.h"#include <stddef.h>#include <stdint.h>#include "doppler/dp_interrupt_guard/dp_interrupt_guard_core.h"
Classes¶
| Type | Name |
|---|---|
| struct | dp_spectrogram_state_t Spectrogram state. Allocate with dp_spectrogram_create() . |
Public Types¶
| Type | Name |
|---|---|
| enum | spectrogram__core_8h_1abed82baf7f470b522273a3e37c24c600 |
Public Functions¶
| Type | Name |
|---|---|
| size_t | dp_spectrogram_consumed (const dp_spectrogram_state_t * s) Input samples the last dp_spectrogram_push() took. |
| dp_spectrogram_state_t * | dp_spectrogram_create (size_t nfft, size_t hop, int window, float beta, int mode) Create a streaming spectrogram. |
| void | dp_spectrogram_destroy (dp_spectrogram_state_t * s) Release a spectrogram and everything it owns. |
| int64_t | dp_spectrogram_flush (dp_spectrogram_state_t * s, float * row, size_t row_len) End the stream: write the one zero-padded row it still owes, if any. |
| size_t | dp_spectrogram_flush_max_out (const dp_spectrogram_state_t * s) Floats dp_spectrogram_flush() writes: nfft, the one row it can owe. |
| void | dp_spectrogram_get_state (const dp_spectrogram_state_t * s, void * blob) Serialize the configuration a row depends on, then the stream position, into blob . |
| size_t | dp_spectrogram_pending (const dp_spectrogram_state_t * s) Samples pushed that no written row has covered yet. |
| size_t | dp_spectrogram_push (dp_spectrogram_state_t * s, const float _Complex * in, size_t n_in, float * out, size_t max_out) Push input, write every whole row it completes that fits. |
| size_t | dp_spectrogram_push_max_out (const dp_spectrogram_state_t * s, size_t n_in) Floats one push of n_in samples writes whenout has room: the rows_for(n_in) count times nfft. |
| void | dp_spectrogram_reset (dp_spectrogram_state_t * s) Forget the stream: drop the carry and restart at sample 0. |
| size_t | dp_spectrogram_rows_for (const dp_spectrogram_state_t * s, size_t n_in) Rows a push of n_in more samples completes, given the carry: exact, not an estimate. |
| int | dp_spectrogram_set_state (dp_spectrogram_state_t * s, const void * blob) Restore the stream position from a blob of the same configuration, so the next push continues it bit for bit. |
| size_t | dp_spectrogram_state_bytes (const dp_spectrogram_state_t * s) Bytes of the state blob, a function of nfft alone. |
Macros¶
| Type | Name |
|---|---|
| define | SPECTROGRAM_STATE_MAGIC [**DP\_FOURCC**](dp__state_8h.md#define-dp_fourcc) ('S', 'P', 'G', 'M')State-blob magic ('SPGM') and layout version. |
| define | SPECTROGRAM_STATE_VERSION 2u |
Detailed Description¶
A row is the PSD of one frame, and nothing else: row k is PSD's per-frame kernel applied to stream samples [k*hop, k*hop + nfft) dp_psd_frame_linear() for power rows, the default, or dp_psd_frame_db() for dB rows, which a caller asks for by name. So the window, the FFT and the full-scale reference are PSD's own, and a full-scale tone on a bin reads 1.0 in power, 0 dB in dB. The rows are a function of the INPUT STREAM, not of how it was split into calls: pushing it in one call, a sample at a time, or in any other partition gives the same rows, bit for bit.
The object composes and re-implements none of its parts. The carry between calls is the ring's framed face (DECLARE_DP_BUFFER_FRAMES): fewer than nfft samples are held once a push returns, so the state blob has a size that depends on nfft alone. The spectrum is PSD's per-frame kernel, held by value (dp_psd_kernel_t): the window, the transform and the full-scale reference, and none of PSD's averaging. It does not average rows (fold them with AccTrace), detect, display or decimate.
Lifecycle: dp_spectrogram_create(), then any number of dp_spectrogram_push() calls, then dp_spectrogram_flush() once to end the stream, then dp_spectrogram_destroy(). A short output buffer never loses input: push stops at a whole row and dp_spectrogram_consumed() says where to resume.
Not thread-safe on one object (the kernel uses the object's scratch). Complex float32 input only. The design, its goals and what it costs are docs/design/spectrogram.md. The C examples are native/examples/ spectrogram_demo.c, which the example gate runs; they are not kept in this header, because the Python docstrings are generated from it.
Public Types Documentation¶
enum spectrogram__core_8h_1abed82baf7f470b522273a3e37c24c600¶
enum spectrogram__core_8h_1abed82baf7f470b522273a3e37c24c600 {
DP_SPECTROGRAM_POWER = 0,
DP_SPECTROGRAM_DB = 1
};
Public Functions Documentation¶
function dp_spectrogram_consumed¶
Input samples the last dp_spectrogram_push() took.
Equal to its n_in unless out ran out of room; then the caller resumes at in + consumed. 0 after create, reset, flush and set_state.
Parameters:
sMust be non-NULL.
function dp_spectrogram_create¶
Create a streaming spectrogram.
dp_spectrogram_state_t * dp_spectrogram_create (
size_t nfft,
size_t hop,
int window,
float beta,
int mode
)
Parameters:
nfftSamples per frame and bins per row, which must be the same number: an nfft that would be zero-padded to a longer transform (anything but a power of two >= 2) is refused rather than given rows wider than its frames.hopSamples between row starts, 1 to nfft. 0 means nfft, which tiles the stream; the default. Less than nfft overlaps the frames. A hop above nfft would leave samples no row covers, so it is refused.windowThe window: "hann", "kaiser", "blackman-harris" or "rect", as PSD takes them. It also refuses a window that sums to zero at this nfft (the symmetric Hann at nfft = 2).betaKaiser beta (ignored for the other windows).modeRow units: "power" (linear rows, the default) or "db" (dBFS rows, asked for by name). Any other value is refused.
Returns:
Heap-allocated state, or NULL on an invalid argument.
Every row is DC-centred exactly as PSD's kernel emits it: bin k at index nfft/2 + k, negative frequencies first.
Note:
Call dp_spectrogram_destroy() when done.
function dp_spectrogram_destroy¶
Release a spectrogram and everything it owns.
Parameters:
sMay be NULL (no-op).
function dp_spectrogram_flush¶
End the stream: write the one zero-padded row it still owes, if any.
The row sits on the hop grid: it starts at the next row start k*hop, never at the first sample no row covered, so it is the row a one-shot push of the input zero-padded to that row's end would have written. It is written if and only if the stream holds a sample no earlier row covered. Either way the spectrogram then restarts at sample 0, as after reset, so a second flush writes nothing.
Parameters:
sMust be non-NULL.rowRoom for nfft floats.row_lenFloats of room inrow. Must be exactly nfft: any other length is refused before anything moves, the owed frame stays owed, and -1 is returned (never a count).
Returns:
Floats written: nfft, or 0 if no row was owed; -1 if the row is not exactly nfft floats long. From Python, the owed row as a (1, nfft) matrix, or None when none was owed.
function dp_spectrogram_flush_max_out¶
Floats dp_spectrogram_flush() writes: nfft, the one row it can owe.
Sized by the object alone, since a flush owes at most one row. It is also the only row length dp_spectrogram_flush() accepts.
Parameters:
sMust be non-NULL.
function dp_spectrogram_get_state¶
Serialize the configuration a row depends on, then the stream position, into blob .
Parameters:
sMust be non-NULL.blobdp_spectrogram_state_bytes(s) bytes, every one written.
function dp_spectrogram_pending¶
Samples pushed that no written row has covered yet.
What dp_spectrogram_flush() would turn into a row: 0 means the stream is complete as it stands.
Parameters:
sMust be non-NULL.
function dp_spectrogram_push¶
Push input, write every whole row it completes that fits.
size_t dp_spectrogram_push (
dp_spectrogram_state_t * s,
const float _Complex * in,
size_t n_in,
float * out,
size_t max_out
)
Takes the input in order and produces each row as soon as a frame of nfft samples is complete, at every hop. A partial frame is carried to the next call, so the rows do not depend on how the input was split into calls. Input that completes no row is always taken whole.
Only whole rows are written. A C caller bounds the write with max_out and takes the rows that fit; the consumed count reports the input those rows used, and the caller offers the rest again. The Python face has no short buffer: its binding sizes the output for the whole chunk (see the Python method doc).
Parameters:
sMust be non-NULL.inComplex baseband samples (cf32).n_inSamples inin.outRows, row-major, nfft floats each.max_outFloatsouthas room for.
Returns:
Floats written, a multiple of nfft. From Python, the completed rows as a (rows, nfft) matrix, or None when none is completed.
function dp_spectrogram_push_max_out¶
Floats one push of n_in samples writes whenout has room: the rows_for(n_in) count times nfft.
The capacity that makes a push take ALL of its input. Saturates at SIZE_MAX rather than wrapping.
Parameters:
sMust be non-NULL.n_inSamples about to be pushed.
function dp_spectrogram_reset¶
Forget the stream: drop the carry and restart at sample 0.
The next row covers samples [0, nfft) of whatever is pushed next. The consumed count and the pending count read 0. Configuration is kept.
Parameters:
sMust be non-NULL.
function dp_spectrogram_rows_for¶
Rows a push of n_in more samples completes, given the carry: exact, not an estimate.
The carry plus n_in samples, cut into frames of nfft at the hop. A push with room for this many rows writes exactly this many and takes all of n_in.
Parameters:
sMust be non-NULL.n_inSamples about to be pushed.
function dp_spectrogram_set_state¶
Restore the stream position from a blob of the same configuration, so the next push continues it bit for bit.
The blob is refused, with s unchanged, when its magic, version or size is wrong; when the configuration it carries differs from s's another mode, nfft, hop or window, or under the Kaiser window another beta, since a checkpoint from another configuration would mean something else (#2102); or when its carry is corrupt. A beta under any other window changes no row, so it is not compared. A version-1 blob, which carried no configuration, is refused by its version.
Parameters:
sA spectrogram.blobFrom dp_spectrogram_get_state().
Returns:
DP_OK, or DP_ERR_INVALID.
function dp_spectrogram_state_bytes¶
Bytes of the state blob, a function of nfft alone.
The blob is the configuration a row depends on mode, nfft, hop, window and beta then the stream position: the framer's snapshot, which is the carry (fewer than nfft samples, padded to nfft - 1), its element size, the stream counts and the hop that frames them. Both sit inside the spectrogram's own envelope, version 2. Every field has a fixed size, so the length depends on nfft alone. It does not carry consumed(), which reads 0 after a restore. What a restore refuses is dp_spectrogram_set_state()'s.
Parameters:
sMust be non-NULL.
Macro Definition Documentation¶
define SPECTROGRAM_STATE_MAGIC¶
State-blob magic ('SPGM') and layout version.
define SPECTROGRAM_STATE_VERSION¶
The documentation for this class was generated from the following file native/inc/doppler/spectrogram/spectrogram_core.h