From: Jeffrey Carter <spam.jrcarter.not@spam.not.acm.org>
Subject: Re: RFC: Generic Fixed-Point IIR Filter
Date: Thu, 26 Mar 2015 10:41:15 -0700
Date: 2015-03-26T10:41:15-07:00 [thread overview]
Message-ID: <mf1ga8$ukc$1@dont-email.me> (raw)
In-Reply-To: <a05f90b1-491d-4e9a-8a01-722c6a136668@googlegroups.com>
On 03/26/2015 09:25 AM, Patrick Noffke wrote:
>
> Below is my first attempt. I noticed the following issues:
> - I cannot define Filter_Value_Type within the IIR_Filter package (i.e. it has to be a generic parameter). If I try to put it in the package and base it on Fixed_Type, I get an error that a non-static expression is used for the delta and range. For example, this gives the error I just mentioned:
>
> type Filter_Value_Type is delta Fixed_Type'Delta / 10
> range N_A * Fixed_Type'First .. N_A * Fixed_Type'Last;
>
> I realize (from http://en.wikibooks.org/wiki/Ada_Programming/Generics) that generic formal objects are non-static, but it's not clear to me why this won't work for a generic formal type (how can a type be non-static?). Is there another way to parameterize the delta and range for intermediate calculations?
All generic formal parameters are non-static. As to a non-static type consider
generic -- P
type T is range <>;
package P is ...
and then
function Input return Natural;
-- Obtains a value of subtype Natural from the user
...
subtype U is Integer range 1 .. Input;
package Q is new P (T => U);
Clearly subtype U is non-static, and so formal type T is also non-static.
>
> - If I try to use Fixed_Type for X_Array and Y_Array, then I do in fact get a constraint error (due to range overflow for an intermediate calculation). Is there a better way to do a calculation for a fixed-point type when you expect the result to be within the specified range of Fixed_Type, but intermediate calculations may not?
All your problems result from suffixing type names with _Type :)
I refer you to ARM 4.5.5, specifically ¶18-19. Multiplication and division
between fixed-point values gives results of type universal_fixed, which is
implicitly convertible to any fixed-point type. When you write
Filter.Y_Array (1) := Filter.B (1) * X;
you are multiplying a Filter_Value_Type * Fixed_Type yielding universal_fixed,
which is then implicitly converted to the type of the LHS, Filter_Value_Type.
Your exceptions result from attempting to convert intermediate results to
Fixed_Type, which lacks the range needed to hold the values. It is therefore
sometimes possible to avoid the 2nd type if all calculations can be done in a
single expression which yields a value that fits in the smaller type, despite
having intermediate results which do not. That doesn't seem to be case for your
problem, though.
Some comments on your implementation:
> package body IIR_Filter is
>
> procedure Init_Filter (Filter : in out IIR_Filter_Type;
Filter appears to be an "out" parameter, not "in out".
> A_Coefficients : A_Coefficient_Array_Type;
> B_Coefficients : B_Coefficient_Array_Type;
> Initial_Value : Fixed_Type) is
> begin
> Filter.A := A_Coefficients;
> Filter.B := B_Coefficients;
> for X_Index in Filter.X_Array'Range loop
> Filter.X_Array (X_Index) := Filter_Value_Type (Initial_Value);
> end loop;
Filter.X_Array := (others => Filter_Value_Type (Initial_Value) ); ?
> for Y_Index in Filter.Y_Array'Range loop
> Filter.Y_Array (Y_Index) := Filter_Value_Type (Initial_Value);
> end loop;
Or even
Filter := (A => A_Coefficients,
B => B_Coefficients,
X_Array => (others => Filter_Value_Type (Initial_Value) ),
Y_Array => (others => Filter_Value_Type (Initial_Value) ) );
> end Init_Filter;
>
> function Step_Filter (Filter : in out IIR_Filter_Type;
> X : Fixed_Type) return Fixed_Type is
> begin
> -- Compute IIR filter using Direct Form I.
>
> -- Move the elements to next oldest position.
> -- TODO: Use a circular buffer for this.
> if Filter.X_Array'Length > 1 then
This if statement (and others like it) is unnecessary. The loop will execute
zero times if the length is 1.
> for X_Index in reverse 2 .. Filter.X_Array'Last loop
> Filter.X_Array (X_Index) := Filter.X_Array (X_Index - 1);
> end loop;
> end if;
Filter.X_Array (2 .. Filter.X_Array'Last) :=
Filter.X_Array (1 .. Filter.X_Array'Last - 1);
>
> if Filter.Y_Array'Length > 1 then
> for Y_Index in reverse 2 .. Filter.Y_Array'Last loop
> Filter.Y_Array (Y_Index) := Filter.Y_Array (Y_Index - 1);
> end loop;
> end if;
>
> -- Store the new X value.
> Filter.X_Array (1) := Filter_Value_Type (X);
>
> -- Compute new filter output. Initialize with b(1) * x(n).
> Filter.Y_Array (1) := Filter.B (1) * X;
>
> -- Compute b(2) * x(n - 1) + b(3) * x(n - 2) + ...
> if Filter.X_Array'Length > 1 then
> for X_Index in 2 .. Filter.X_Array'Last loop
> Filter.Y_Array (1) := Filter.Y_Array (1) +
> Filter.B (X_Index) * Filter.X_Array (X_Index);
> end loop;
> end if;
You appear to be storing things backwards: x(n) is in X_Array (1), x(n-1) in
X_Array (2), ... (similarly for y). This makes your comments confusing.
HTH.
--
Jeff Carter
"Since I strongly believe that overpopulation is by
far the greatest problem in the world, this [Soylent
Green] would be my only message movie."
Charleton Heston
123
next prev parent reply other threads:[~2015-03-26 17:41 UTC|newest]
Thread overview: 13+ messages / expand[flat|nested] mbox.gz Atom feed top
2015-03-26 16:25 RFC: Generic Fixed-Point IIR Filter Patrick Noffke
2015-03-26 17:05 ` Dmitry A. Kazakov
2015-03-26 17:41 ` Jeffrey Carter [this message]
2015-03-26 19:44 ` Patrick Noffke
2015-03-26 20:34 ` Randy Brukardt
2015-03-26 20:39 ` Jeffrey Carter
2015-03-26 21:12 ` Randy Brukardt
2015-03-26 21:30 ` Patrick Noffke
2015-03-26 22:02 ` Jeffrey Carter
2015-03-27 12:17 ` G.B.
2015-03-26 21:17 ` Patrick Noffke
2015-03-26 20:37 ` Jeffrey Carter
2015-03-27 11:37 ` Brian Drummond
replies disabled
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox