• No results found

As stated in Section 5.5 on page 39, this system will be using the SI units of volts, amps and ohms when measuring voltages, currents and resistances respectively.

While this will make clear what units an answer should be in when performing calculations using equations such as Ohm’s law, it will mean that very small values will have to be manipulated; the current through a wire in an integrated circuit can be as little as one nano amp (0.000000001 amps).

In this system there will be a lot of calculations using these small values, especially in the solving of equations involving matrices as in MNA. Therefore to ensure that the requirement that the system should produce accurate results is met, a suitable type has to be used for storing these numbers. The type should provide enough storage space that will avoid the need to truncate values as this can lead to rounding errors through repeated use of such values in computations.

To reduce the likelihood of truncation as far as possible, the largest data type available could be used. In C, this is the long double, however not all platforms support this type. On those platforms that don’t support long double, its size is the same as that of the standard double type. This is an issue for the circuit analysis system since it is required to run on all the platforms supported by Pulsic.

The results returned by the system should be consistent whatever platform it is running on and so the long double type cannot be used for storing the electrical units. Therefore the system will use the double type as it generally provides sixty-four bits of storage space and is supported on all platforms.

6.3 Data Structures

For the system to be able to store pertinent information in a logical format that allows efficient access to the data, some data structures had to be designed.

Following is a discussion of the key decisions made in their design.

6.3.1 Matrices

Since the MNA algorithm is based on matrix manipulation, a data structure had to be designed to represent a matrix. The basic structure of a matrix resembles a two dimensional array, so it was obvious to conclude that the data structure should be a two dimensional array.

Each element of a matrix will be storing values relating to resistances, currents and voltages which, as stated in Section 6.2, are stored as type double. This means that the matrix data structure had to be a two dimensional array of type double.

However, since the size of the circuit design is not known until after the system has started running, the size of the array required is also not known, which precludes the use of the C language’s in-built array structures. The array has to be dynamically allocated using malloc.

The most obvious way to create a dynamic two dimensional array of doubles is to allocate an array of pointers to doubles, and then for each pointer in that array, allocate an array of doubles. This is shown in the following section of code:

¨ ¥

1 A = m a l l o c ( rows ∗ s i z e o f ( double ∗ ) ) ;

2 for ( i = 0 ; i <= s i z e ; i ++)

3 {

4 A[ i ] = m a l l o c ( columns ∗ s i z e o f ( double ) ) ;

5 }

§ ¦

If the two dimensional array is implemented in this way, an element of the array can be accessed in the normal way. For example accessing the element at the fifth row and ninth column would be:

¨ ¥

1 A [ 5 ] [ 9 ]

§ ¦

However, there is another way of creating a two dimensional array in which accessing the elements of the array is faster than the previous method. The implementation shown above relies on the language/compiler keeping track of the pointers so that it is possible to index to the right location by inserting the row and column in the square brackets. It is possible to control the indexing manually which is faster than having the language/compiler do it.

This implementation involves allocating a one dimensional piece of memory that is rows * columns in length as seen below:

¨ ¥

1 A = ( double ∗ ) m a l l o c ( rows ∗ columns ∗ s i z e o f ( double ) ) ;

§ ¦

Conceptually, this one dimensional piece of memory can be thought of as rows of a two dimensional array arranged end-to-end rather than on top of one another.

To index to the right element, a simple calculation like the following is required:

¨ ¥

1 A [ ( row ∗ c o l s ) + column ]

§ ¦

Simply multiply the desired row to index to by the number of columns per row will index to the right ’row’ of the array. Then adding the column required will index to the exact element. In this way a two dimensional array can be modelled as a one dimensional one and is actually how the language/compiler models it.

This second method is faster than allocating an array of pointers to arrays and letting the indexing being done automatically. This is because an array of pointers to arrays is likely to have 2 page misses, one looking for the row and then one for the column. Because of the construction of the array these are unlikely to be near to each other in memory which means cache prefetch will not help. This means two main memory fetches will occur and that can easily slow a 3GHz processor down to the speed of the memory bus or slower (as the memory bus speed is for bursts not for random access).

If you have a one dimensional array, although you need to do a multiply to find the right index this will be a single cycle in the ALU of the processor. You then only get one memory access, and because this will be arranged in a pattern that CPU’s are optimised for, you will find in most cases that the data has been prefetched by the CPU, hence the processor runs nearer its full speed.

Having chosen the second option for implementing the matrices some methods were created for accessing the data. These implement the indexing mechanism described above and also do some bounds checking to ensure that the element required is actually within the confines of the array. The following is an example routine that enters a value into the matrix:

¨ ¥

16 {

17 matrix−>mat [ ( row ∗ matrix−>c o l s ) + c o l ] = v a l u e ;

18 }

19 e l s e

20 {

21 p r i n t f ( ” F a t a l e r r o r − matrix i n d e x out o f bounds \n” ) ;

22 e x i t ( 1 ) ;

23 }

24 }

§ ¦

6.3.2 Circuit Elements

A ring and mesh circuit that has to be analysed will contain circuit elements including nodes, branches (modelled as resistors), current sources and voltage sources. Each one of these components requires a data structure that will be able to store the important information that is related to them.

First of all, it is important to be able to distinguish between the different nodes, current sources and so on, which is why each has been given a unique identification number. This is simply an integer which starts at one, and is incremented as each circuit element is read in by the system.

To be able to reflect in the data structures how the circuit is connected, the resistors connected to a node are stored. Since there can only be a maximum of four resistors connected to any one node, the resistor identification numbers are stored in a four element array. If there are fewer than four resistors connected to a node, zero is stored in the unused array elements to signify the lack of a resistor in that position.

A node may also be connected to one voltage source and one current source, so there are integer slots in the node data structure to store the identification numbers of these, or zero if one is not connected.

Since circuit analysis calculates the voltage at each node, there also has to be a slot for storing the voltage that is calculated, which as explained earlier in Section 6.2 on page 44 are stored as type double.

For a resistor, it is necessary to know the nodes that are connected to in order to describe the circuit properly. So in the resistor data structure there are integer slots that store the identification numbers of the two nodes at either end of the resistor. There are also slots of type double for storing the values of the resistance of the resistor and the current flowing through it.

The current source data structure and voltage source data structure are very similar. They store the identification number of the node the element is connected to and the current/voltage that they draw or supply to the circuit respectively.

Following is a section of code that illustrates the resistor data structure:

With each circuit element being stored in their own data structure, there needs to be a of way organising a collection of the data structures so that a individual element, a node for instance, can easily be located. This larger structure has to be dynamically allocated as the number of circuit elements that have to be stored will only be known after the system has started running.

One method of doing this would be to create a linked list of each type of data structure. This would require adding a pointer field to each data structure that would be set to point at the next structure in the list. Finding the desired element would then require a search down the list, checking the identification number of each element until the correct one is found. This search would mean a time penalty each time a piece of information is required about a node, resistor and so on.

To avoid this time penalty, a dynamically allocated one dimensional array is used instead to hold each type of data structure. The array for the node data structures is declared as follows:

Each node is stored in the element that corresponds to its identification number.

Therefore a node can be found in the array in one calculation by simply going to the array index of the id, thus removing the search time required by the linked list method.

Related documents