DSIL Design Notes
Why commit c8ae7ad avoids value wrap and keeps the Rx I/Q channels balanced, traced from new40kHz4.v and its parent. | 依 new40kHz4.v 與其上一版,說明 commit c8ae7ad 為何能避免數值翻轉(wrap),同時維持 Rx I/Q 兩通道平衡。
1. Summary | 摘要
The Rx image reject needs Q to be 1.03× I. The parent commit got there by amplifying Q by 1.03; commit c8ae7ad (c8ae7adcc4303f2aea6df1e43753075b590e02f1) attenuates I by 1/1.03 instead. Both give the same ratio Q/I = 1.03, so the balance is unchanged. But a gain below 1 can never push a 14-bit sample past its range, while ×1.03 turns full scale into ±8437, which wraps to the opposite sign.
Rx 鏡像抑制需要 Q 是 I 的 1.03 倍。上一版的做法是把 Q 放大 1.03 倍;commit c8ae7ad 改成把 I 縮小 為 1/1.03。兩者的比值 Q/I 都是 1.03,所以平衡不變。但小於 1 的增益永遠不會讓 14 位元取樣超出範圍;×1.03 則會把滿刻度變成 ±8437,翻轉成相反的正負號。
2. The change | 改了什麼
Only the Rx ADC input stage of new40kHz4.v changed.
只改了 new40kHz4.v 的 Rx ADC 輸入級。
2.1 Before (c8ae7ad^): I × 1, Q × 1.03 in floating point | 改動前:I × 1,Q × 1.03(浮點)
328 assign Rx_Q_ = {~ADC_DA[13], ADC_DA[12:0]}; //Q Channel for Rx 329 assign Rx_I_ = {~ADC_DB[13], ADC_DB[12:0]}; //I Channel for Rx 342 Convert_b2FP Converter_Rx_I_ADC ( 344 .dataa(Rx_I_), // I x 1 347 MULT Multiplier_Rx_ADC ( 349 .dataa(Rx_Q__FP), 350 .datab(32'h3f83d70a), // Q x 1.03
2.2 After (c8ae7ad): I × 1/1.03 in fixed point, Q × 1 | 改動後:I × 1/1.03(定點),Q × 1
335 wire signed [31:0] Rx_I_scaled = Rx_I_ * 18'sd63627; // 63627/65536 = 0.970871 336 wire signed [13:0] Rx_I_bal = Rx_I_scaled >>> 16; 349 Convert_b2FP Converter_Rx_I_ADC ( 351 .dataa(Rx_I_bal), // I x 0.970871 354 MULT Multiplier_Rx_ADC ( 356 .dataa(Rx_Q__FP), 357 .datab(32'h3f800000), // Q x 1.0, kept to preserve pipeline latency
3. Why the balance is maintained | 為何平衡得以維持
The image-reject sum is Rx = Rx_I + Rx_Q_delay, where Q has been delayed by 90°. The image cancels only when the two legs have the same amplitude. The analog front end makes Q about 3% weaker than I, so the digital gains must satisfy gain_Q / gain_I = 1.03.
鏡像抑制的和是 Rx = Rx_I + Rx_Q_delay,其中 Q 已延遲 90°。只有兩路振幅相同時鏡像才會抵消。類比前端讓 Q 比 I 弱約 3%,所以數位增益必須滿足 gain_Q / gain_I = 1.03。
With exact quadrature, the image left over relative to the wanted signal is |1 − r| / (1 + r), where r = (gain_Q · h_Q) / (gain_I · h_I) and h_I, h_Q are the analog gains. Only the ratio r appears, so multiplying both channels by the same constant changes nothing.
在正交完全精確時,殘留鏡像相對於有用訊號是 |1 − r| / (1 + r),其中 r = (gain_Q · h_Q) / (gain_I · h_I),h_I、h_Q 是類比增益。式中只出現比值 r,所以兩通道同乘一個常數不會改變任何結果。
| gain_I | gain_Q | gain_Q / gain_I | |
|---|---|---|---|
| Before | 改動前 | 1 | 1.03 | 1.030000 |
| After | 改動後 | 63627/65536 = 0.970871 | 1 | 1.030003 |
The commit multiplies both channels by the same factor, 1/1.03. The ratio, and with it the image rejection, stays the same to within 3 ppm (the rounding of K = 63627). The only side effect is that the overall signal is 2.9% (0.26 dB) smaller.
這個 commit 等於把兩通道同乘 1/1.03。比值以及鏡像抑制都維持不變,差異在 3 ppm 以內(來自 K = 63627 的捨入)。唯一的副作用是整體訊號小了 2.9%(0.26 dB)。
4. Why it avoids wrap | 為何能避免翻轉
The ADC samples are 14-bit two's complement, −8192 … +8191.
ADC 取樣是 14 位元二補數,範圍 −8192 … +8191。
- Before: ×1.03 makes the output larger than the input. A full-scale sample becomes +8191 × 1.03 = +8436.7, or −8192 × 1.03 = −8437.8, which is outside the 14-bit range. Whenever that value is converted back into a 14-bit integer, it doesn't clip; it wraps to the opposite sign. +8436 becomes −7948, a full-scale spike in the wrong direction. ×1.03 is only safe while the input stays below 8191/1.03 ≈ 7952 (97% of full scale).改動前:×1.03 讓輸出大於輸入。滿刻度取樣變成 +8191 × 1.03 = +8436.7 或 −8192 × 1.03 = −8437.8,超出 14 位元範圍。只要這個值被轉回 14 位元整數,它不會被截在上限,而是翻轉成相反正負號:+8436 變成 −7948,一個方向相反的滿刻度尖峰。×1.03 只有在輸入低於 8191/1.03 ≈ 7952(滿刻度的 97%)時才安全。
- After: ×0.9709 always makes the output smaller in magnitude than the input: |K·x| ≤ |x| ≤ 8192 for every possible input. Full scale gives +7952 or −7954, which always fit in 14 bits. No input level can overflow, and no downstream stage needs headroom.改動後:×0.9709 永遠讓輸出的絕對值小於輸入:對任何輸入都有 |K·x| ≤ |x| ≤ 8192。滿刻度得到 +7952 或 −7954,一定放得進 14 位元。任何輸入都不會溢位,下游也不需要預留餘量。
| Full-scale input | 滿刻度輸入 | Before: Q × 1.03 | 改動前 | After: I × 0.970871 | 改動後 |
|---|---|---|
| +8191 | +8436.7 → −7948 (wrap) | +7952 |
| −8192 | −8437.8 → +7947 (wrap) | −7954 |
| |I + Q| in a 15-bit sum (limit 16383) | 15 位元的 I + Q 和(上限 16383) | 8192 + 8437 = 16629 | 7954 + 8192 = 16146 |
5. Where the wrap could actually happen in this commit | 在這個 commit 裡翻轉實際會發生在哪裡
In the parent commit, the ×1.03 was an IEEE-754 floating-point multiply, and floating point doesn't wrap by itself. The risk was at the points where values return to 14-bit integers. The parent file contains exactly that path, commented out:
上一版的 ×1.03 是 IEEE-754 浮點乘法,浮點本身不會翻轉。風險在數值轉回 14 位元整數的地方。上一版的檔案裡正好有這條路徑,只是被註解掉:
353// Convert_FP2b Converter_Rx_ADC_b (.dataa(Rx_Q__Amped_FP), .result(Rx_Q_Amped)); // FP -> 14-bit 315// wire signed [13:0] Rx_I, Rx_Q; 372// assign Rx = Rx_I + Rx_Q_delay; // integer sum
That 14-bit Rx_Q_Amped path is where Q × 1.03 would wrap. Moving the balance to a gain below 1 on I removes the risk on every path at once, whether it stays floating point or returns to integers.
Q × 1.03 會翻轉的地方就是這條 14 位元的 Rx_Q_Amped 路徑。把平衡改成在 I 上乘小於 1 的增益,一次消除了所有路徑的風險,不論數值留在浮點還是轉回整數。
That's why it mattered later. On 2026-09-04 the whole Rx chain was converted to fixed point, and this exact I × 63627 >>> 16 code was carried into adc_iface.v (lines 36–41). Today the 15-bit I + Q90 sum in _1Mhz_beta010.v fits only because neither channel is ever amplified.
這也是它後來變得重要的原因。2026-09-04 整條 Rx 鏈改成定點,這段 I × 63627 >>> 16 原封不動搬進了 adc_iface.v(第 36–41 行)。今天 _1Mhz_beta010.v 裡 15 位元的 I + Q90 和之所以放得下,正是因為兩通道都沒有被放大。
6. Side effects | 副作用
- Latency is unchanged. The I multiply is combinational, and the Q
MULTwas left in place at ×1.0 instead of being removed. Removing it would have shortened the Q pipeline and broken theRx_I_d1/d2/ctrlvsRx_Q_delayalignment.延遲不變。I 的乘法是組合邏輯,Q 的MULT則保留為 ×1.0 而沒有移除。若移除,Q 的管線會變短,破壞Rx_I_d1/d2/ctrl與Rx_Q_delay的對齊。 - Truncation offset.
>>> 16rounds toward −∞, so I gets an average offset of −½ LSB, which is negligible next to ADC noise.截位偏移。>>> 16向 −∞ 捨入,所以 I 有 −½ LSB 的平均偏移,相對 ADC 雜訊可忽略。
The commit message says it "mirrors the Tx amplitude-balance change". The Tx side follows the same rule: balance by attenuating the stronger channel (Q × 1/1.022), never by amplifying the weaker one.
commit 訊息說它「對應 Tx 端的振幅平衡修改」。Tx 端遵循同一原則:靠縮小較強的通道來平衡(Q × 1/1.022),而不是放大較弱的通道。