Electronics > FPGA
How to convert a 16-bit unsigned to 16-bit signed for multipliers
Dmeads:
I am very new to filter design on FPGA, but I am doing one for a hobby project. I have a 16-bit unsigned value coming from my ADC, which then needs to go into an IIR filter. The FPGA has 16-bit multipliers, and since some of my coefficients are negative, I think I need both operands to be signed in the multiplication. The ADC is unipolar, positive voltage only.
What is the proper way to truncate or round the 16-bit unsigned ADC value into a 16-bit signed number (twos compliment)?
brucehoult:
You can only sensibly convert an unsigned value into a signed one with the same numerical value by making sure the top bit is clear.
What are you going to do it it's not clear e.g. your ADC gave a value between 0x8000 and 0xFFFF ? Do you want to set all such values to 0x7FFF? That's not very nice. Maybe you want instead to halve all values -- either digitally, or by limiting the input range to the ADC?
But all this is unnecessary anyway, as it's perfectly well possible to multiply an unsigned 16 bit number by a signed 16 bit number to give the CORRECT 32 bit result.
CPU instruction sets such as RISC-V provide three different instructions to get the hi bits of a multiply: MULH, MULHU, and MULHSU (SxS, UxU, SxU). The lo bits are the same regardless.
You can probably configure your FPGA's DSP blocks to do signed*unsigned multiplication.
Or you can write code like...
--- Code: ---module signed_unsigned_multiplier (
input signed [15:0] a, // Signed 16-bit input
input [15:0] b, // Unsigned 16-bit input
output [31:0] result // 32-bit result
);
assign result = $signed(a) * b;
endmodule
--- End code ---
... which notionally extends a to 32 bits first (which should get optimised, hopefully just by putting the multiplier block into signed*unsigned mode)). A lot of FPGAs actually have 18 bit multipliers, in which case the signed variable only has to be extended to 18 bits (and the unsigned one zero-extended) and all will be well.
SiliconWizard:
Yes, you can keep it unsigned.
But if you really want to turn the value into a signed one, I'm assuming you have a 0x0000-0xFFFF range of values from min to max, and would like to turn that into a signed integer, 0x8000 becoming zero, 0x0000 becoming -32768 and 0xFFFF becoming 32767.
If so, you'd just have to subtract 0x8000 from the unsigned value.
Note that subtracting 0x8000 in that case doesn't even require a complete subtraction. If bit 15 is set, just clear it. If bit 15 is not set, set it. So all in all => just invert bit 15 and you should turn your unsigned value into a signed one, for which 0 corresponds to the middle value.
radiolistener:
Just subtract 0x8000.
But first check ADC documentation, because usually they already send the data in two's compliment signed format. And some have configuration register/pin to select desired format.
Note that bit truncation is not a safe operation because it introduces noise. Proper rounding should be used to minimize this noise. Similarly, bit expansion is also not safe, as it can introduce bias if scaling is involved.
brucehoult:
omg
Navigation
[0] Message Index
[#] Next page
Go to full version