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 valuesoft_n(used byfs_x16for sync-word correlation).Bits
[15:0]— 3-bit signed quantized soft decision sign-extended to 16 bits (forwarded tomsk_decode_x16for 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-protOptional:
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-protOptional:
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:
boolAccess:
Parameter:
FalseWritable:
TrueInitial:
FalseVolatile:
False
Default value:
false
sym_count: Soft decisions emitted per channel since reset.Type:
ulongArray dimensions:
['16']
Access:
Parameter:
FalseWritable:
FalseInitial:
FalseVolatile:
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 forcomplex_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_CHconstant; it is not a runtime-configurable parameter.The soft-quantizer parameters (
OUT_W=3,ACC_W=24,DECAY=8) are compile-time constants matched tomsk_demod_channel; they cannot be changed without re-synthesis.The hunt and lock thresholds for downstream
fs_x16must 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