Differential Soft Decision, 16-Channel Folded (dsd_x16)

16-channel time-shared differential detector and adaptive soft quantizer, converting complex symbol pairs into channel-tagged 3-bit soft decisions for downstream Viterbi decoding.

Tested platforms include xsim.

Design

dsd_x16 is the third stage of the folded MSK front-end chain (cr_x16 → ted_x16 → dsd_x16 → fs_x16). It implements the time-shared equivalent of 16 parallel diff_detector + soft_quantizer pairs from msk_demod_channel, operating on the tagged-symbol stream produced by ted_x16.

Differential detection. For each incoming symbol pair (I(n), Q(n)), the differential product is computed as:

soft = Q(n)*I(n-1) - I(n)*Q(n-1)

which is the imaginary part of x(n) * conj(x(n-1)). The result is then negated to match the polarity convention used in msk_demod.vhd. The products are 32 bits wide (16x16); subtraction produces a 33-bit imag_diff. The top 16 bits of that result are taken as the wide soft value soft_n.

Adaptive soft quantization. An IIR magnitude tracker maintains a per-channel accumulator mag_acc (24 bits) with decay shift 8, yielding a mean estimate mean = mag_acc[23:8] (16 bits). The bit-shift for the output window is derived from the MSB position of mean, clamped so that the final value saturates into the signed 3-bit range [-3, +3]. This is the same algorithm as soft_quantizer.vhd (IN_W=16, OUT_W=3, ACC_W=24, DECAY=8).

Feed-forward fold. No inter-symbol control loop exists; the only per-channel state is:

  • i_prev / q_prev — 16-bit signed previous symbol (16 entries).

  • mag_acc — 24-bit IIR accumulator (16 entries).

These are held in simple signal arrays, read and written in the same clock cycle as the incoming sample beat (atomic update). Because the input is sparse (one symbol per channel every many clocks), there is no pipeline collision risk and no pipeline staging is needed for the per-channel RAM access. This is the same fold argument applied in cr_x16 and ted_x16.

Output word packing. Each accepted symbol produces a 32-bit output sample word:

  • Bits [31:16] — wide 16-bit soft value soft_n (used by fs_x16 for sync-word correlation).

  • Bits [15:0] — 3-bit signed quantized soft decision sign-extended to 16 bits (forwarded to msk_decode_x16 for Viterbi input).

Both fields derive from the same negated differential value, exactly mirroring how msk_demod_frontend fans soft_out_n in parallel to frame_sync and soft_quantizer.

Tagging protocol. Every output symbol is preceded by a 4-word metadata message carrying the channel index in the low 4 bits of word 2 (value field of the complex_short_timed_sample metadata opcode). The downstream worker fs_x16 extracts the channel id from the same metadata position.

Backpressure. An internal 64-entry FIFO decouples the 3-stage computation pipeline from the output FSM. Input is stalled (take de-asserted) when the FIFO has fewer than 4 free slots. The output FSM sequences metadata words (OST_M0–OST_M3) followed by the sample word (OST_S), yielding five output beats per symbol, each individually backpressure-handled via the WSI ready signal.

Interface

<?xml version='1.0' encoding='utf-8'?>
<!-- dsd_x16: FOLDED 16-channel differential detector + soft quantizer, the
     time-shared equivalent of 16 parallel (diff_detector + soft_quantizer)
     pairs from msk_demod_channel.  Converts symbol decisions into 3-bit soft
     decisions for the Viterbi.

     INPUT  (tagged symbols, from ted_x16): per symbol, metadata(id=0,value=ch)
       then a 1-sample message carrying the symbol (sym_i[31:16], sym_q[15:0]).
     OUTPUT (tagged soft): per symbol, metadata(id=0,value=ch) then a 1-sample
       message: HIGH 16 bits = the wide 16-bit soft (for fs_x16's frame_sync
       correlation), LOW 16 bits = the 3-bit signed quantized soft sign-extended
       (for the Viterbi).  Both derive from the negated diff value, mirroring
       how msk_demod_frontend fans soft_out_n to frame_sync AND soft_quantizer.

     diff_detector: soft = Im{x(n)*conj(x(n-1))} = Q(n)*I(n-1) - I(n)*Q(n-1),
     then NEGATED (polarity convention from msk_demod.vhd) before quantizing.
     soft_quantizer: adaptive IIR magnitude tracker picks the bit window and
     emits an OUT_W=3 signed value.  This is FEED-FORWARD (no loop): the only
     per-channel state is each diff_detector's previous symbol (i_prev/q_prev)
     and each soft_quantizer's IIR accumulator (mag_acc), held in 16-entry RAMs.
     Same sparse-input fold argument as cr_x16 / ted_x16. -->
<ComponentSpec>

  <property name='init' type='bool' writable='true' default='false'
            description="Pulse high to reset all 16 per-channel diff/quantizer states"/>

  <property name='sym_count' type='ulong' volatile='true' arraylength='16'
            description="Soft decisions emitted per channel since reset"/>

  <port name="input"  producer="false" protocol="complex_short_timed_sample-prot"/>
  <port name="output" producer="true"  protocol="complex_short_timed_sample-prot"/>

</ComponentSpec>

Ports

Inputs:

  • input: Tagged complex-symbol input from ted_x16 (metadata + sample per symbol).

    • Protocol: complex_short_timed_sample-prot

    • Optional: False

Outputs:

  • output: Tagged soft-decision output to fs_x16 (metadata + sample per symbol; HIGH 16 = wide soft, LOW 16 = 3-bit quantized soft sign-extended).

    • Protocol: complex_short_timed_sample-prot

    • Optional: False

Opcode Handling

The dsd_x16 worker consumes complex_short_timed_sample metadata and sample opcodes on its input. Metadata words are parsed to extract the channel index; sample words trigger the differential-detect and quantizer pipeline.

On output, the same two opcodes are generated: four metadata words followed by one sample word per symbol.

No other opcodes are generated or forwarded. An input EOF causes the output FSM to assert EOF after draining the internal FIFO.

Properties

  • init: Pulse high to reset all 16 per-channel diff/quantizer states.

    • Type: bool

    • Access:

      • Parameter: False

      • Writable: True

      • Initial: False

      • Volatile: False

    • Default value: false

  • sym_count: Soft decisions emitted per channel since reset.

    • Type: ulong

      • Array dimensions: ['16']

    • Access:

      • Parameter: False

      • Writable: False

      • Initial: False

      • Volatile: True

    • Default value: None

Implementations

  • dsd_x16 (HDL)

    16-channel time-shared differential detector and adaptive soft quantizer; converts complex symbol pairs into channel-tagged 3-bit soft decisions with an accompanying 16-bit wide soft value for sync correlation.

Dependencies

The dsd_x16 HDL worker depends on:

  • ieee.std_logic_1164

  • ieee.numeric_std

  • ocpi.types (OpenCPI generated types, including opcode enumerations for complex_short_timed_sample-prot)

No external primitive libraries or generated ROM files are required; the differential multiply, subtraction, and quantizer are inlined in the worker architecture.

Limitations

Limitations of dsd_x16 are:

  • The number of channels is fixed at 16 by the N_CH constant; it is not a runtime-configurable parameter.

  • The soft-quantizer parameters (OUT_W=3, ACC_W=24, DECAY=8) are compile-time constants matched to msk_demod_channel; they cannot be changed without re-synthesis.

  • The hunt and lock thresholds for downstream fs_x16 must be tuned relative to the expected soft amplitude, which depends on signal level and the IIR magnitude tracker’s operating point.

Testing

The unit test applies a sequence of tagged MSK symbol pairs (including known sync-word symbol sequences) and verifies that the 3-bit quantized soft decisions and wide soft values match the expected differential-detect output. Per-channel sym_count properties are checked to confirm all 16 channels emit decisions.

Tested platforms: None