Back to Applet


Major Topics:
What have we done and why. (Our tasks and goals.)
Simulation of electrical circuits was always an interesting, useful and also necessary in both academy and industry. A lot of simulators exist, and a few of them, very famous, can give very precise results and are used in industry. The main purpose of this project wasn’t just to make another simulator, but to do something different. All existing simulators give numerical results and waveforms, but with all this information it still can be difficult to understand how the circuit really works.
In this project we have tried to visualize (animate) the emulation of electronic circuit. The user will not just see the numbers, but will actually see the node’s voltage growing up and down by moving of the node itself on the circuit. The changes of current are shown by ampermeter width, and some other elements’ states also can be seen by changing of the element itself, like FET in Cut-Off state looks broken. All that in addition to standard waveforms. The goal is to give the user a better feeling and understanding of what is going on, and how it actually works. User can change the values of the components and to see how it affects on circuit’s work, during the simulation without stopping it.
The inspiration to the project was article of Tom Hornak: "True Analog Circuit Design" in: "Analog Circuit Design" - Edited by Jim Williams (see bibliography).
As can be understood from previous paragraphs, our goal was to create user friendly and flexible multi-platform simulator with animated simulation. To achieve this goal we had placed to ourselves several tasks. First one is to create a user-friendly interface for circuits editor, which will work in most common browsers. Second one is to create algorithms for calculations, which will be fast enough to work in real-time together with animation. Last one is to make animation, from which the user will easily understand the circuit’s behavior. This animation should be fast enough to reflect the calculations in real-time and also to work in most common browsers. Circuits editor and calculations’ algorithms, as well as calculations’ and animation’s algorithms, should have common data structures for easy communication. The calculation mechanism and the animation should be able to communicate in real time during the simulation. The animation should be done at editor’s worksheet – to make user’s editing during the simulation easier.
To understand what we are talking about, here are few screenshots taken from simulation of CMOS NOT gate. Step voltage source is connected as an input to the gate. Pictures describe clock cycle of the voltage source. Nodes, which are shown as black circles, are moving up and down according to their voltages. More information about the simulation itself can be read below at user’s manual.


Here is another example of simulator. Step voltage source is used as an input to CMOS NOR circuit:




Here is another example of simulation. Step voltage source is used as an input to CMOS NAND circuit.




Why should one use our Simulator
One can use the simulator to understand how do complicated electronic circuits work. Circuits with few field effect transistors, which are hard for understanding for people who don’t usually works with electronics or for students who study the subject, can be understood in two minutes using our simulator. Differential Pair is a good example for such a circuit. One can build it in few seconds in our simulator. The next thing he would see by his own eyes – the voltages growing up and falling down, the current flow, its sizes and directions, the states of transistors, which are breaking and connecting again on the screen. And more and more and more…
Pupils in schools can easily understand physical phenomena such as capacitor charge and discharge by seeing the voltages’ and currents’ animation on the circuit. One can see the waveforms of the circuit, to run it step by step in any period time, to check the numeric values of all voltages and currents and more…
For all this, all the work and effort one should do is just a few seconds or minutes to create a circuit on the blank worksheet by simplest and easiest techniques, like “drag & drop”. No need for learning new application or new technology. No need for install of new software. No previous knowledge needed. Just open a simulator’s web page in any Java enabled browser such as Netscape Navigator or Internet Explorer read the simple instructions and you are on the way to the incredible animated world of electronics.
Here is example of a differential pair (two screenshots)


Here is example of Operation Amplifier based inverter:

Here is example of charging and discharging of capacitor:


Advantages and disadvantages of our simulator
As one can see, our animated simulator is full of advantages. Of course, it has the disadvantages as well. We’ll try to compare it with classical simulator (like Spice) to find all it’s advantages and disadvantages.
Our animated simulator doesn’t require any purchase, download or install, just as any special requirements on hardware, operating system or additional software, like any other simulators do. Our simulator does not require any previous knowledge in electronics, computers or Internet to get started, like any other simulators do. Our simulator is portable and can be run anywhere and anytime. Our simulator helps to understand how the circuit works to someone who does not have background in the subject and does not require from the user to understand the circuit and to know the theory just to get started. Our simulator uses new visual techniques of animation for circuits’ simulation, to achieve better understanding by visual comprehension.
On the other hand, our simulator does not include as much electrical components as other do, but we give easy and simple way to add new components to someone who will want to do so. Our simulator use simple calculations technique, which makes results not very accurate as in other simulators and also dependable on iterations’ time steps. In some circuits, in our simulator, it is user’s task to choose correct time step to get best performance. Our simulator, in its default way, limits the user by the size of circuit, in spite of the existence of the possibility to change worksheet size in html source.
Here is example of charging and discharging of capacitor:

Block Diagram


Flow chart

The relaxation method.
As has been shown in previous section, the main purpose of this project was not to make a very precise simulator, but to add graphical visualization to simulation, thing that requires speed and flexibility in calculations. The method that was chosen for this project is relaxation.
The main speciality of this method is that while calculating voltage for one node – it does not refer to another nodes in the circuit. In each step (iteration) all nodes are recalculated. For each such iteration Kirchoff Current Law (KCL) is used. While calculating new voltage for each node using KCL, previous values of voltages of other nodes, which have not been calculated yet, are being used. The initial voltage values of all nodes are set to zero. If the time step, which is set by user, is small enough, the results can be very precise.
The applet’s abilities.
The applet has the following abilities: User friendly circuit’s editor, which includes smart drag and drop facility for easier construction of the circuits. The components, which are currently available, are resistors, capacitors, inductors, NMOS and PMOS transistors, DC, AC and Square voltage sources, current sources, operation amplifiers, diodes and switches. Auxiliary elements are animated nodes, probes and ampermeters. All parameters of those components and also the time steps of the simulation are user defined and can be changed during simulation. Additional options, like toggle waveforms or add pull down resistors and coupled capacitors, load circuits from text file or save it, are also available. The applet is also built in a way, that advanced user, who has access to the source code, will be able to add a new component. It can be done by adding of a new class and describing in it component’s properties, in a very short time, without need to change anything at all in entire applet, even without need to recompile it. The way to do it will be described below. After the circuit was built, the parameters were set and the simulation was started – the nodes of the circuit, or the points which were marked as nodes by user, start moving according to the voltage changes in the circuit. Elements’ states are shown on the circuit, ampermeters are changing their shape according to current and waveforms’ window popup automatically. During the simulation, timer shows the time progress in both simulation modes: step mode and continuous mode. The modes can be changed during the simulation without restarting.
How does it works, and how to use it. (Users manual.)
The applet’s screen contains two main components and additional control tools. First one, on the top of the screen, is components’ toolbar. This toolbar contains all existing components, including nodes probes and ampermeters, which are used for two purposes: first one – as wire node and second one – as animated part of the circuit. The second main component is the worksheet – matrix on which user can compose the electronic circuit.
To place electrical component on the matrix user should simply drag it from the toolbar and drop it on one of the cells of the matrix.

By pressing right mouse button on the component (in MS and X Windows or long press in MAC) user gets additional options. He can remove the component from the worksheet, he can rotate it or he can change its properties. Changing properties can be also done by double click on the element.
By choosing properties’ label, user gets properties’ dialog, which is different from one electrical component to another. For example in resistor’s properties’ dialog only resistance can be changed, while in Square - Step voltage source DC level, amplitude, period time and pulse percentage can be changed. It works on both - Toolbar and Matrix. While changing properties on Toolbar, all new elements of same type will have same initial properties.

From right mouse button menu few other options are available, like dropping nodes or probes on the wires, or removing entire wire. Additional options are available during the simulation.
After placing all components on the matrix and rotating them if necessary – they can be connected by wires. Connecting wires is very simple – just by dragging mouse from one electrical contact to another. The applet choose by itself the shortest available way to put wires (using BFS algorithm). To recognize which part of the electrical component is a contact and can be connected – the contacts change their color to red, while mouse pass over them.
Nodes can be dropped on the wires, in this case wire remains connected and two additional connections can be done. To remove wires from the worksheet – to ways can be used: as for other components (from menu, by pressing right mouse button) or by “remove wire” from same menu. By dropping one component on another the old one is being removed and the new one is placed in the same direction as old one (including dropping components on wires).

When the simulation starts – heuristics choose best time step for it. User can change this value during all simulation.
It’s necessary that all contacts will be connected, and that at least one voltage source or ground will be placed on circuit to start simulation. Otherwise the simulation won’t start and warning message will pop up.

After the circuit has been composed and all properties’ values of its components has been set the simulation can begin. There are two modes of simulation: step by step simulation or continuous run. The modes can be switched during the simulation. By pressing on make step button – single iteration of calculations will be done. Voltages of all nodes will be recalculated and all animated elements will be repainted according to their new values. During this mode time step value can be changed, same as all components’ properties’ parameters, and the simulation can be continued without restarting.
By pressing right mouse button on components during the simulation – usual menu appear with additional available labels.
By choosing “Info” label user can see the voltages of all electrical contacts of the component he had choose (including wires and nodes) and additional element’s specific information, usually according to it’s state.

To view waveforms one should place probes, which behave same as simple node, but is colored and have wave of same color in waveform window.

In waveforms’ window, which will popup on the beginning of simulation if one or more probes were placed, one can change the resolutions in following ways: X scale can be changed by moving “Pixels per second” slider and simple resizing of waveforms’ window in Y direction will change Y scale. Waveforms’ window can be hidden by “Hide waveforms” button and restored by “Show waveforms” button. When simulation has stopped or paused – waveforms are available for scrolling.

Any removal, adding or changing direction of any component (including wires) – will restart the simulation (includes adding, removal or change of pull down resistors and coupled capacitors). By pressing on start/continue button the automatic simulation will begin. The iterations will run automatically, according to time step value. By pressing stop/pause button – the simulation will return to previous, step mode. To reset (restart) simulation – one can press on “reset” button. Drag and drop facilities on the matrix are disabled during the simulation. To use it – one should reset the simulation.
Save/Load options. By pressing “Save/Load” button – new editor window will popup. If Matrix contained a circuit – it will appear in the editor window in text format. It can be copied and saved for later use. To load it, one should just paste the saved circuit into this window and choose “Update matrix” option from menu.

Project comes with number of predefined circuits, which can be loaded by pressing “>>” button, next to “Save/Load” button and cit by it’s name. One can add new predefined circuit (if he has access to the applet directory) by putting new “.ckt” file into “circuits” directory and adding it’s name into “index.html” as applet parameter.
“Clear” button can be used to clear all the components from the matrix.
Applet itself has following parameters, which are defined in “index.html” and can be changed (if one has access to applet’s directory): MatrixSize – number of cells in one column or row. Must be an integer. Elements – list of elements, which are available in Toolbar. Predefines – list of predefine circuits, which are available in load predefines menu (“>>”).
Program description, its major concepts and main algorithms.
Calculations are done in the following way: For the connected circuit the graph is built. The graph is built by following the wires from one electrical contact to another and as a result we get the graph of nodes. For each node, after the circuit is composed, we add pull down resistor or/and coupled capacitor if specified by user, which is connected to the ground by his second contact. Class Vertex (in file Vertex.java – see sources) implements nodes. It includes following information: list of electrical contacts, which are connected to it, its current voltage, number in the list, information if it should be evaluated during simulation or if it is connected to some constant voltage element and some other functions. Few nodes (vertices) can be connected during the simulation and to behave like same one (in case of switch for example). During the simulation, in any iteration, following things are done: for each node (Vertex) the KCL equation is created. In any such equation – the variable is the voltage of calculated node. During the simulation numerical results are also available for user by right mouse button’s menu (“Info” label). In case of step by step simulation – each click on make step button runs iteration. In case of continuous simulation – separate thread is created, which manages the iterations.
Breadth-first search (BFS)
Breadth-first search is one of simplest and fastest algorithms for searching a graph. Given a graph and distinguished source vertex, breadth-first search systematically explores the edges of the graph to "discover" every vertex that is reachable from the source. It computes the distance (fewest number of edges) from the source to all such reachable vertices. For any vertex reachable from the source the algorithm builds a "shortest path", a path containing fewest number of edges from the source to this vertex.
In our application BFS is used, when the user wants to connect some parts of electrical circuit built on the working matrix. For user it's just to pull "with mouse" "wire" from node or one of contacts of electrical components (which is highlighted on mouse over) to another one and release the mouse. What's done in program: the matrix is represented as an undirected graph, matrix' cells are vertices of the graph and free paths between adjacent cells are edges. The BFS is run in order to find path (if exists) between two electrical contacts chosen by user. In other words, to connect chosen contacts with "wire". The BFS algorithm is most efficient way to achieve this goal.
Double buffering technique
The flashing is a common problem with animation (and occasionally with static graphics).
The flashing effect is the result of two facts:
1. By default, the background of the animation is cleared (its whole area redrawn in the background color) before the paint() method is called.
2. The computation in the previous example's paint() method is complex enough that it takes longer to compute and draw each frame of animation than the video screen's refresh rate. As a result, the first part of the frame is drawn on one video refresh pass, and the rest of the frame is drawn on the next (or even the pass after that). The result is that although the first part of the frame is animated smoothly (usually), you can see a break between the first and second parts, since the second part is blank until the second pass.
We use two techniques to eliminate flashing: overriding the update() method and implementing double buffering:
1. Overriding the update() Method
To eliminate flashing, whether or not we use double buffering, we override the update() method. The reason lies in the way the AWT requests that a Component (such as an Applet, Canvas, or Frame) repaint itself. The AWT requests a repaint by calling the Component's update() method. The default implementation of update() clears the Component's background before calling paint(). Because eliminating flashing requires that we eliminate all unnecessary drawing, our first step is always to override update() so that it clears the entire background only when necessary. When moving drawing code from the paint() method to update(), we might need to modify the drawing code so that it doesn't depend on the background being cleared.
2. Implementing Double Buffering
Double buffering involves performing multiple graphics operations on an undisplayed graphics buffer, and then displaying the resulting image onscreen. Double buffering prevents incomplete images from being drawn to the screen. We use double buffering to avoid this crawling effect by forcing the entire frame to be drawn at once. To implement double buffering, we create an undisplayed buffer (often called a backbuffer or offscreen buffer), draw to it, and then display the resulting image onscreen.
Tracking Image Loading
We might encounter two things about the image animation in the program:
1. While the images are loading, the program displays some images partially and others not at all.
2. Loading the images takes a long time. The problem of displaying partial images is easy to fix, using the MediaTracker class. MediaTracker also can decrease the amount of time that loading images takes. The MediaTracker class lets us easily download data for a group of images and find out when the images are fully loaded. Ordinarily, an image's data isn't downloaded until the image is drawn for the first time. To load data synchronously (waiting for the data to arrive), we use waitForAll() method. The MediaTracker methods that load data use several background threads to download the data, resulting in increased speed.
Easy way to extend applet abilities – adding new components.
As have been told before, the source code of the applet was written to make it simpler and easy for future updates. The calculation mechanism can be used separately with another user interfaces. One of the main advances, which this code includes, is the possibility to add new components, just by describing their properties in standard format, without changing the calculation mechanism. Because of current limitations of user interface, which has matrix with square cells (four sides) – new components with up to four electrical contacts only can be added. To add new component, user should add new class (in new file), which should inherit one of existing abstract classes of components’ classes’ hierarchy. Currently, for inheriting, few classes are available: Element, WireElement, PowerSourceElement, VoltageSource, VoltageDependElement, ConstVoltageElement.
Elements, which are not power sources and not just wires – have to inherit from class Element. Elements, which have zero conduction, have to inherit from class WireElement or to use connection techniques like Switch and Ampermeter do. Elements, which are independent voltage sources, have to inherit from class ConstVoltageElement, dependent ones – from VoltageDependElement. Elements, which are power sources, but not voltage sources, have to inherit from class PowerSourceElement. Elements, which inherit from class Element, have to override few following functions:
public Polynom getCurrent(int dir, double timeStep) – this function gets two arguments: first is number of electrical contact of element, for which function should return polynom coefficients of current via this contact.Here is example of getCurrent function of Resistor with explanations:
function returns current via resistor, which is i = V/R
i = Vnew/R - VofSecondContact/R (Vnew is variable)
public Polynom getCurrent(int dir, double timeStep) {
Polynom p = new Polynom(); This line creates new polynom
Next line is a check for existing contacts, resistor has, by definition, two electrical contacts (NORTH and SOUTH), so in case that function is running for other contacts – it should return zero coefficients.
if (dir == WEST || dir == EAST) return p;
For more simplicity to user – all values in applet defined by two numbers: value and its order. Significance of orders are following: "p", "n", "u", "m", " ", "k", "M", "G" equals to numbers 0 to 7
Function valueOf – combines value and order together and returns numeric value.
double R = valueOf(resistance, order);
By formula current is equal to voltage on the resistor divided by resistance. Direction of current in all calculation is to the node for which we are calculating it. In this case current equal to the difference between voltage on the electrical contact of the resistor which is connected to the node, for which calculations are done now and voltage on the second electrical contact of the resistor. According to the formula we get: (“Unknown voltage” – “Voltage of second contact” ) / “Resistance”.
“Unknown voltage” is a variable, X, so we get X/R – and the coefficient of X (first coefficient of polynom) is 1/R. By array contVertex, we can access all nodes, which are connected to specified electrical element, in this case – resistor. The opposite electrical contact of the resistor (its number in array) can be calculated by (dir+2)%4, where dir is number of node, given as argument to function, according to resistor’s definition in its constructor.
p.setCoef(1, 1/R);
p.setCoef(0, -1*contVertex[(dir+2)%4].voltage/R);
lastCurrent[dir] = p;
return p;
}
New polynom is saved in lastCurrent array, for future use by getLastCurrent function. Different examples of getCurrent functions can be seen in applet source code. In this case, function argument timeStep – wasn’t used, but there are some electrical elements, which use it. (For example capacitor.)
Second function is: public String paramString(), and here is simple example.
public String paramString() {
return new String("K=" + k + "," + korder + ";Vt=" + Vt + "," + vtorder);
}
This function is used for Load/Save options, so it should return all element’s properties, to be able to restore the element by them in the future.
Function which restores the element is public void parseString(String values).
Here’s example:
public void parseString(String values) {
String vals[] = parse(values, ";");
try {
k = getValue(vals[0]);
korder = getOrder(vals[0]);
Vt = getValue(vals[1]);
vtorder = getOrder(vals[1]);
} catch (Exception e) {}
}
Third function is: public Object[] getProperties(). This function returns element properties for properties dialog. There are 6 objects for each parameter:
1st – Name of parameter
2nd – Value
3rd – minimal valid order
4th – maximal valid order
5th – current order
6th – units
The number of objects that should be created should be – number of properties of electrical element multiplied by six. Here is the example of resistor, which has only one propery.
public Object[] getProperties() {
Object[] props = new Object[6];
props[0] = new String("Resistance"); // Resistance
props[1] = new Double(resistance).toString();
props[2] = new Integer(validOrderLow);
props[3] = new Integer(validOrderHigh);
props[4] = new String(ORDERS[order]);
props[5] = new String("Ohm");
return props;
}
Forth function is public void setProperties(String[] props). This function sets properties of element by properties dialog. The function gets as argument array of strings, where for each property (parameter) of element there are two strings.
1st - Value
2nd - its order
Here is example for resistor, which has only one parameter.
public void setProperties(String[] props) {
resistance = Double.valueOf(props[0]).doubleValue(); // Resistance
for (int i = 0; i < 8; i++)
if (props[1].equals(ORDERS[i]))
order = i;
}
Fifth function is public boolean checkVoltage(int dir, double timeStep, double newVoltage). This function is used to check the result of calculation, when more than one result obtained. For example, it can be used in case of transistors, when we get quadratic equation. Arguments are same as for getCurrent() function, with additional argument newVoltage – which is result of calculations. The function returns true or false – for this value.
Another function - public String[] getInfo(int angle)
It returns information for this element, such as voltage, current etc. Argument angle - angle of current graphical representation for the element. Function returns array of Strings with information.
Function public String getTip(int type) returns tool tip of the element, while argument type means if it’s equal to 0 – element is in Toolbar and 1 – element on Matrix.
Function public void connect() – runs once, after the graph of the circuit was created, before the simulation begins. In case of Ampermeter – it creates short circuit between to it’s vertices, action that should be done once, after the graph was built.
Function protected void initImageNames() should returns array of Strings with names of all images that will be used by element and should be loaded.
For example – Switch:
public void initImageNames() {
imageNames = new String[2];
imageNames[0] = "library/" + getClass().getName() + ".gif";
imageNames[1] = "library/" + getClass().getName() + "1.gif";
}
In case of animated element – few pictures can be used. In this case few more functions should be overridden:
Function public Image getImage(int angle, double time) returns elements image accordingly to element’s state. Arguments: angle – element’s angle, time – current time. Function public Image getImage(int angle) – same, but without time.
Example of Switch’s function:
public Image getImage(int angle, double time) {
int D, S, G;
double Vgs, Vds;
if (contVertex[NORTH] == null || contVertex[SOUTH] == null || contVertex[WEST] == null)
return baseImage[0][angle/90];
double Vt = valueOf(this.Vt, vtorder);
G = WEST;
// checking for Drain and Source
if ( contVertex[NORTH].voltage > contVertex[SOUTH].voltage ) {
D = NORTH;
S = SOUTH;
} else {
D = SOUTH;
S = NORTH;
}
Vgs = contVertex[G].voltage - contVertex[S].voltage;
Vds = contVertex[D].voltage - contVertex[S].voltage;
if ( Vgs < Vt ) { // Off
return baseImage[0][angle/90];
}
return baseImage[1][angle/90];
}
Function public void paint(Graphics g, int angle, Dimension size, boolean isSimulating, boolean animated) – paints the element. Arguments as follow:
g - the graphic context
angle - how much the element is rotated
size - size of element on the screen
isSimulating - is the applet simulating now
animated - is the element should be animated or should be static like in Toolbar
Beside this functions constructor should set information about electrical contacts of element, for example constructor of resistor:
Resistor() {
contacts[NORTH] = true; // set valid contacts
contacts[SOUTH] = true;
}
Second constructor should take as a parameter an element of the same type (copy constructor)
public Resistor(Resistor e) {
this();
resistance = e.resistance; // Resistance
order = e.order;
baseImage = e.baseImage;
}
Resistor has two valid contacts, one on the north and one on the south.
Class itself, in case of resistor, inherit from Element, and includes other information about resistor itself, information which is depends on the electrical element and is up to user. Here is example of resistor:
public class Resistor extends Element {
double resistance = 1; // Resistance
int order = 5; // it's order (kohm)
int validOrderLow = 4; // min. valid order (ohm)
int validOrderHigh = 6; // max. valid order (Mohm)
…
All elements, which are power sources, and inherit from PowerSourceElement, or from ConstVoltageElement if they are voltage sources should override two extra functions:
abstract double getMaxVoltage() , which should return maximal voltage of this element (used for drawing to set maximum) and abstract double getMinVoltage(), which should return minimal voltage of this element (used for drawing to set minimum).
All elements, which inherit from VoltageSource, should override additional function:
public double getVoltage(double time, double timeStep), which should return element’s voltage according to given time and time step.
After all described changes were done, following things required to accomplish update.
Appropriate picture, with size 40x40 256c in gif format should be added, named ClassName.gif. In case of resistor: Resistor.gif In case of animated element – few pictures can be added, with any names, functions initImageNames() and getImage(int angle, double time) should be overrided.
New class should be compiled and added into jar archive together with image files.
Bibliography: