LabVIEW

cancel
Showing results for 
Search instead for 
Did you mean: 

How to divide or multiply accurately on FPGA within single-cycle timed loop?

Solved!
Go to solution

I am performing an FFT on the PXIe-7846R FPGA module and then I'm transferring the data through Peer-to-peer transfer to another FPGA where it is processed for the project I'm working on. After the FFT is performed I need to scale the data just by either dividing it by 8192 or multiplying it by 1/8192 and was wondering what the best method would be, I can't transfer back to the host to perform the division. Attached below is what the output should look like after the division, and also what it looks like using the "High Throughput Multiply" function which seems to round the values for some reason.

Download All
0 Kudos
Message 1 of 10
(6,360 Views)

How is the high throughput multiply configured?  You should be able to have it match the input bitness.  Basically somewhere you are getting a digitization error.


Certified LabVIEW Architect, Certified Professional Instructor
ALE Consultants

Introduction to LabVIEW FPGA for RF, Radar, and Electronic Warfare Applications
0 Kudos
Message 2 of 10
(6,350 Views)

I matched the input bitness and this was the output (left), what it should look like is on the right, not sure why there is now a vertical offset as well. I also attached the high throughput multiply settings

mult2.PNG

mult2_settings.PNG

  

0 Kudos
Message 3 of 10
(6,304 Views)

Hi Trekkie,

 

are you sure about the used FXP datatypes? Do you really need an output datatype of <±,32,32>? Does your FFT really output <±,32,31> FXP values?

 

See this:

Each label describes the used FXP settings. The "1M" multiplier is using the same datatype as your x input…

Best regards,
GerdW


using LV2016/2019/2021 on Win10/11+cRIO, TestStand2016/2019
0 Kudos
Message 4 of 10
(6,291 Views)
Solution
Accepted by topic author Trekkie123

I would have guessed that defining your 1/8192 as +,1,-12 would be the best for reducing the data usage.

 

This would then allow multiplication with a signed, 32-bit word (including sign bit in LabVIEW's description, e.g. +-, 8, 8 ranges between -128 and 127 (2^7)) into a 32 bit signed result with a reduced integer word length.

The result will always be smaller than the input, and because your "1/8192" value is only a single bit in +,1,-12 - it can only have the values 1/8192 or 0. This means the output will either be a reinterpretation with the fixed point moved (but the same boolean array pattern) or a bunch of 0 bits.

 

You can do this without multiplying/dividing at all, by using the "Reinterpret Number" node on FPGA. You only need to work out what your new Integer Word Length should be (it will be the input - 13, since you're shifting by 2^-13).


GCentral
0 Kudos
Message 5 of 10
(6,276 Views)

I attempted to use reinterpret number and this is the output graphed (left) vs what it should look like (right). I'm not sure what could be wrong. I used reinterpret number and set the integer word length to 17 bits since 30 - 13 = 17

reint_num.PNG

reint_num_settings.PNG

  

0 Kudos
Message 6 of 10
(6,267 Views)

new_reint1.PNG

I believe I figured it out. Any idea why there is a vertical offset of .0017 though? Otherwise, it looks right

0 Kudos
Message 7 of 10
(6,257 Views)

Hi Trekkie,

 


@Trekkie123 wrote:

I believe I figured it out. Any idea why there is a vertical offset of .0017 though?


How did you figure it out?

Which datatypes do you currently use?

Mind to attach raw and converted data along with your VI?

Best regards,
GerdW


using LV2016/2019/2021 on Win10/11+cRIO, TestStand2016/2019
0 Kudos
Message 8 of 10
(6,250 Views)

It's been a while since I thought about this but I don't think you can bitshift signed numbers like you can unsigned ones. That's where your negative values are popping in and out.

 

Your FFT should be generating only positive values. Make sure it's outputting unsigned integers, then your reinterpretation should work.

Message 9 of 10
(6,236 Views)

Filling in a bit of details:

OP:  Please read up on binary math (shift left, and shift right) and 2's complement arithmetic (the encoding that defines positive and negative values in binary). AFTER doing that, please read below for examples.

Power of 2 mult/divide is a a single-cycle operation whether signed or unsigned.  The difference is how many steps it takes to perform that operation.  Obviously this is simplified for all positive numbers, so try NOT to have negative numbers if you can avoid it (does your FFT really need negative numbers?)

Let's take small numbers because they're easy to see whats going on.

4 * 2 = 4 << (log2 (2))  = 4 << (1) = 100 << 1 = 1000 = 8.

5*16 = 5 << (log2 (16)) = 5 << (4) = 101 << 4 = 101_0000 = 64

To perform, shift left, with 0s being shifted into the vacant position at the right.

 

To do a divide (and understand we'll be truncating, so your rounding will come into play)

42 / 8 = 42 >> (log2(8)) = 42 >> (3) = 10_1010 >> 3 = 101.010 = 5.25 (but we truncate) => 5 

To perform, shift right, with 0's being shifted into the vacant position at the left, and pay attention to rounding.

 

So now let's do this with 2's complement. Since sign bits matter, let's use 16-bit numbers. Here's a refresher on 2's Complement.

To invert the sign:    1) invert each bit.  2) add '1' (not just flip the LSB, but actually add).  This works in both directions.

So let's do similar problems as examples:

-52  * 4 = invert(-52) * 4 = invert(invert(-52) < (log2(4))) = invert( 52 << 2) = invert (0011_0100 << 2) = ...
... invert (1101_0000) = invert (208) = -208.

So much longer, but still do-able in SCTL at fairly high frequency.
1) invert your operand by flipping all bits and adding 1.
2) shift your operand for either mult/divide by the log2 of the amount to be mult/divided.
3) invert your results by flipping all bits and adding 1. 

This saves you the need for DSP48E slices, lets you abstract the invert function into a subVI, lets you operate in SCTL.

0 Kudos
Message 10 of 10
(6,140 Views)