Quartus: FIR filters using megafunctions - Page 1
Forum section: electronics / general

author: RedLion
author_rank: Regular Contributor
timestamp: September 03, 2020, 10:30:22 pm
content: Hello everyone,for a university course I am tasked to build 4 second-order FIR filters (one each hi-pass, lo-pass, band-pass, band-cut).The requirement is to build them graphically using megafunctions and subsequently create symbol files of the entire thing to put all 4 in another project at the end.Now, the problem I'm having is that I'm supposed to work with signed fixed-point-decimals (Q1.3, 2's complement), but I failed at the first block I tried to place, because the IP Cores only seem to support integers.Intuitively, I would assume that the use of decimals is not possible, and figure out a little VHDL file to shift the whole thing over by 3 bits, and shift the output back. But then I wouldn't know how to get the decimal numbers out on the other side, as I've never worked with decimal numbers on FPGAs at all. Am I missing something obvious here? Or how would one go about this?There is no device to program here by the way, because the unis are still closed, it just has to work with the .vwf simulation.Huge Thanks to all,Ivo

author: Daixiwen
author_rank: Frequent Contributor
timestamp: September 04, 2020, 08:06:45 am
content: Requiring to build a filter graphically instead of HDL is torture, I'm so sorry for you!In VHDL you could use the sfixed type from VHDL 2008 and just do everything with the regular * and + operators.But since you need to use the megafunctions, as you figured out you need to do some bit shifting around. Additions work the same way whether they work on integer or fixed point so you don't need to do anything there, but when you multiply two fixed point decimals you need to shift the result and throw away the LSBs. Now if you can live with just throwing away the LSBs, there is a way in the graphical tool from Quartus to pick up a part of a vector into a new vector. Unfortunately I haven't used it in a while so I can't give you more details about it.If you want to round the result instead you will need a small block of VHDL, I don't think there is any megafunction for that.

author: BrianHG
author_rank: Super Contributor
timestamp: September 04, 2020, 10:03:09 am
content: These are the floating point megafunctions.The old-style ones are available in all the old quartus versions before Quartus-Prime.They use 32 bit single or 64 bit double precision.You will need to take care about clock cycles as these functions are complex and require at least 2 clocks, more like 6 through 11 for a better FMAX on the slower low end Cyclone series FPGAs.The new style has the full function set including compares, trig functions and complex plane multiply.All these can has a pipeline clock set between 2 through any higher number depending on your desired FMAX and the megafunction builder will give you the predicted FMAX based on pipeline clock delay, or, you choose the desired FMAX and you will be told the required pipeline delay.The new style FP_megafunction will also support smaller and odd number of floating point bit depths like 16bit half precision.The input and output is in standard IEEE 754 format.

author: BrianHG
author_rank: Super Contributor
timestamp: September 04, 2020, 10:17:00 am
content: If you are just doing integer and want to shave bits, all you need to do is:-------------ina[15..0] ------| || MULT1 |------p[31..0]inb[15..0]-------| |--------------------------p[31..16] ------| || MULT2 |------q[31..0]inc[15..0]-------| |--------------------------q[31..16] ------| || MULT3 |------z[31..0]ind[15..0]-------| |-------------z[31..16]-----output_pin result[15..0]Just break the wire like above and take the top bits when feeding the second multiply or add...

author: RedLion
author_rank: Regular Contributor
timestamp: September 04, 2020, 12:45:12 pm
content: First of all thanks to all of you for the help.Quote from: BrianHG on September 04, 2020, 10:03:09 amUnfortunately, we're supposed to use fixed point decimals only.But I wondered, if all that's coming from the ADC is a 4 bit vector, couldn't you just treat the numbers as integers and interprete them as fixed-point decimals after the fact?

author: BrianHG
author_rank: Super Contributor
timestamp: September 04, 2020, 01:02:25 pm
content: Quote from: RedLion on September 04, 2020, 12:45:12 pmAre you sure you may not be interpreting the test properly?Integer in, integer out. All fixed point.If you are multiplying 2 numbers, you can use the full result, or, use the bit-shaving-shift in my second integer example to divide the result by 2/4/8/16/32...In simple terms,X = A * ((1/16) * B)is the same asX = A * B, thenon X, shave off the 4 LSBs which basically dividing the result by 16 without any logic.also equals in Verilog code:X <= (A * B) >> 4;In binary, the decimal point, or, M.N math has a binary fraction, not decimal.This means 1/2, 1/4, 1/8, 1/16 for each bit after the decimal point.Otherwise you would need a X 10/100/1000 of your source data and your output will be x 10,100, or 1000 and you would mentally need to note that there is a decimal place shift when you print the decimal result.

author: RedLion
author_rank: Regular Contributor
timestamp: September 04, 2020, 01:10:07 pm
content: Quote from: BrianHG on September 04, 2020, 01:02:25 pmIf you mean the course instrucions, yes, they are unmistakably stating that the input from the ADC is coded as Q1.3 2's complement signed fixed point decimals. The DAC expects its values in that same format.As far as my fixed point arithmethics go, shift to the left by 3 (not 4, as I have written before) would give a signed 4 bit integer, if you multiply 2 of them, that will get you 8 bits, and you then shift back 6 positions. The instructions also state to just drop the MSB.

author: BrianHG
author_rank: Super Contributor
timestamp: September 04, 2020, 01:26:57 pm
content: Quote from: RedLion on September 04, 2020, 01:10:07 pmOoops, sorry for not re-reading your top post when I was going on and on.Ok, in the block diagram editor, here is another example of shaving and shifting bits:Now your ADC & DAC Q1.3 coding I'm assuming is 1 bit for 2's compliment sign and 3 bits for the amplitude.-------------ina[3..0] -------| || MULT3 |------z[7..0]inf[3..0]---------| |-------------z[6..3]-----output_pin result[3..0]orx[7..5] -> (wire symbol) -> zout[2..0](gnd symbol) -> zoutYou will need to adjust this to your needs.You can also do a bundled XOR symbol with 1 bus in and out of the 1.3 as 4 straight bits, and the second input with the MSB = to 1 and the 3lsb equal the the first input MSB so you can convert the 2's compliment to a straight binary, perform the filter with positive numbers only, then convert back to 2's compliment for the output. (I hope I got that one right, still need my morning coffee...)

author: BrianHG
author_rank: Super Contributor
timestamp: September 04, 2020, 01:40:10 pm
content: Was this all you were asking for, a 2's converter back and forth in block diagram form?This means 0 through 7 will be converted to 8 up to 15 while 0 through -8 will be converted to 8 down to 0.IE, 2's -8 through +7 becomes 0 through 15.Because, if all you were asking was about shifting bits around, it's basic 101 child's play. You are just naming what range is wired into the new net name.

author: BrianHG
author_rank: Super Contributor
timestamp: September 04, 2020, 01:49:33 pm
content: This should be equivalent, but it's been so long ago, you would need to verify.I think you can use the 'WIRE' to take 1 signal and spread it across a bus...

author: asmi
author_rank: Super Contributor
timestamp: September 04, 2020, 01:56:13 pm
content: Quote from: BrianHG on September 04, 2020, 01:02:25 pmHow do you know what operations (and how many) happen inside IP core? FIRs typically use MACC operations, so you will need to adjust the decimal point (or truncate) as many bits as there are multiply/MACC operations.It's really odd that Quartus IP does not support fixed point math as it's a SUPER common use case for DSP. Xilinx IP ("FIR Compiler") does support fixed point datapath - it allows you specifying number of fractional bits in the input, and it will either output a full-precision result (which will have more integer bits than input), or you can use some rounding (in this case it will tell you at design time where decimal point is in the result).

author: BrianHG
author_rank: Super Contributor
timestamp: September 04, 2020, 02:10:30 pm
content: Quote from: asmi on September 04, 2020, 01:56:13 pmThe OP is making his own filter, not using Quartus's FIR firter. At least this is what I believe when he says 'I am tasked to build 4 second-order FIR filters'.He's literally is being asked to do all that work by hand.The output from Altera's MACC does give you all the summed bits. But what I guess you are asking is if you can limit/truncate the output bits. Trimming off bits from the left side seems possible when defining the megafunction. It's trimming bits off the right side, IE divide the result down which you need to do manually.Outside of just using the floating-point which doesn't have this issue, I have not done enough integer math using the mega-functions to ever have to worry about the problem, so I don't know. I usually do such coding in verilog.I do not have experience with Altera's FIR compiler megafunction. However, the new Quartus Prime has far superior handling of data-path definition when doing math with any megafunctions on the block diagram entry.

author: asmi
author_rank: Super Contributor
timestamp: September 04, 2020, 02:57:30 pm
content: Quote from: BrianHG on September 04, 2020, 02:10:30 pmAre we both reading the same text? Quote from the OP:QuoteThat seems to be the total opposite of what you're saying.

author: NorthGuy
author_rank: Super Contributor
timestamp: September 04, 2020, 03:01:52 pm
content: Quote from: RedLion on September 04, 2020, 01:10:07 pmThen do not worry about the format. If you enter Q1.3 numbers to FIR routines and want to get Q1.3 result, it's all the same as if you fed 4-bit integers to the FIR routines and wanted to get the integer result.The FIR coefficients will be scaled integers. As a result of series of MACs, you'll get an integer number. You get the top 4 bits of the result. If you want the result in the same format as the ADC, it doesn't matter if they're 4-bit integers, Q1.3, Q2.2 or whatever. As it wouldn't matter if these were mV, V, kV, as long as both are the same.

author: SiliconWizard
author_rank: Super Contributor
timestamp: September 04, 2020, 04:06:50 pm
content: Quote from: Daixiwen on September 04, 2020, 08:06:45 amI've never used the fixed types in VHDL so far. The main standard package to consider is 'fixed_generic_pkg'. Since VHDL-2008 support is still not quite complete in some synthesis tools, I wonder which FPGA vendors fully supports this one, and whether it's fully synthesizable? Then if it is, I wonder how the tools really implement fixed point under the hood, and how resource-hungry that would be.If anyone has already experimented with that...

author: asmi
author_rank: Super Contributor
timestamp: September 04, 2020, 04:42:00 pm
content: Quote from: SiliconWizard on September 04, 2020, 04:06:50 pmFor Xilinx Vivado - there is a section in the UG901 explaining how to use it. Basically, it is supported, but requires going through some hoops. Here are excerpts from the document (Chapter 6: VHDL-2008 Language Support -> Supported VHDL-2008 Features -> Fixed Point Support):QuoteQuoteQuoteAddition and multiplication are supported for synthesis, however you've got to make sure that the signal for result has appropriate size (there is a table in the document showing how to calculate correct size).Also, in VHDL-2008 is now legal to assign value directly to output ports, without using intermediate signals (as was previously required, which contributed a lot to the noise in the code), also port maps now can use function calls, assignments and logic expressions:Quote

author: BrianHG
author_rank: Super Contributor
timestamp: September 04, 2020, 06:03:37 pm
content: Quote from: asmi on September 04, 2020, 02:57:30 pmI so screwed up this one...Ok, your right, it was Daixiwen first line in reply #1 here:Quote from: Daixiwen on September 04, 2020, 08:06:45 amHun, I'm so sorry for you?Did I read RedLion's opening post wrong?Double clicking on an empty block diagram and selecting a fir filter megafunction compiler, then just configuring it.I took those words'Requiring to build a filter graphically instead of HDL is torture, I'm so sorry for you!'meaning RedLion was expected to configure a bunch of multiply adds to generate a FIR filter from scratch.I could not understand such dread in just filling the right numbers into this 'altera_fir_compiler_ii' megafunction:So, I assumed RedLion had to do everything from scratch...I mean, everything is there. Bit shift, truncate, including thing like you mentioned, rounding the truncated results and saturating the results when using a truncated output.I think this is what the RedLion was talking about:

author: asmi
author_rank: Super Contributor
timestamp: September 04, 2020, 07:19:35 pm
content: Quote from: BrianHG on September 04, 2020, 06:03:37 pmThat's what I assumed too! Which is why I was so surprised that someone would have any troubles using it.

author: Daixiwen
author_rank: Frequent Contributor
timestamp: September 07, 2020, 08:29:48 am
content: It's possible I misunderstood the original question, I thought the OP had to do a FIR filter from scratch using only elementary operations.Of course if you can use the FIR filter compiler then it is pretty easy once you know where to fill the details, as BrianHG showed. But then I don't see what you are supposed to learn from this assignment.

author: RedLion
author_rank: Regular Contributor
timestamp: September 07, 2020, 01:48:58 pm
content: Sorry to all of you for the late reply, but it seems the notification fairy has taken the weekend off.I could have been clearer with my questions, I am supposed to build the filter graphically, with either IP Cores or Megafunctions (I think the assignment text is so old it predates the phrase "IP cores"), but build it from scratch using the basic building blocks, I.E. latches, adders and multipliers.Essentially, we're given this:[ Specified attachment is not available ]and we have to rebuild it in the block diagram file. Same goes for the other three filters. Using the FIR megafunction straight from the library would have been too easy. So BrianHG read it right the first time.The conversion I am speaking of was from Q1.13 to signed integer at the beginning and back to Q1.13 at the end, since all Megafunctions/IP Cores seem to expect signed integers.But since the bitvector is the same in the end, as NorthGuy says, it should not be a problem to just treat the numbers "as if they were integers" and truncate the bits as I need in the end. That's the part I didn't know because I've never even seen fixed point decimals before.I contacted the professor in the mean time and he confirmed to me that the data was supposed to come in as 14-bit-vector from the ADC. As far as I know those don't have decimal points, so it's all just a matter of interpretation, right?Also note that the number has suddenly gone up to 14 bit, because it didn't say in the assignment and I misread my notes the entire time. Apparently I can't read my own handwriting.Sorry again for all the confusion I caused.Edit: Also, the bloody image doesn't attach for no fuckin' reason. Just pretend it did.

author: BrianHG
author_rank: Super Contributor
timestamp: September 07, 2020, 03:56:01 pm
content: Your Z-1is nothing more than a DFF symbol with a bus input and a bus output for the data line. All the DFF clks need to be tied together to the data clock input pin.The adds are nothing more than 2 signed 'lpm_add_sub' commands with no clocks.The 0.25 and 0.5 are bit shifts by 1 and 2, where you copy the MSB, or 2's sign bit into the top missing bits so that you retain the positive or negative number.Or you can set the 'lpm_add_sub' command to have a different 'B' size in bits and shave the LSBs so you don't need to bother retaining the MSB.'lpm_mult' may also be used with port 'B' set to 3 bits signed, shaving the output LSB bits allowing for positive and negative coefficients.'lpm_mult' is more useful as you can set port 'B' to 8 bits, or anything even larger to create longer filters with varying coefficients or even dynamic ones.'lpm_add_sub' can also be replaced with 'parallel_add' to add all the coefficients together in a single module.For highest qualityof output, you would multiply the 0.5 value by 2, keep the 0.25 as 1:1, add all the values together, then trim the bottom 2 output bits after/at the adder output. This way you do not shave/loose LSB information/definition when adding the coefficients together.

author: NorthGuy
author_rank: Super Contributor
timestamp: September 07, 2020, 06:08:23 pm
content: Your coefficients are effectively 2-bit, so you need 16-bit accumulator (14 + 2 = 16). You don't need multiplication for these numbers. If you used CPU you could use shifts. With FPGA you just select appropriate wires. The whole thing is just 3 lines of code:Code:x1 <= x;x2 <= x1;s <= "00"&x + "0"&x1&"0" + "00"&x2;One you get the 16-bit sum, you take the top 14 bits and dismiss the bottom 2.For better rounding, you may add "10":Code:x1 <= x;x2 <= x1;s <= "00"&x + "0"&x1&"0" + "00"&x2 + "0000000000000010";If you need speed, you pipeline it.This all works the same whether x is signed or unsigned.Of course, it must be hard work to do this with blocks and megafunctions. So, in your spare time, you may ask your professor why does he need blocks and megafunctions, when three lines of code is quite sufficient.

author: RedLion
author_rank: Regular Contributor
timestamp: September 10, 2020, 09:43:51 pm
content: Just to update everyone, I could make my filters work.I have pictures of the Low Pass and High Pass attached, the other two are still in the making.Apparently, the only complicated bit about the numbers was to convert the constants from Q1.13 to 14bit integer and know whrer to chop off the output at the end.The Constant 12288 is what -4096 would look like as a positive integer. Works just as well, just has to be the exact number of bits.Could have been so easy if we learned to do this in our courses but we are left to find that out by ourselves because that's apparently what's understood as "excellent university" these days....anyways...Thank you all for helping

author: RedLion
author_rank: Regular Contributor
timestamp: September 14, 2020, 12:01:41 am
content: Oh and for good measure, here's a Bandpass in VHDL, written in 10 minutes. That's 30 lines of code after you discount my liberal application of dead space.Worked on first try. Just saying. IfEVERyou wanted to do this, do it that way.Code:library ieee;use ieee.std_logic_1164.all;use ieee.numeric_std.all;entity FIRBandPass isport(CLK : in std_logic;X_n : in integer range -8192 to 8191;Y_n : out integer);end entity;architecture FIRBandPass_arch of FIRBandPass issignal Z_1 : integer := 0;-- Latch 1signal Z_2 : integer := 0;-- Latch 2signal P_1 : integer := 0;-- Produkt 1signal P_2 : integer := 0;-- Produkt 2beginprocess (CLK) -- D-Flipflop-- Ein doppeltes, 14 bit breites D-Flipflop/Schieberegisterbeginif rising_edge(CLK) thenZ_1 <= X_n;Z_2 <= Z_1;end if;end process;process (CLK) -- Pipeline-- Um dem Multiplizierer einen Takt Zeit zu geben.beginif rising_edge(CLK) thenP_1 <= X_n * (-4096);P_2 <= Z_2 * 4096;end if;end process;Y_n <= P_1 + P_2;end architecture;

author: Daixiwen
author_rank: Frequent Contributor
timestamp: September 14, 2020, 07:57:56 am
content: Maybe that's the lesson you are supposed to learn from the assignmentAnd you now have code that you can use also on other FPGAs, rather than be locked on Altera/Intel.