make_conv1d_stream#

Streaming 1D convolution: filter a signal delivered in segments. The concatenated output equals a one-shot conv1d over the whole stream when the total signal length is at least the filter length. For shorter signals one-shot conv1d swaps the operand roles, while the streaming object keeps the signal and filter roles fixed and returns the input-aligned result. FULL mode is role-symmetric and matches for any length. The convolution uses the direct (time-domain) method, which limits the filter to 1024 taps.

Added in version 1.1.0.

struct Conv1DStreamParams#

Construction-time parameters for a streaming 1D convolution object.

Aggregate with designated-initializer support, e.g. make_conv1d_stream<float>(h, {.mode = MATX_C_MODE_FULL}, exec). A params struct is used so future options can be added without changing call sites.

Public Members

matxConvCorrMode_t mode = MATX_C_MODE_SAME#

Edge mode of the equivalent one-shot conv1d over the concatenated stream. SAME (default): one output per input sample, time-aligned with the input (the filter’s group delay is removed). FULL: causal; one output per input sample during feed() plus the L-1 trailing outputs at flush(). VALID: only outputs whose filter window is fully immersed in real samples.

template<typename InType, typename FilterOp, typename Exec = cudaExecutor>
auto matx::make_conv1d_stream(const FilterOp &filter, const Conv1DStreamParams &params, Exec exec = {})#

Create a streaming 1D convolution object.

The object filters an arbitrarily long signal delivered in segments of any (possibly varying) size. Feed segments via feed() and call flush() once at end of stream. The concatenation of the produced outputs equals a single one-shot conv1d(signal, filter, params.mode) over the whole signal whenever the total signal length N is at least the filter length L. For N < L the one-shot swaps its operand roles (the smaller operand becomes the filter and the output is sized to the larger). The object instead keeps the roles fixed and produces the input-aligned result, where SAME emits exactly N outputs and VALID emits max(0, N-L+1). FULL is role-symmetric and matches the one-shot for any N.

The object computes the convolution with the direct (time-domain) method. The filter is therefore limited to 1024 taps, and the constructor throws for longer filters. FFT-based streaming convolution may be added in a future update.

The object owns a filter-length retain buffer. No allocation scales with the segment size. The output buffer provided to feed() / flush() must be large enough to hold the maximum number of outputs that can be produced by a single call. This value is returned by max_output(max_input_segment_size). If the maximum segment size is known a priori, then a single output buffer can be allocated and reused for all calls.

Each feed() / flush() call writes the outputs to the front of the output buffer and returns the number written (which may be 0), so no dynamic memory is allocated during the call. Consume the produced region slice(out, {0}, {count}) before reusing the output buffer. A zero-length slice is not valid, so create and use the slice only when count > 0.

Template Parameters:
  • InType – Sample type of the input stream (as in make_tensor<T>)

  • FilterOp – Type of the filter operator (deduced)

  • Exec – Executor type (CUDA or host; deduced, cudaExecutor by default)

Parameters:
  • filter – FIR filter (1D, length 1 to 1024). The object materializes a copy of the filter at construction, so any filter operator (including a transform expression) is evaluated once and need not outlive the object.

  • params – Stream parameters; see Conv1DStreamParams

  • exec – Executor bound to this stream’s lifetime. All feed()/flush() work runs on it. For CUDA executors the retain buffer is stream-ordered device memory. For host executors the retain buffer is system-allocated memory. The executor (and, for CUDA, its stream) must outlive the object.

Returns:

A streaming object exposing feed(), flush(), max_output(), reset(), and history_len()

template<typename InType, typename FilterOp, typename Exec>
class Conv1DStream#

Streaming 1D convolution object; construct via make_conv1d_stream().

Filters an arbitrarily long signal delivered in segments of any (possibly varying) size. The only stream state is a filter-length retain buffer; no allocation scales with the segment size. All work runs asynchronously on the executor bound at construction. An object serves one stream at a time and is not thread-safe. The convolution uses the direct (time-domain) method, which limits the filter to 1024 taps.

Public Functions

Conv1DStream(const Conv1DStream&) = delete#

Streaming objects are not copyable: a copy would share the retained history buffer while tracking its state independently, corrupting both streams. Move construction/assignment transfers ownership and is allowed.

Conv1DStream &operator=(const Conv1DStream&) = delete#

Streaming objects are not copyable: a copy would share the retained history buffer while tracking its state independently, corrupting both streams. Move construction/assignment transfers ownership and is allowed.

Conv1DStream(Conv1DStream&&) = default#

Move-construct, transferring ownership of the stream state.

Conv1DStream &operator=(Conv1DStream&&) = default#

Move-assign, transferring ownership of the stream state.

inline index_t history_len() const#

Number of trailing input samples retained between calls (L - 1).

Informational; the caller does not size anything with it. feed() concatenates the retained history internally.

Returns:

Retained history length in samples

inline index_t max_output(index_t new_len) const#

Upper bound on the outputs a single feed() or flush() call can produce.

Size one reusable output buffer with max_output(largest segment size); it is then large enough for every feed() of up to that many samples and for flush().

Parameters:

new_len – Largest segment size that will be passed to feed()

Returns:

Maximum outputs a single call may produce

inline void reset()#

Restart the stream for a new input signal.

Clears the retained history (zero initial conditions), the mode’s startup skip, and the end-of-stream state set by flush().

template<typename InOp, typename OutTensor>
inline index_t feed(const InOp &new_samples, OutTensor &out)#

Feed a segment of new samples and receive the number of outputs it produces.

Outputs are written to the front of out; the return value is the number of outputs written. Consume slice(out, {0}, {count}) (the produced region) before reusing out. Runs asynchronously on the object’s executor. Emits up to one output per new sample; the first feeds of a SAME or VALID stream emit fewer (possibly zero) while the mode’s leading outputs are skipped. Throws matxInvalidParameter if called after flush(). Use reset() to start a new stream.

Template Parameters:
  • InOp – 1D input operator type (deduced)

  • OutTensor – 1D output tensor type (deduced)

Parameters:
  • new_samples – New signal samples (1D, non-empty). Any MatX operator is accepted and its lifecycle is run each call. A transform-valued segment (e.g. ifft(…) or slice(ifft(…))) therefore works but allocates and evaluates a per-call temporary; for hot streaming loops prefer a directly-evaluable segment (a tensor, view, or generator) or materialize once and reuse.

  • out – Output buffer with last-dim size >= max_output(input_segment_size); throws matxInvalidSize if smaller than the produced count

Returns:

Number of outputs written to the front of out (may be 0). A zero-length slice is not valid, so create and use slice(out, {0}, {count}) only when count > 0.

template<typename OutTensor>
inline index_t flush(OutTensor &out)#

Emit the end-of-stream trailing outputs for the configured mode.

FULL emits the L-1 trailing (right-zero-padded) outputs, SAME emits L-1-L/2, and VALID emits none. The first call emits the trailing outputs and ends the stream. Subsequent calls return 0, and feed() throws until reset() starts a new stream. A flush() that throws (for example, an undersized output buffer) does not end the stream and can be retried. Runs asynchronously on the object’s executor.

Template Parameters:

OutTensor – 1D output tensor type (deduced)

Parameters:

out – Output buffer with last-dim size >= max_output(input_segment_size); throws matxInvalidSize if smaller than the produced count

Returns:

Number of outputs written to the front of out (may be 0). A zero-length slice is not valid, so create and use slice(out, {0}, {count}) only when count > 0.

Examples#

auto conv_stream = make_conv1d_stream<T>(h, {.mode = MATX_C_MODE_SAME}, exec);
auto output_frame = make_tensor<T>({conv_stream.max_output(a.chunk)});
index_t off = 0;
index_t nchunks = 0;
for (index_t g = 0; g < N; g += a.chunk) {
  const index_t in_length = std::min(a.chunk, N - g);
  auto in_chunk = slice(sig, {g}, {g + in_length});

  // feed() writes outputs to the front of the reusable frame and returns how
  // many it produced. The produced region is slice(output_frame, {0}, {cnt}).
  // Everything runs on the object's bound stream, so the copy below is ordered
  // after this write and the next feed() is ordered after the copy.
  const index_t cnt = conv_stream.feed(in_chunk, output_frame);

  // For real applications, consume slice(output_frame, {0}, {cnt}) here

  // For validation only, copy the frame into the full-length buffer.
  if (cnt > 0) {
    (slice(full, {off}, {off + cnt}) = slice(output_frame, {0}, {cnt})).run(exec);
  }
  off += cnt;
  ++nchunks;
}
// End of stream: emit the trailing (right-zero-padded) SAME outputs.
const index_t tcnt = conv_stream.flush(output_frame);
if (tcnt > 0) {
  (slice(full, {off}, {off + tcnt}) = slice(output_frame, {0}, {tcnt})).run(exec);
}
off += tcnt;