Next: OTHER SPECIFIC TECHNICAL ASPECTS
Up: Sonic Flow A Program
Previous: ARCHITECTURE DESCRIPTION
Subsections
All the classes (table 3.2 and figure 3.2) will be desribed in detail in this chapter. Each subsection of this
chapter contains the specifications for one class, and the section name will be
the class name.
The SF_Block is an abstract base class, i.e. there cannot be an
instance of it. The SF_Network class and all the atomic blocks
described in section 4.2 of the functional specification [] are
derived from this class.
This class is the basic building block of the system. Theoretically networks
contain blocks only.
class SF_Block
{
public:
SF_Block (SF_Input_Terminal inputs[],
SF_Output_Terminal outputs[],
unsigned int num_inputs,
unsigned int num_outputs,
const char *instance_name = 0);
virtual ~SF_Block ();
inline const char *get_class_name () const;
inline const char *get_instance_name () const;
inline void set_instance_name (const char *instance_name);
inline SF_Network *get_host_network () const;
inline void set_host_network (SF_Network *host);
virtual void print (ostream *stream) const = 0;
virtual bool is_functional () const = 0;
inline bool is_potential_source () const;
inline bool is_potential_sink () const;
// simulation
virtual void finish (); // post-simulation cleanup
virtual void initialize (); // pre-simulation initializations
virtual void simulate () = 0; // one round of simulations
// for BFS ()
inline void address_first_output_connection ();
inline SF_Block *get_next_output_connection ();
protected:
const char * class_name; // generic name for the kind of this block
const char * instance_name; // an intuitive name for the very block
SF_Network * host_network; // the network this block belongs to
bool potential_source; // true if the block *can* act as a source
bool potential_sink; // true if the block *can* act as a sink
SF_Input_Terminal *input_terminals; // array of input terminals
SF_Output_Terminal *output_terminals; // array of output terminals
unsigned int num_input_terminals; // number of input term:s
unsigned int num_output_terminals; // number of output term:s
unsigned int output_terminal_index;// for sequential access to output term:s
// internally for {address_first, get_next}_output_connection ()
inline void address_first_output_terminal ();
inline SF_Output_Terminal *get_next_output_terminal ();
// for initialize ()
void clear_frames ();
private:
};
This is the constructor.
Figure 3.2:
Class hierarchy.
| 1 |
class_name = NULL |
| 2 |
instance_name = instance_name |
| 3 |
host_network = NULL |
| 4 |
potential_source = FALSE |
| 5 |
potential_sink = FALSE |
| 6 |
input_terminals = inputs |
| 7 |
output_terminals = outputs |
| 8 |
num_input_terminals = num_inputs |
| 9 |
num_output_terminals = num_outputs |
| 10 |
output_terminal_index = 0 |
- if the block is nonfunctional, prints (not functional) after the block name
class SF_Exception
{
public:
SF_Exception (const SF_Block *origin,
const char *description);
virtual ~SF_Exception ();
const SF_Block *origin; // the initiator of the exception or NULL
const char * description; // textual information
};
A frame is a short segment of a (currently one-dimensional) signal. Frames are
used to pass data around in networks.
class SF_Frame
{
public:
SF_Frame (SF_Frequency sample_rate);
virtual ~SF_Frame ();
inline SF_Sample *get_signal () const;
inline SF_Length get_signal_length () const;
inline void set_short_signal (bool short_signal);
void update_frame_length (SF_Frequency sample_rate);
// for global initialization FIXME only
// access to the static data member duration (DO NOT TOUCH)
static inline SF_Time get_duration () const;
static inline void set_duration (SF_Time dur);
private:
SF_Sample * signal; // frame_length number of SF_Samples
SF_Length frame_length;
bool short_signal; // true if get_length() is actually frame_length - 1
static SF_Time duration; // declaration of a static data member
};
This class implements the pathway for delivery of data into a block. The class
implements also the destination end of a wire.
class SF_Input_Terminal : public SF_Terminal
{
public:
SF_Input_Terminal (const char *name, // sample_rate and relative_s_r
const SF_Block *host, // are optional
bool multiple_inputs,
SF_Frequency sample_rate,
double relative_sample_rate);
SF_Input_Terminal (const char *name,
const SF_Block *host,
SF_Sample default,
bool multiple_inputs,
SF_Frequency sample_rate,
double relative_sample_rate);
virtual ~SF_Input_Terminal ();
// for connect () and disconnect ()
void add_input (const SF_Frame *in); // throws SF_Exceptions
void remove_input (const SF_Frame *in);
inline int get_degree () const; // the number of connections
void address_first_frame ();
SF_Frame * get_next_frame ();
private:
inline bool is_full () const; // true if no more connections are allowed
bool enable_default; // if a default value is used with absent wire
SF_Sample default_value; // the default value to use
SF_List * input_list; // list of SF_Frames from which to get data
int degree;
bool multiple_inputs;
};
This function is for the creation of wires. This function is called by
SF_Output_Terminal::connect ().
| 1 |
ADD (input_list, in) |
| 2 |
 |
This function is for the destruction of wires. This function is called by
SF_Output_Terminal::disconnect ().
| 1 |
try |
| 2 |
REMOVE (input_list, in) |
| 3 |
 |
| 4 |
catch (SF_Exception e) |
| 5 |
throw SF_Exception (host_block, ``Internal error.'') |
A generic ordered list of pointers.
class SF_List
{
public:
SF_List ();
virtual ~SF_List ();
void add (const void *content);
void remove (const void *content);
bool find (const void *content); // returns true, if the node is found
inline bool is_empty () const;
inline void address_first ();
inline const void *get_next ();
void sort (int (*comparison_function) (const void *a, const void *b));
private:
SF_List_Node * search (const void *content);
SF_List_Node * nil;
SF_List_Node * current;
}
Create an empty list.
| 1 |
a = new SF_List_Node |
| 2 |
 |
| 3 |
 |
| 4 |
 |
| 5 |
nil = a |
| 6 |
current = a |
Add a new node to the end of the list.
| 1 |
a = new SF_List_Node |
| 2 |
 |
| 3 |
 |
| 4 |
 |
| 5 |
 |
| 6 |
 |
Remove a node from the list.
| 1 |
 |
| 2 |
if then |
| 3 |
throw SF_Exception (NULL, ``Node not found'') |
| 4 |
 |
| 5 |
 |
| 6 |
delete a |
| 7 |
 |
Search for a certain node in the list.
| 1 |
 |
| 2 |
while and do |
| 3 |
 |
| 4 |
if then |
| 5 |
return NULL |
| 6 |
return a |
Reset the internal state of the list so that the succeeding
get_next () will return the first node on the list.
| 1 |
 |
Return the content of the next node on the list.
| 1 |
if current.next = nil then |
| 2 |
return NULL |
| 3 |
current = current.next |
| 4 |
return current.content |
Sort the list in ascending order according to the user supplied comparison
function. The comparison function must return an integer less than, equal to,
or greater than zero to indicate if the content a is to be considered
less than, equal to, or greater than the content b, respectively.
The SF_List_Node class is a dumb class in the sense that it is
essentially a plain data structure.
class SF_List_Node
{
public:
SF_List_Node ();
SF_List_Node (const void *content);
virtual ~SF_List_Node ();
const void * content;
SF_List_Node * next;
SF_List_Node * prev;
private:
}
The main class used to model dataflow diagrams.
class SF_Network : public SF_Block
{
public:
SF_Network ();
virtual ~SF_Network ();
// block handling
void add_block (SF_Block &block);
void remove_block (SF_Block &block);
void check (); // throws SF_Network_Sanity_Exceptions
virtual void print (ostream *stream);
inline SF_Time get_simulation_duration () const;
inline void set_simulation_duration (SF_Time dur_ms);
void start_simulation ();
void stop_simulation ();
virtual void finish ();
virtual void simulate ();
virtual void initialize (); // throws SF_Network_Sanity_Exceptions
inline bool is_running () const;
inline bool is_error () const;
inline SF_Exception *get_simulation_exception () const; // simulation-time exceptions
inline bool is_modified () const;
inline void set_modified (bool modified);
private:
// partitioning the blocks
void sort_block_list ();
void BFS (SF_Network_Block_List_Content *source);
SF_List * block_list; // list of blocks in the network
bool modified;
SF_Time simulation_duration;
// child process
pid_t simulation_child;
bool simulation_running;
SF_Exception * simulation_exception;
};
This function will check the consistency of the network, partition it to layers FIXME
| 1 |
if modified = FALSE then |
| 2 |
return |
| 3 |
for each SF_Network_Block block_list do |
| 4 |
SET_RANK (n, 0) |
| 5 |
INITIALIZE (n) |
| 6 |
for each SF_Network_Block block_list do |
| 7 |
if (IS_POTENTIAL_SOURCE (n.block) and (IS_FUNCTIONAL (n.block) then |
| 8 |
for each SF_Network_Block n block_list do |
| 9 |
SET_VISITED (n, FALSE) |
| 10 |
BFS (n) |
| 11 |
SORT (block_list) |
| 12 |
modified = FALSE |
foobar FIXME
| 1 |
for each SF_Network_Block block_list do |
| 2 |
SIMULATE (n) |
foobar FIXME
| 1 |
for each SF_Network_Block block_list do |
| 2 |
FINISH (n) |
The BFS function implements the breadth-first search (BFS) algorithm
according to [17, p. 261].
The basic principle is to calculate the rank of a block, i.e. its distance to
the farthest source. This distance can be defined otherwise as the greatest
number of hops (wirings) between a node and a source.
In the case of recursive networks there is an implicit delay within every
feedback loop. This implicit delay is not counted in into the rank; the
feedback loops are NOT traversed while finding the farthest source. This is
accomplished so that the finding algorithm must recognize the situations when it
has come back to a node it has already visited.
| 1 |
 |
| 2 |
 |
| 3 |
SET_VISITED (s, TRUE) |
| 4 |
SET_RANK (s, 1) |
| 5 |
 |
| 6 |
while do |
| 7 |
 |
| 8 |
for each SF_Network_Block .Adj do |
| 9 |
if v.visited = FALSE then |
| 10 |
SET_VISITED (v, TRUE) |
| 11 |
SET_RANK (v, MAX (v.rank, )) |
| 12 |
ENQUEUE (Q, v) |
| 13 |
if IS_POTENTIAL_SINK (v.block) then |
| 14 |
 |
| 15 |
DEQUEUE (Q) |
| 16 |
if then |
| 17 |
throw SF_Exception (s.block, ``No sink after this source'') |
Add a block to the end network. The block must be added to the end of
the block list to ensure the stability of the sorting algorithm. (FIXME?)
Remove a block from the network.
foobar FIXME
| 1 |
if simulation_running then |
| 2 |
throw SF_Exception (this, ``Network already running'') |
| 3 |
p = FORK () |
| 4 |
if ( ) then |
| 5 |
INITIALIZE () |
| 6 |
i=0 |
| 7 |
while  |
| 8 |
and not (SIGINT caught) do |
| 9 |
SIMULATE () |
| 10 |
i = i + 1 |
| 11 |
FINISH () |
| 12 |
else |
| 13 |
 |
| 14 |
 |
foobar FIXME
Figure 4.1:
An example printout.
 |
This class is a dumb class in the sense that it is essentially a plain data
structure.
class SF_Network_Block_List_Content
{
public:
SF_Network_Block_List_Content (const SF_Block *block);
virtual ~SF_Network_Block_List_Content ();
inline int compare (const void *a, const void *b) const;
int rank;
bool visited;
SF_Block * block;
private:
};
inline int compare (const void *a, const void *b) const
{
return ((SF_Network_Block_List_Content *)a)->rank
- ((SF_Network_Block_List_Content *)b)->rank;
}
The base class of all the exceptions the program throws.
class SF_Network_Sanity_Exception : SF_Exception
{
public:
SF_Network_Sanity_Exception (const SF_Block *origin,
const char *description);
virtual ~SF_Network_Sanity_Exception ();
};
This class implements the pathway for delivery of data out of a block. The
class implements also the connection of blocks (terminals) together and is
source end of a wire.
class SF_Output_Terminal : public SF_Terminal
{
public:
SF_Output_Terminal (const char *name,
const SF_Block *host,
SF_Frequency sample_rate, // sample_rate and
double relative_sample_rate); // r_s_r are optional
virtual ~SF_Output_Terminal ();
void connect (SF_Input_Terminal &dest);
void disconnect (SF_Input_Terminal &dest);
SF_Output_Terminal &operator>> (SF_Input_Terminal &destination); // operator `>>' duplicates
// the functionality of
// Network::connect ()
private:
SF_List * wire_destinations; //list of input terminals
SF_Frame * output; //the frame which is filled every epoch
};
The connection function is called by the user.
Figure 4.1:
An example printout.
| 1 |
 |
| 2 |
if not IS_FULL (d) then |
| 3 |
ADD (d, wire_destinations) |
| 4 |
SET_MODIFIED (GET_HOST_NETWORK (host_block), TRUE) |
| 5 |
ADD_INPUT (d, output) |
| 6 |
else |
| 7 |
throw SF_Exception (GET_HOST_BLOCK (d), |
| |
``No more connections allowed to input terminal'') |
The disconnection function is called by the user.
| 1 |
 |
| 2 |
if then |
| 3 |
REMOVE (d, wire_destinations) |
| 4 |
SET_MODIFIED (GET_HOST_NETWORK (host_block), TRUE) |
| 5 |
REMOVE_INPUT (d, output) |
| 6 |
else |
| 7 |
throw SF_Exception (host_block, |
| |
``No such connection'') |
A generic data queue of pointers.
class SF_Queue
{
public:
SF_Queue ();
virtual ~SF_Queue ();
enqueue (const void *content);
const void * dequeue ();
inline bool is_empty () const;
inline const * get_head () const;
private:
SF_Queue_Node * head;
SF_Queue_Node * tail;
}
Add a new node to the end of the queue.
| 1 |
a = new SF_Queue_Node |
| 2 |
 |
| 3 |
 |
| 4 |
if head = NULL then |
| 5 |
 |
| 6 |
else |
| 7 |
 |
| 8 |
 |
Remove the first node of the queue.
| 1 |
if IS_EMPTY () then |
| 2 |
throw SF_Exception (NULL, ``Queue underflow'') |
| 3 |
else |
| 4 |
 |
| 5 |
 |
| 6 |
 |
| 7 |
delete t |
| 8 |
return a |
Return true if queue is empty, false otherwise.
The SF_Queue_Node class is a dumb class in the sense that it is
essentially a plain data structure.
class SF_Queue_Node
{
public:
SF_Queue_Node ();
SF_Queue_Node (const void *content);
virtual ~SF_Queue_Node ();
const void * content;
SF_Queue_Node * next;
private:
}
The base class of SF_Input_Terminal and
SF_Output_Terminal.
class SF_Terminal
{
public:
SF_Terminal (const char *name,
const SF_Block *host,
SF_Frequency sample_rate, // sample_rate and
double relative_sample_rate); // r_s_r are optional
virtual ~SF_Terminal ();
inline const char * get_name () const;
inline const SF_Block * get_host_block () const;
inline SF_Frequency get_sample_rate () const;
inline void set_sample_rate (SF_Frequency fs);
inline double get_relative_sample_rate () const;
inline void set_relative_sample_rate (double rfs);
private:
const char * name;
const SF_Block *host_block;
SF_Frequency sample_rate;
double relative_sample_rate; //relative to all the other terminals in a block
};
Adds an arbitrary number of input signals pointwise.
class SF_Adder : public SF_Block
{
public:
SF_Adder ();
virtual ~SF_Adder ();
virtual void finish ();
virtual void initialize ();
virtual void simulate ();
SF_Input_Terminal inputs[1];
SF_Output_Terminal outputs[1];
enum Input_Indices {X};
enum Output_Indices {Y};
};
This is the constructor.
| 1 |
SF_Block (POINTER (inputs), POINTER (outputs), 1, 1) |
| 2 |
inputs[0] = SF_Input_Terminal ("x", this, TRUE) |
| 3 |
outputs[0] = SF_Output_Terminal ("y", this) |
| 4 |
potential_source = FALSE |
| 5 |
potential_sink = FALSE |
This is the destructor.
This function calculates the sum of the inputs.
| 1 |
for each SF_Sample do |
| 2 |
s[i] = 0 |
| 3 |
for each SF_Frame do |
| 4 |
for each SF_Sample do |
| 5 |
![$\textit{y}.\textit{signal}[i] = \textit{y}.\textit{signal}[i] + s[i]$](img51.gif) |
The class throws mathematics exceptions on error conditions.
Filter input data with a
-order IIR band-pass filter.
class SF_Band_Pass_Filter : public SF_Block
{
public:
SF_Band_Pass_Filter ();
virtual ~SF_Band_Pass_Filter ();
virtual void finish ();
virtual void initialize ();
virtual void simulate ();
SF_Input_Terminal inputs[3];
SF_Output_Terminal outputs[1];
enum Input_Indices {X, F1, F2};
enum Output_Indices {Y};
private:
SF_Sample a0, a1, a2;
SF_Sample b0, b1, b2;
SF_Sample past_x[2], past_y[2];
};
This is the constructor. It is essentially identical to the constuctor of
SF_Adder (section 4.14), except for the following
aspects:
| multiple_inputs = FALSE |
| a0, a1, a2 = 0 |
| b0, b1, b2 = 0 |
| past_x[0, 1] = 0 |
| past_y[0, 1] = 0 |
This function filters the input signal.
| 1 |
 |
| 2 |
for each SF_Sample do |
| 3 |
Calculate a0, a1, a2, b0, b1 and b2 from f1, f2 and fs |
| |
according to Table 4.1 from []. |
| 4 |
![$t = \textit{b2} \times \textit{past\_x}[1] + \textit{b1} \times \textit{past\_x}[0] + \textit{b0} \times s[i]$](img55.gif) |
| |
![$- \textit{a2} \times \textit{past\_y}[1] - \textit{a1} \times \textit{past\_x}[0]$](img56.gif) |
| 5 |
t = t / a0 |
| 6 |
![$\textit{y}.\textit{signal}[i] = t$](img57.gif) |
| 7 |
past_y[1] = past_y[0] |
| 8 |
past_y[0] = t |
| 9 |
past_x[1] = past_x[0] |
| 10 |
past_x[0] = s[i] |
The class throws mathematics exceptions on error conditions.
Analoguous to 4.15 SF_Band_Pass_Filter.
class SF_Delay_Line : public SF_Block
{
public:
SF_Delay_Line (SF_Time memory);
virtual ~SF_Delay_Line ();
virtual void finish ();
virtual void initialize ();
virtual void simulate ();
inline void set_delay_memory (SF_Time memory);
inline SF_Time get_delay_memory () const;
SF_Input_Terminal inputs[2];
SF_Output_Terminal outputs[1];
enum Input_Indices {X, D};
enum Output_Indices {Y};
private:
SF_Sample interpolate_delay_line (SF_Time delay);
SF_Time delay_memory; // length of the delay line memory
unsigned int delay_memory_length; // length of the delay line memory in samples
SF_Sample * delay_line;
unsigned int current_index; // index to delay_line
SF_Sample fractional_delay_filter_state;
};
This is the constructor. It is essentially identical to the constuctor of
SF_Adder (section 4.14), except for the following
aspects:
| multiple_inputs = FALSE |
| delay_memory = memory |
| delay_memory_length = 0 |
| delay_line = NULL |
The pre-simulation initialization.
| 1 |
 |
| 2 |
 |
| 3 |
delay_memory_length = l |
| 4 |
delay_memory =  |
| 5 |
delay_line = new SF_Sample[l] |
| 6 |
if delay_line = NULL then |
| 7 |
throw SF_Exception (this, ``Out of memory'') |
| 8 |
for each SF_Sample do |
| 9 |
s[i] = 0 |
This function delays the input signal.
| 1 |
for each SF_Sample x do |
| 2 |
delay_line[current_index = s[i] |
| 3 |
current_index = MODULO (current_index + 1, delay_memory_length) |
| 4 |
for each SF_Sample y do |
| 5 |
if d[i] < 0 then |
| 6 |
throw SF_Exception (this, ``Negative delay'') |
| 7 |
if then |
| 8 |
throw SF_Exception (this, ``Delay exceeds maximum delay'') |
| 9 |
s[i] = INTERPOLATE_DELAY_LINE (d[i]) |
This function carries out the interpolation from the delay line (see
Dattorro [4]).
| 1 |
 |
| 2 |
 |
| 3 |
 |
| 4 |
f = a - i |
| 5 |
c = (1 - f)/(1 + f) |
| 6 |
 |
| |
 |
| 7 |
 |
| 8 |
 |
| 9 |
return v |
The class throws mathematics exceptions on error conditions.
class SF_File_Input : public SF_Block
{
public:
SF_File_Input ();
virtual ~SF_File_Input ();
virtual void finish ();
virtual void initialize ();
virtual void simulate ();
private:
};
class SF_File_Output : public SF_Block
{
public:
SF_File_Output ();
virtual ~SF_File_Output ();
virtual void finish ();
virtual void initialize ();
virtual void simulate ();
private:
};
Analoguous to 4.15 SF_Band_Pass_Filter.
Analoguous to 4.15 SF_Band_Pass_Filter.
class SF_Max_Min : public SF_Block
{
public:
SF_Max_Min ();
virtual ~SF_Max_Min ();
virtual void finish ();
virtual void initialize ();
virtual void simulate ();
private:
};
Analoguous to 4.14 SF_Adder.
class SF_Negation : public SF_Block
{
public:
SF_Negation ();
virtual ~SF_Negation ();
virtual void finish ();
virtual void initialize ();
virtual void simulate ();
private:
};
class SF_Noise_Generator : public SF_Block
{
public:
SF_Noise_Generator ();
virtual ~SF_Noise_Generator ();
virtual void finish ();
virtual void initialize ();
virtual void simulate ();
private:
};
class SF_Quantizer : public SF_Block
{
public:
SF_Quantizer ();
virtual ~SF_Quantizer ();
virtual void finish ();
virtual void initialize ();
virtual void simulate ();
private:
};
class SF_Reciprocal : public SF_Block
{
public:
SF_Reciprocal ();
virtual ~SF_Reciprocal ();
virtual void finish ();
virtual void initialize ();
virtual void simulate ();
private:
};
class SF_Sine_Generator : public SF_Block
{
public:
SF_Sine_Generator ();
virtual ~SF_Sine_Generator ();
virtual void finish ();
virtual void initialize ();
virtual void simulate ();
private:
};
class SF_Variable : public SF_Block
{
public:
SF_Variable ();
virtual ~SF_Variable ();
virtual void finish ();
virtual void initialize ();
virtual void simulate ();
private:
};
Next: OTHER SPECIFIC TECHNICAL ASPECTS
Up: Sonic Flow A Program
Previous: ARCHITECTURE DESCRIPTION
Sepp{nen Jarno
11/10/1998