====== UVC Hue rotation (YCbCr 4:4:4) ====== This block applies UVC Hue adjustment by rotating the chroma vector \((C_b, C_r)\) around the neutral point, while leaving luma \(Y\) unchanged. This block does **not** clamp the output values. Chroma values outside the nominal 12-bit full-range are allowed and are expected to be handled later in the pipeline. This block takes as input 12-bit per-channel YCbCr 4:4:4 of the following format: \[ Y12 \in [0..4095]\\ C_b12 \in [0..4095]\text{, neutral at }2048\\ C_r12 \in [0..4095]\text{, neutral at }2048 \] ===== Control input ===== Hue control value is a signed integer \(H\) in degrees \(\times 100\): \[ H \in [-18000..+18000]\text{, default }0 \] Rotation angle (in degrees): \[ \theta = H / 100 \] ===== Step 1: calculate chroma deltas ===== Convert chroma channels into signed deltas around neutral: \[ \Delta C_b = C_b12 - 2048\\ \Delta C_r = C_r12 - 2048 \] ===== Step 2: rotate chroma vector ===== Apply 2D rotation: \[ \Delta C_b' = \Delta C_b \cdot \cos(\theta) - \Delta C_r \cdot \sin(\theta)\\ \Delta C_r' = \Delta C_b \cdot \sin(\theta) + \Delta C_r \cdot \cos(\theta) \] ===== Step 3: re-center chroma ===== Re-apply neutral offset: \[ C_b^{out} = 2048 + \Delta C_b'\\ C_r^{out} = 2048 + \Delta C_r'\\ Y^{out} = Y12 \] No clamping or range limiting is performed in this block. ===== Fixed-point implementation ===== ==== Trigonometric coefficients (MCU) ==== The microcontroller computes \(\sin(\theta)\) and \(\cos(\theta)\) and writes them as signed Q18 fixed-point values: \[ \sin_q = \mathrm{round}(\sin(\theta) \cdot 2^{18})\\ \cos_q = \mathrm{round}(\cos(\theta) \cdot 2^{18}) \] ==== FPGA math (signed Q18) ==== Chroma deltas are treated as signed values: \[ \Delta C_b, \Delta C_r \in [-2048..+2047] \] Multiply-accumulate: \[ T_b = \Delta C_b \cdot \cos_q - \Delta C_r \cdot \sin_q\\ T_r = \Delta C_b \cdot \sin_q + \Delta C_r \cdot \cos_q \] Convert back from Q18 using rounding-to-nearest: \[ \Delta C_b' = (T_b + 131072) >> 18\\ \Delta C_r' = (T_r + 131072) >> 18 \] All operations use **signed arithmetic with arithmetic right shift**. ===== Bit width after hue rotation ===== Input deltas: \[ \Delta C_b, \Delta C_r \in [-2048..+2047] \] Maximum chroma vector magnitude: \[ r_{max} = \sqrt{2048^2 + 2048^2} \approx 2896 \] Maximum rotated deltas: \[ \Delta C_b', \Delta C_r' \in [-2896..+2896] \] After re-centering: \[ C_b^{out}, C_r^{out} \in [-848..+4944] \] 13-bit signed storage is insufficient. Minimum safe width is **14-bit signed**. Recommended internal chroma width is **15–16 bits signed** to allow margin for rounding and subsequent chroma-domain adjustments.