declare_array_real

Macro declare_array_real 

Source
macro_rules! declare_array_real {
    ( $name:ident, $N:expr, $T:ty ) => { ... };
}
Expand description

This macro implements a type which consists of an array of fixed-point numberts of size N. Complete with the traits shown below.

§Arguments

  • name - The name of the array type. E.g. Arr4.
  • N - The length of the array. E.g 4.
  • T - The fixed type of the elements.

§Example

Arrays types of fixed size is defined with traits through the macro as follows:

use integer_array as ia;
use integer_array::trait_definitions::*;
use fixed::{types::extra::U20, FixedI32};
 
// Declare the type.
integer_array::declare_array_real!( Arr11, 11, FixedI32<U20> );

The name of the type for the above array is Arr11. The size of the error is 11 elements, and it has 18 fractional bits. The implemented traits are documented below. See the source for a complete list.

§Initialization

The array can be initalized with a single value across the array, or by creating a ramp.

§Generate an array of zeros.

zeros is made as separate trait for convenience.

use integer_array as ia;
use ia::trait_definitions::*;
use fixed::{types::extra::U20, FixedI32};
 
ia::declare_array_real!( Arr2, 2, FixedI32<U20> );
let x = Arr2::zeros();
assert_eq!{x.as_array_i32(), [0, 0]};

§::new

For creating an array with a specific value.

§Arguments

  • value - The falue to fill each item with.

§Example

use integer_array as ia;
use ia::trait_definitions::*;
use fixed::{types::extra::U20, FixedI32};
 
ia::declare_array_real!( Arr2, 2, FixedI32<U20> );
let x = Arr2::new(FixedI32::<U20>::from_num(200));
assert_eq!{x.as_array_i32(), [200, 200]};

To simplify decleration of arrays, float and int types are sypported through the following methods.

::new_from_i32( value ), ::new_from_f32( value ) and ::new_from_f64( value ).

§::ones

ones is made as separate trait for convenience. It generates an array of ones.

§Example

use integer_array as ia;
use ia::trait_definitions::*;
use fixed::{types::extra::U20, FixedI32};
 
ia::declare_array_real!( Arr2, 2, FixedI32<U20> );
let x = Arr2::ones();
assert_eq!{x.as_array_i32(), [1,1]};

§::ramp

Generate an array of increasing value.

§Arguments

  • start - The starting value (of item 0).
  • step - The incrimental value.

§Example

ramp_from_f32( value ) is added for convenience, but using ´ramp( value )´ with a value of the correct fixed type is also supported.

use integer_array as ia;
use ia::trait_definitions::*;
use fixed::{types::extra::U20, FixedI32};
 
ia::declare_array_real!( Arr4, 4, FixedI32<U20> );
let x = Arr4::ramp_from_f32(100.0,20.0);
assert_eq!{x.as_array_i32(), [100, 120, 140, 160] };

§::front and ::back:

Access the first element of the array using the .front() trait.

§Examples

use integer_array as ia;
use ia::trait_definitions::*;
use fixed::{types::extra::U20, FixedI32};
 
ia::declare_array_real!( Arr2, 2, FixedI32<U20> );
let x = Arr2::new(FixedI32::<U20>::from_num(200));
assert_eq!{x.front(), 200};

Access the last element of the array using the .back() trait.

use integer_array as ia;
use ia::trait_definitions::*;
use fixed::{types::extra::U20, FixedI32};
 
ia::declare_array_real!( Arr32, 32, FixedI32<U20> );
let x = Arr32::ramp_from_f32(100.0,20.0);
assert_eq!{x.back(), 720};

§::at

A specific item can be accessed through either using square bracket notation, or .at( index ).

§Arguments

  • index - The index of the item, in the range 0..N-1.

§Example

use integer_array as ia;
use ia::trait_definitions::*;
use fixed::{types::extra::U20, FixedI32};
 
ia::declare_array_real!( Arr2, 2, FixedI32<U20> );
let x = Arr2::zeros();
assert_eq!{x.at(1), 0};

§Bracket indexing

Square bracket indexing can be used both for reading and writing from/to an item.

§Examples

use integer_array as ia;
use ia::trait_definitions::*;
use fixed::{types::extra::U20, FixedI32};
 
ia::declare_array_real!( Arr8, 8, FixedI32<U20> );
let x = Arr8::ramp_from_f32(0.0,22.0);
assert_eq!{x[2], 44i32 };
use integer_array as ia;
use ia::trait_definitions::*;
use fixed::{types::extra::U20, FixedI32};
 
ia::declare_array_real!( Arr8, 8, FixedI32<U20> );
let mut x = Arr8::ramp_from_f32(0.0,22.0);
x[2] = FixedI32::<U20>::from_num(56);
assert_eq!{x[2], 56i32 };

§::bias

The bias trai adds a scalar bias to every element in the array.

§::odd and ::even

Get the items in the odd or even indexes as an array.

§Examples

use integer_array as ia;
use ia::trait_definitions::*;
use fixed::{types::extra::U20, FixedI32};
 
ia::declare_array_real!( Arr8, 8, FixedI32<U20> );
let x = Arr8::ramp_from_f32(0.0,22.0);
let y = x.odd();
assert_eq!{y, [22, 66, 110, 154] };
use integer_array as ia;
use ia::trait_definitions::*;
use fixed::{types::extra::U20, FixedI32};
 
ia::declare_array_real!( Arr8, 8, FixedI32<U20> );
let x = Arr8::ramp_from_f32(0.0,22.0);
let y = x.even();
assert_eq!{y, [0, 44, 88, 132] };

§::bias

The bias trai adds a scalar bias to every element in the array.

§Arguments

  • value - The bias amount.

§Examples

use integer_array as ia;
use ia::trait_definitions::*;
use fixed::{types::extra::U20, FixedI32};
 
ia::declare_array_real!( Arr2, 2, FixedI32<U20> );
let x = Arr2::new_from_i32(200);
let y = x.bias_f32(0.25);
assert_eq!{y.front(), 200.25};

The bias can also be implemented by adding or subtracting the array with a scalar.

use integer_array as ia;
use ia::trait_definitions::*;
use fixed::{types::extra::U20, FixedI32};
 
ia::declare_array_real!( Arr4, 8, FixedI32<U20> );
let mut x = Arr4::ramp_from_f32(0.0,22.0);
x = x+3;
assert_eq!{x[1], 25i32 };
 
let mut x = Arr4::ramp_from_f32(0.0,22.0);
x = x-3;
assert_eq!{x[1], 19i32 };

§::scale

The scale trait scales every element in the array with a scalar value.

§Arguments

  • value - The scaling factor.

§Examples

use integer_array as ia;
use ia::trait_definitions::*;
use fixed::{types::extra::U20, FixedI32};
 
ia::declare_array_real!( Arr2, 2, FixedI32<U20> );
let x = Arr2::new_from_i32(100);
let y = x.scale_f32(5.0);
   assert_eq!{y.front(), 500};

Scaling can also be used by simply multiplying the array with a scalar value.

use integer_array as ia;
use ia::trait_definitions::*;
use fixed::{types::extra::U20, FixedI32};

ia::declare_array_real!( Arr8, 8, FixedI32<U20> );
let mut x = Arr8::ramp_from_f32(0.0,22.0);
x = x*3;
assert_eq!{x[1], 66i32 };

or through a division.

use integer_array as ia;
use ia::trait_definitions::*;
use fixed::{types::extra::U20, FixedI32};
 
ia::declare_array_real!( Arr4, 4, FixedI32<U20> );
let mut x = Arr4::ramp_from_f32(0.0,22.0);
x = 1000/x;
assert_eq!{x.as_array_f32(), [2048.0, 45.454544, 22.727272, 15.151515] };

§::sqrt

The sqrt trait finds the item-wise square root of array.

§Argument

  • error - The gratest allowed error in the numerical method.

§Example

use integer_array as ia;
use ia::trait_definitions::*;
use fixed::{types::extra::U20, FixedI32};
 
ia::declare_array_real!( Arr4, 4, FixedI32<U20> );
let x = Arr4::ramp_from_f32(18.0, 10.0);
let y = x.sqrt( FixedI32::<U20>::from_num(0.1) );
assert_eq!{ y[1], 5.300915f32 };

§Array operations

Operations can also be performed on an inter-array-basis. The arrays must be of the same size. The operations are written similarly as one would for scalars in Rust.

§Examples

use integer_array as ia;
use ia::trait_definitions::*;
use fixed::{types::extra::U20, FixedI32};
 
ia::declare_array_real!( Arr4, 4, FixedI32<U20> );
let mut x = Arr4::ramp_from_f32(0.0,22.0);
let y = Arr4::new_from_i32(10);
x = x+y;
assert_eq!{x.as_array_i32(), [10,32,54,76] };
 
x = x-y;
assert_eq!{x.as_array_i32(), [0,22,44,66] };
use integer_array as ia;
use ia::trait_definitions::*;
use fixed::{types::extra::U20, FixedI32};
 
ia::declare_array_real!( Arr4, 4, FixedI32<U20> );
let mut x = Arr4::ramp_from_f32(10.0,22.0);
let  y = Arr4::new_from_i32(10);
x = x*y;
assert_eq!{x.data, [100,320,540,760] };
 
x = Arr4::ramp_from_f32(0.0,22.0);
x = x/y;
assert_eq!{x.as_array_i32(), [0,2,4,6] };

In a divide-by-zero case, the maximum int value is returned.

use integer_array as ia;
use ia::trait_definitions::*;
use fixed::{types::extra::U20, FixedI32};
 
ia::declare_array_real!( Arr4, 4, FixedI32<U20> );
let mut x = Arr4::ramp_from_f32(0.0,22.0);
let y = Arr4::new_from_i32(1);
x = y/x;
assert_eq!{x.as_array_f32(), [2048.0, 0.045454025, 0.022727013, 0.015151024] };

§::wrap_phase

Wrap array to a fixed-point -π=<x<π range.

§Example

use integer_array as ia;
use ia::trait_definitions::*;
use fixed::{types::extra::U20, FixedI32};
 
ia::declare_array_real!( Arr8, 8, FixedI32<U20> );
let x = Arr8::ramp_from_f32(0.0, 3.1415/3.0);
let y = x.wrap_phase();
assert_eq!{ y.as_array_f32(), [0.0, 1.0471668, 2.0943336, 3.1415005, -2.0945168, -1.0473499, -0.00018310547, 1.0469837] };

§::sin

Take the elemtent-wise sine using a Taylor approximation of sine x.

Sin is calculated using the following polynomial:

sin(x) = x -( x^3/6.0 )+( x^5/120.0 )-( x^7/5040.0 )+( x^9/362880.0 )

Self must be wrapped to the -π=<x<π range.

§Example

use integer_array as ia;
use ia::trait_definitions::*;
use fixed::{types::extra::U20, FixedI32};
 
ia::declare_array_real!( Arr8, 8, FixedI32<U20> );
let mut x = Arr8::ramp_from_f32(0.0,3.1415/6.0);
x = x.wrap_phase();
let y = x.sin();
assert_eq!{ y.as_array_f32(), [0.0, 0.49998665, 0.8660097, 1.0000038, 0.86605644, 0.50006676, 0.000091552734, -0.4999075] };

Below is the the taylor approximation for sine compared to the Julia native sin function. The below plot is generated with double presicion floationg point for demonstrative purposes. In the figure it is apparent that there is greater error in the Taylor approximation further from origo. Alt version To counter these, the fact that all quarters of the sine(x) function are mirrored versions of each other. Therefore the first quarters, having the least error, which can be seen in the time domain plot above, are used for all values of x. Resulting in a practically ideal sine function, as can be seen in the frequency domain comparison below. Alt version

§::cos

Take the elemtent-wise cosine using a Taylor approximation of cos x.

Cos is calculated using the following polynomial:

cos(x) = 1 -( x^2/2 )+( x^4/24.0 )-( x^6/720.0 )+( x^8/40320.0 )

Self must be wrapped to the -π=<x<π range.

§Example

use integer_array as ia;
use ia::trait_definitions::*;
use fixed::{types::extra::U20, FixedI32};
 
ia::declare_array_real!( Arr8, 8, FixedI32<U20> );
let mut x = Arr8::ramp_from_f32(0.0,60.0);
x = x.wrap_phase( );
let y = x.cos();
assert_eq!{ y.as_array_f32(), [1.0, -0.95240974, 0.814167, -0.5984316, 0.3257389, -0.022058487, -0.2837639, 0.56254864] };

A first-quarter method as described for the sine implementation is also used on cosine. The pure Taylor approximation is displayed below. Alt version With the first-quarter method, the resulting cosine power spectrum is displayed below. Alt version

§::tan

Take the element-wise tan using a Taylor approximation of tan x.

Tan is calculated using the following polynomial:

tan(x) = x+( x^3/3 )+( x^5*2/15.0 )+( x^7*17/315.0 )+( x^9*62/2835.0 )+( x^11*1382/155925.0 )+( x^13*21844/6081075.0 )+( x^15*929569/638512875.0 )

Self must be wrapped to the -π/2=<x<π/2 range. The function is based on a Taylor expansion. Its error increases as |x| approaches π/2.

§Example

use integer_array as ia;
use ia::trait_definitions::*;
use fixed::{types::extra::U4, FixedI32};
 
ia::declare_array_real!( Arr8, 8, FixedI32<U4> );
let x = Arr8::ramp_from_f32(0.0,0.17);
let y = x.tan();
assert_eq!{ y.as_array_f32(), [0.0, 0.1875, 0.375, 0.5625, 0.875, 1.25, 1.6875, 2.5625] };

Below is the the taylor approximation for tan compared to the Julia native tan function. The below plot is generated with double presicion floationg point for demonstrative purposes. Alt version

§::atan

Calculate atan(x) using a polynomial approximation. Utilizes the following polynomial to estimate the angle θ [radians].

atan(x) = ((x)+0.372003(x)^3) / (1+0.703384(x)^2 + 0.043562(x)^4)

The method is accurat within 0.003 degrees when |θ|<=π/4.

[1] R. G. Lyons, Streamlining Digital Signal Processing, Second Etition, IEEE Press, 2012.

§Example

use integer_array as ia;
use ia::trait_definitions::*;
use fixed::{types::extra::U4, FixedI32};
 
ia::declare_array_real!( Arr8, 8, FixedI32<U4> );
let x = Arr8::ramp_from_f32(0.0,0.1);
let y = x.atan();
assert_eq!{ y.as_array_f32(), [0.0, 0.125, 0.25, 0.3125, 0.4375, 0.5, 0.625, 0.6875] };

§::max and ::min

The maimum and minimum value in the array can be found through the .max() and .min() traits respectively.

§Examples

use integer_array as ia;
use ia::trait_definitions::*;
use fixed::{types::extra::U20, FixedI32};
 
ia::declare_array_real!( Arr32, 32, FixedI32<U20> );
let x = Arr32::ramp_from_f32(100.0,20.0);
assert_eq!{x.max(), 720};
use integer_array as ia;
use ia::trait_definitions::*;
use fixed::{types::extra::U20, FixedI32};
 
ia::declare_array_real!( Arr32, 32, FixedI32<U20> );
let x = Arr32::ramp_from_f32(100.0,20.0);
assert_eq!{x.min(), 100};

§::argmax and ::argmin

The index of the maximum and minimum items in the array can be found through the .argmax() and .argmin() traits respectively.

§Example

use integer_array as ia;
use ia::trait_definitions::*;
use fixed::{types::extra::U20, FixedI32};
 
ia::declare_array_real!( Arr32, 32, FixedI32<U20> );
let x = Arr32::ramp_from_f32(0.0,1.0);
assert_eq!{x.argmax(), 31};
use integer_array as ia;
use ia::trait_definitions::*;
use fixed::{types::extra::U20, FixedI32};
 
ia::declare_array_real!( Arr32, 32, FixedI32<U20> );
let x = Arr32::ramp_from_f32(100.0,20.0);
assert_eq!{x.argmin(), 0};