update to schematic tool
This commit is contained in:
88
js/cktsim.js
88
js/cktsim.js
@@ -97,9 +97,11 @@ cktsim = (function() {
|
||||
// load circuit from JSON netlist (see schematic.js)
|
||||
Circuit.prototype.load_netlist = function(netlist) {
|
||||
// set up mapping for ground node always called '0' in JSON netlist
|
||||
this.node_map['0'] = this.gnd_node();
|
||||
var gnd_label = '0';
|
||||
this.node_map[gnd_label] = this.gnd_node();
|
||||
|
||||
// process each component in the JSON netlist (see schematic.js for format)
|
||||
var found_ground = false;
|
||||
for (var i = netlist.length - 1; i >= 0; --i) {
|
||||
var component = netlist[i];
|
||||
var type = component[0];
|
||||
@@ -118,6 +120,7 @@ cktsim = (function() {
|
||||
var connections = component[3];
|
||||
for (var j = connections.length - 1; j >= 0; --j) {
|
||||
var node = connections[j];
|
||||
if(node == gnd_label) found_ground = true;
|
||||
var index = this.node_map[node];
|
||||
if (index == undefined) index = this.node(node,T_VOLTAGE);
|
||||
connections[j] = index;
|
||||
@@ -137,12 +140,18 @@ cktsim = (function() {
|
||||
else if (type == 'i') // current source
|
||||
this.i(connections[0],connections[1],properties['value'],name);
|
||||
else if (type == 'o') // op amp
|
||||
this.opamp(connections[0],connections[1],connections[2],properties['A'],name);
|
||||
this.opamp(connections[0],connections[1],connections[2],connections[3],properties['A'],name);
|
||||
else if (type == 'n') // n fet
|
||||
this.n(connections[0],connections[1],connections[2],properties['W/L'],name);
|
||||
else if (type == 'p') // p fet
|
||||
this.p(connections[0],connections[1],connections[2],properties['W/L'],name);
|
||||
}
|
||||
if(found_ground == false) { // No ground on schematic
|
||||
alert('Please make at least one connection to ground (inverted T symbol)');
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
// if converges: updates this.solution, this.soln_max, returns iter count
|
||||
@@ -187,6 +196,8 @@ cktsim = (function() {
|
||||
|
||||
// DC analysis
|
||||
Circuit.prototype.dc = function() {
|
||||
|
||||
// Allocation matrices for linear part, etc.
|
||||
this.finalize();
|
||||
|
||||
// Load up the linear part.
|
||||
@@ -624,6 +635,17 @@ cktsim = (function() {
|
||||
return this.add_device(d, name);
|
||||
}
|
||||
|
||||
Circuit.prototype.opamp = function(np,nn,no,ng,A,name) {
|
||||
// try to convert string value into numeric value, barf if we can't
|
||||
if ((typeof A) == 'string') {
|
||||
ratio = parse_number(A,undefined);
|
||||
if (A === undefined) return undefined;
|
||||
}
|
||||
var branch = this.node(undefined,T_CURRENT);
|
||||
var d = new Opamp(np,nn,no,ng,branch,A,name);
|
||||
return this.add_device(d, name);
|
||||
}
|
||||
|
||||
Circuit.prototype.n = function(d,g,s, ratio, name) {
|
||||
// try to convert string value into numeric value, barf if we can't
|
||||
if ((typeof ratio) == 'string') {
|
||||
@@ -1090,6 +1112,15 @@ cktsim = (function() {
|
||||
src.value = function(t) { return v; } // closure
|
||||
}
|
||||
|
||||
// post-processing for impulse sources
|
||||
// impulse(height,width)
|
||||
else if (src.fun == 'impulse') {
|
||||
var h = arg_value(src.args,0,1); // default height: 1
|
||||
var w = Math.abs(arg_value(src.args,2,1e-9)); // default width: 1ns
|
||||
src.args = [h,w]; // remember any defaulted values
|
||||
pwl_source(src,[0,0,w/2,h,w,0],false);
|
||||
}
|
||||
|
||||
// post-processing for step sources
|
||||
// step(v_init,v_plateau,t_delay,t_rise)
|
||||
else if (src.fun == 'step') {
|
||||
@@ -1263,8 +1294,8 @@ cktsim = (function() {
|
||||
// MNA stamp for independent voltage source
|
||||
ckt.add_to_Gl(this.branch,this.npos,1.0);
|
||||
ckt.add_to_Gl(this.branch,this.nneg,-1.0);
|
||||
ckt.add_to_Gl(this.npos,this.branch,1.0);
|
||||
ckt.add_to_Gl(this.nneg,this.branch,-1.0);
|
||||
ckt.add_to_Gl(this.npos,this.branch,-1.0);
|
||||
ckt.add_to_Gl(this.nneg,this.branch,1.0);
|
||||
}
|
||||
|
||||
// Source voltage added to b.
|
||||
@@ -1448,9 +1479,9 @@ cktsim = (function() {
|
||||
// MNA stamp for inductor linear part
|
||||
// L on diag of C because L di/dt = v(n1) - v(n2)
|
||||
ckt.add_to_Gl(this.n1,this.branch,1);
|
||||
ckt.add_to_Gl(this.branch,this.n1,1);
|
||||
ckt.add_to_Gl(this.branch,this.n1,-1);
|
||||
ckt.add_to_Gl(this.n2,this.branch,-1);
|
||||
ckt.add_to_Gl(this.branch,this.n2,-1);
|
||||
ckt.add_to_Gl(this.branch,this.n2,1);
|
||||
ckt.add_to_C(this.branch,this.branch,this.value)
|
||||
}
|
||||
|
||||
@@ -1464,6 +1495,51 @@ cktsim = (function() {
|
||||
Inductor.prototype.load_tran = function(ckt) {
|
||||
}
|
||||
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Simple Voltage-Controlled Voltage Source Op Amp model
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
function Opamp(np,nn,no,ng,branch,A,name) {
|
||||
Device.call(this);
|
||||
this.np = np;
|
||||
this.nn = nn;
|
||||
this.no = no;
|
||||
this.ng = ng;
|
||||
this.branch = branch;
|
||||
this.gain = A;
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
Opamp.prototype = new Device();
|
||||
Opamp.prototype.constructor = Opamp;
|
||||
|
||||
Opamp.prototype.load_linear = function(ckt) {
|
||||
// MNA stamp for VCVS: 1/A(v(no) - v(ng)) - (v(np)-v(nn))) = 0.
|
||||
var invA = 1.0/this.gain;
|
||||
ckt.add_to_Gl(this.no,this.branch,1);
|
||||
ckt.add_to_Gl(this.ng,this.branch,-1);
|
||||
ckt.add_to_Gl(this.branch,this.no,-invA);
|
||||
ckt.add_to_Gl(this.branch,this.ng,invA);
|
||||
ckt.add_to_Gl(this.branch,this.np,1);
|
||||
ckt.add_to_Gl(this.branch,this.nn,-1);
|
||||
}
|
||||
|
||||
Opamp.prototype.load_dc = function(ckt,soln,rhs) {
|
||||
// Op-amp is linear.
|
||||
}
|
||||
|
||||
Opamp.prototype.load_ac = function(ckt) {
|
||||
}
|
||||
|
||||
Opamp.prototype.load_tran = function(ckt) {
|
||||
}
|
||||
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Simplified MOS FET with no bulk connection and no body effect.
|
||||
|
||||
@@ -634,9 +634,10 @@ schematic = (function() {
|
||||
|
||||
// create a circuit from the netlist
|
||||
var ckt = new cktsim.Circuit();
|
||||
ckt.load_netlist(netlist);
|
||||
|
||||
return ckt;
|
||||
if (ckt.load_netlist(netlist))
|
||||
return ckt;
|
||||
else
|
||||
return null;
|
||||
}
|
||||
|
||||
Schematic.prototype.dc_analysis = function() {
|
||||
@@ -645,6 +646,7 @@ schematic = (function() {
|
||||
this.redraw_background();
|
||||
|
||||
var ckt = this.extract_circuit();
|
||||
if (ckt === null) return;
|
||||
|
||||
// run the analysis
|
||||
this.operating_point = ckt.dc();
|
||||
@@ -712,6 +714,7 @@ schematic = (function() {
|
||||
Schematic.prototype.ac_analysis = function(npts,fstart,fstop,ac_source_name) {
|
||||
// run the analysis
|
||||
var ckt = this.extract_circuit();
|
||||
if (ckt === null) return;
|
||||
var results = ckt.ac(npts,fstart,fstop,ac_source_name);
|
||||
|
||||
// save a copy of the results for submission
|
||||
@@ -731,11 +734,28 @@ schematic = (function() {
|
||||
var y_values = []; // list of [color, result_array]
|
||||
var probes = this.find_probes();
|
||||
|
||||
var probe_maxv = [];
|
||||
var probe_color = [];
|
||||
|
||||
// Check for proble with near zero transfer function and warn
|
||||
for (var i = probes.length - 1; i >= 0; --i) {
|
||||
probe_color[i] = probes[i][0];
|
||||
var label = probes[i][1];
|
||||
var v = results[label];
|
||||
probe_maxv[i] = array_max(v); // magnitudes always > 0
|
||||
}
|
||||
var all_max = array_max(probe_maxv);
|
||||
for (var i = probes.length - 1; i >= 0; --i) {
|
||||
if ((probe_maxv[i] / all_max) < 1.0e-10) {
|
||||
alert('Near zero ac response, remove ' + probe_color[i] + ' probe');
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
for (var i = probes.length - 1; i >= 0; --i) {
|
||||
var color = probes[i][0];
|
||||
var label = probes[i][1];
|
||||
var v = results[label];
|
||||
|
||||
// convert values into dB relative to source amplitude
|
||||
var v_max = 1;
|
||||
for (var j = v.length - 1; j >= 0; --j)
|
||||
@@ -774,6 +794,8 @@ schematic = (function() {
|
||||
this.dialog('Transient Analysis',content,function(content) {
|
||||
var sch = content.sch;
|
||||
var ckt = sch.extract_circuit();
|
||||
if (ckt === null) return;
|
||||
|
||||
|
||||
// retrieve parameters, remember for next time
|
||||
sch.tran_npts = content.fields[npts_lbl].value;
|
||||
@@ -1943,25 +1965,27 @@ schematic = (function() {
|
||||
var x1 = (index == 0) ? x_values[0] : x_values[index-1];
|
||||
var x2 = x_values[index];
|
||||
|
||||
// for each plot, interpolate and output value at intersection with marker
|
||||
c.textAlign = 'left';
|
||||
var tx = graph.left_margin + 4;
|
||||
var ty = graph.top_margin;
|
||||
for (var plot = 0; plot < graph.y_values.length; plot++) {
|
||||
var values = graph.y_values[plot][1];
|
||||
if (x2 != undefined) {
|
||||
// for each plot, interpolate and output value at intersection with marker
|
||||
c.textAlign = 'left';
|
||||
var tx = graph.left_margin + 4;
|
||||
var ty = graph.top_margin;
|
||||
for (var plot = 0; plot < graph.y_values.length; plot++) {
|
||||
var values = graph.y_values[plot][1];
|
||||
|
||||
// interpolate signal value at graph_x using values[index-1] and values[index]
|
||||
var y1 = (index == 0) ? values[0] : values[index-1];
|
||||
var y2 = values[index];
|
||||
var y = y1;
|
||||
if (graph_x != x1) y += (graph_x - x1)*(y2 - y1)/(x2 - x1);
|
||||
// interpolate signal value at graph_x using values[index-1] and values[index]
|
||||
var y1 = (index == 0) ? values[0] : values[index-1];
|
||||
var y2 = values[index];
|
||||
var y = y1;
|
||||
if (graph_x != x1) y += (graph_x - x1)*(y2 - y1)/(x2 - x1);
|
||||
|
||||
// annotate plot with value of signal at marker
|
||||
c.fillStyle = element_style;
|
||||
c.fillText('\u2588\u2588\u2588\u2588\u2588',tx-3,ty);
|
||||
c.fillStyle = probe_colors_rgb[graph.y_values[plot][0]];
|
||||
c.fillText(engineering_notation(y,3,false),tx,ty);
|
||||
ty += 14;
|
||||
// annotate plot with value of signal at marker
|
||||
c.fillStyle = element_style;
|
||||
c.fillText('\u2588\u2588\u2588\u2588\u2588',tx-3,ty);
|
||||
c.fillStyle = probe_colors_rgb[graph.y_values[plot][0]];
|
||||
c.fillText(engineering_notation(y,3,false),tx,ty);
|
||||
ty += 14;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3086,7 +3110,8 @@ schematic = (function() {
|
||||
this.add_connection(0,0); // +
|
||||
this.add_connection(0,16); // -
|
||||
this.add_connection(48,8); // output
|
||||
this.bounding_box = [0,-8,48,24];
|
||||
this.add_connection(24,32); // ground
|
||||
this.bounding_box = [0,-8,48,32];
|
||||
this.update_coords();
|
||||
}
|
||||
OpAmp.prototype = new Component();
|
||||
@@ -3104,7 +3129,9 @@ schematic = (function() {
|
||||
// inputs and output
|
||||
this.draw_line(c,0,0,8,0);
|
||||
this.draw_line(c,0,16,8,16);
|
||||
this.draw_text(c,'gnd',37,18,property_size);
|
||||
this.draw_line(c,40,8,48,8);
|
||||
this.draw_line(c,24,16,24,32);
|
||||
// + and -
|
||||
this.draw_line(c,10,0,16,0);
|
||||
this.draw_line(c,13,-3,13,3);
|
||||
@@ -3176,6 +3203,9 @@ schematic = (function() {
|
||||
source_functions = {
|
||||
'dc': ['DC value'],
|
||||
|
||||
'impulse': ['Height',
|
||||
'Width (secs)'],
|
||||
|
||||
'step': ['Initial value',
|
||||
'Plateau value',
|
||||
'Delay until step (secs)',
|
||||
|
||||
Reference in New Issue
Block a user