# Standard library: Numerics

## Decibel Factor

Goal: implement functions to convert from Decibel values to factors and vice-versa.

Steps:

1. Implement the Decibels package.

1. Implement the To_Decibel function.

2. Implement the To_Factor function.

Requirements:

1. The subtypes Decibel and Factor are based on a floating-point type.

2. Function To_Decibel converts a multiplication factor (or ratio) to decibels.

• For the implementation, use $$20 * log_{10}(F)$$, where F is the factor/ratio.

3. Function To_Factor converts a value in decibels to a multiplication factor (or ratio).

• For the implementation, use $$10^{D/20}$$, where D is the value in Decibel.

Remarks:

1. The Decibel is used to express the ratio of two values on a logarithmic scale.

1. For example, an increase of 6 dB corresponds roughly to a multiplication by two (or an increase by 100 % of the original value).

2. You can find the functions that you'll need for the calculation in the Ada.Numerics.Elementary_Functions package.



package Decibels is

subtype Decibel is Float;
subtype Factor  is Float;

function To_Decibel (F : Factor) return Decibel;

function To_Factor (D : Decibel) return Factor;

end Decibels;

package body Decibels is

function To_Decibel (F : Factor) return Decibel is
begin
return 0.0;
end To_Decibel;

function To_Factor (D : Decibel) return Factor is
begin
return 0.0;
end To_Factor;

end Decibels;

with Decibels;         use Decibels;

procedure Main is
type Test_Case_Index is
(Db_Chk,
Factor_Chk);

procedure Check (TC : Test_Case_Index; V : Float) is

package F_IO is new Ada.Text_IO.Float_IO (Factor);
package D_IO is new Ada.Text_IO.Float_IO (Decibel);

procedure Put_Decibel_Cnvt (D : Decibel) is
F : constant Factor := To_Factor (D);
begin
D_IO.Put (D, 0, 2, 0);
Put (" dB => Factor of ");
F_IO.Put (F, 0, 2, 0);
New_Line;
end;

procedure Put_Factor_Cnvt (F : Factor) is
D : constant Decibel := To_Decibel (F);
begin
Put ("Factor of ");
F_IO.Put (F, 0, 2, 0);
Put (" => ");
D_IO.Put (D, 0, 2, 0);
Put_Line (" dB");
end;
begin
case TC is
when Db_Chk =>
Put_Decibel_Cnvt (Decibel (V));
when Factor_Chk =>
Put_Factor_Cnvt (Factor (V));
end case;
end Check;

begin
if Argument_Count < 2 then
Put_Line ("ERROR: missing arguments! Exiting...");
return;
elsif Argument_Count > 2 then
end if;

Check (Test_Case_Index'Value (Argument (1)), Float'Value (Argument (2)));
end Main;

Enable tabbed editor view for this editor

Use the dark theme



## Root-Mean-Square

Goal: implement a function to calculate the root-mean-square of a sequence of values.

Steps:

1. Implement the Signals package.

1. Implement the Rms function.

Requirements:

1. Subtype Sig_Value is based on a floating-point type.

2. Type Signal is an unconstrained array of Sig_Value elements.

3. Function Rms calculates the RMS of a sequence of values stored in an array of type Signal.

1. See the remarks below for a description of the RMS calculation.

Remarks:

1. The root-mean-square (RMS) value is an important information associated with sequences of values.

1. It's used, for example, as a measurement for signal processing.

2. It is calculated by:

1. Creating a sequence $$S$$ with the square of each value of an input sequence $$S_{in}$$.

2. Calculating the mean value $$M$$ of the sequence $$S$$.

3. Calculating the square-root $$R$$ of $$M$$.

3. You can optimize the algorithm above by combining steps #1 and #2 into a single step.



package Signals is

subtype Sig_Value is Float;

type Signal is array (Natural range <>) of Sig_Value;

function Rms (S : Signal) return Sig_Value;

end Signals;

package body Signals is

function Rms (S : Signal) return Sig_Value is
begin
return 0.0;
end;

end Signals;

package Signals.Std is

Sample_Rate : Float := 8000.0;

function Generate_Sine (N : Positive; Freq : Float) return Signal;

function Generate_Square (N : Positive) return Signal;

function Generate_Triangular (N : Positive) return Signal;

end Signals.Std;

package body Signals.Std is

function Generate_Sine (N : Positive; Freq : Float) return Signal is
S : Signal (0 .. N - 1);
begin
for I in S'First .. S'Last loop
S (I) := 1.0 * Sin (2.0 * Pi * (Freq * Float (I) / Sample_Rate));
end loop;

return S;
end;

function Generate_Square (N : Positive) return Signal is
S : constant Signal (0 .. N - 1) := (others => 1.0);
begin
return S;
end;

function Generate_Triangular (N : Positive) return Signal is
S      : Signal (0 .. N - 1);
S_Half : constant Natural := S'Last / 2;
begin
for I in S'First .. S_Half loop
S (I) := 1.0 * (Float (I) / Float (S_Half));
end loop;
for I in S_Half .. S'Last loop
S (I) := 1.0 - (1.0 * (Float (I - S_Half) / Float (S_Half)));
end loop;

return S;
end;

end Signals.Std;

with Signals;                 use Signals;
with Signals.Std;             use Signals.Std;

procedure Main is
type Test_Case_Index is
(Sine_Signal_Chk,
Square_Signal_Chk,
Triangular_Signal_Chk);

procedure Check (TC : Test_Case_Index) is
package Sig_IO is new Ada.Text_IO.Float_IO (Sig_Value);

N    : constant Positive := 1024;
S_Si : constant Signal := Generate_Sine (N, 440.0);
S_Sq : constant Signal := Generate_Square (N);
S_Tr : constant Signal := Generate_Triangular (N + 1);
begin
case TC is
when Sine_Signal_Chk =>
Put ("RMS of Sine Signal: ");
Sig_IO.Put (Rms (S_Si), 0, 2, 0);
New_Line;
when Square_Signal_Chk =>
Put ("RMS of Square Signal: ");
Sig_IO.Put (Rms (S_Sq), 0, 2, 0);
New_Line;
when Triangular_Signal_Chk =>
Put ("RMS of Triangular Signal: ");
Sig_IO.Put (Rms (S_Tr), 0, 2, 0);
New_Line;
end case;
end Check;

begin
if Argument_Count < 1 then
Put_Line ("ERROR: missing arguments! Exiting...");
return;
elsif Argument_Count > 1 then
end if;

Check (Test_Case_Index'Value (Argument (1)));
end Main;

Enable tabbed editor view for this editor

Use the dark theme



## Rotation

Goal: use complex numbers to calculate the positions of an object in a circle after rotation.

Steps:

1. Implement the Rotation package.

1. Implement the Rotation function.

Requirements:

1. Type Complex_Points is an unconstrained array of complex values.

2. Function Rotation returns a list of positions (represented by the Complex_Points type) when dividing a circle in N equal slices.

1. See the remarks below for a more detailed explanation.

2. You must use functions from Ada.Numerics.Complex_Types to implement Rotation.

3. Subtype Angle is based on a floating-point type.

4. Type Angles is an unconstrained array of angles.

5. Function To_Angles returns a list of angles based on an input list of positions.

Remarks:

1. Complex numbers are particularly useful in computer graphics to simplify the calculation of rotations.

1. For example, let's assume you've drawn an object on your screen on position (1.0, 0.0).

2. Now, you want to move this object in a circular path — i.e. make it rotate around position (0.0, 0.0) on your screen.

• You could use sine and cosine functions to calculate each position of the path.

• However, you could also calculate the positions using complex numbers.

2. In this exercise, you'll use complex numbers to calculate the positions of an object that starts on zero degrees — on position (1.0, 0.0) — and rotates around (0.0, 0.0) for N slices of a circle.

1. For example, if we divide the circle in four slices, the object's path will consist of following points / positions:

Point #1: ( 1.0,  0.0)
Point #2: ( 0.0,  1.0)
Point #3: (-1.0,  0.0)
Point #4: ( 0.0, -1.0)
Point #5: ( 1.0,  0.0)


Or graphically:

1. As expected, point #5 is equal to the starting point (point #1), since the object rotates around (0.0, 0.0) and returns to the starting point.

2. We can also describe this path in terms of angles. The following list presents the angles for the path on a four-sliced circle:

Point #1:    0.00 degrees
Point #2:   90.00 degrees
Point #3:  180.00 degrees
Point #4:  -90.00 degrees (= 270 degrees)
Point #5:    0.00 degrees

1. To rotate a complex number simply multiply it by a unit vector whose arg is the radian angle to be rotated: $$Z = e^\frac{2 \pi}{N}$$



package Rotation is

type Complex_Points is array (Positive range <>) of Complex;

function Rotation (N : Positive) return Complex_Points;

end Rotation;

package body Rotation is

function Rotation (N : Positive) return Complex_Points is
C : Complex_Points (1 .. 1) := (others => (0.0, 0.0));
begin
return C;
end;

end Rotation;

with Rotation; use Rotation;

package Angles is

subtype Angle is Float;

type Angles is array (Positive range <>) of Angle;

function To_Angles (C : Complex_Points) return Angles;

end Angles;

package body Angles is

function To_Angles (C : Complex_Points) return Angles is
begin
return A : Angles (C'Range) do
for I in A'Range loop
A (I) := Argument (C (I)) / Pi * 180.0;
end loop;
end return;
end To_Angles;

end Angles;

package Rotation.Tests is

procedure Test_Rotation (N : Positive);

procedure Test_Angles (N : Positive);

end Rotation.Tests;

with Angles;                 use Angles;

package body Rotation.Tests is

package C_IO is new Ada.Text_IO.Complex_IO (Complex_Types);
package F_IO is new Ada.Text_IO.Float_IO (Float);

--
--  Adapt value due to floating-point inaccuracies
--

function Adapt (C : Complex) return Complex is
function Check_Zero (F : Float) return Float is
(if F <= 0.0 and F >= -0.01 then 0.0 else F);
begin
return C_Out : Complex := C do
C_Out.Re := Check_Zero (C_Out.Re);
C_Out.Im := Check_Zero (C_Out.Im);
end return;

function Adapt (A : Angle) return Angle is
(if A <= -179.99 and A >= -180.01 then 180.0 else A);

procedure Test_Rotation (N : Positive) is
C : constant Complex_Points := Rotation (N);
begin
Put_Line ("---- Points for " & Positive'Image (N) & " slices ----");
for V of C loop
Put ("Point: ");
C_IO.Put (Adapt (V), 0, 1, 0);
New_Line;
end loop;
end Test_Rotation;

procedure Test_Angles (N : Positive) is
C : constant Complex_Points := Rotation (N);
A : constant Angles.Angles  := To_Angles (C);
begin
Put_Line ("---- Angles for " & Positive'Image (N) & " slices ----");
for V of A loop
Put ("Angle: ");
F_IO.Put (Adapt (V), 0, 2, 0);
Put_Line (" degrees");
end loop;
end Test_Angles;

end Rotation.Tests;

with Rotation.Tests;          use Rotation.Tests;

procedure Main is
type Test_Case_Index is
(Rotation_Chk,
Angles_Chk);

procedure Check (TC : Test_Case_Index; N : Positive) is
begin
case TC is
when Rotation_Chk =>
Test_Rotation (N);
when Angles_Chk =>
Test_Angles (N);
end case;
end Check;

begin
if Argument_Count < 2 then
Put_Line ("ERROR: missing arguments! Exiting...");
return;
elsif Argument_Count > 2 then
end if;

Check (Test_Case_Index'Value (Argument (1)), Positive'Value (Argument (2)));
end Main;

Enable tabbed editor view for this editor

Use the dark theme