From 6f55bd55e2ca86dac061b40ea6568bf6845c84df Mon Sep 17 00:00:00 2001 From: cjt Date: Sat, 4 Feb 2012 10:26:47 -0500 Subject: [PATCH 1/9] update to schematic tool --- js/cktsim.js | 88 +++++++++++++++++++++++++++++++++++++++++++++---- js/schematic.js | 74 ++++++++++++++++++++++++++++------------- 2 files changed, 134 insertions(+), 28 deletions(-) diff --git a/js/cktsim.js b/js/cktsim.js index 9a9fbe351f..cbbcb21a1d 100755 --- a/js/cktsim.js +++ b/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. diff --git a/js/schematic.js b/js/schematic.js index 15997a4988..af694040c6 100644 --- a/js/schematic.js +++ b/js/schematic.js @@ -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)', From 7c922e69f1e3607ea00976591fdc8cd1f30d7640 Mon Sep 17 00:00:00 2001 From: cjt Date: Sat, 4 Feb 2012 10:50:11 -0500 Subject: [PATCH 2/9] schematic tool formatting issues --- js/schematic.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/js/schematic.js b/js/schematic.js index af694040c6..29b935eaf8 100644 --- a/js/schematic.js +++ b/js/schematic.js @@ -1339,6 +1339,7 @@ schematic = (function() { ok_button.appendChild(document.createTextNode('OK')); ok_button.dialog = dialog; // for the handler to use ok_button.addEventListener('click',dialog_okay,false); + ok_button.style.display = 'inline'; ok_button.style.border = '1px solid'; ok_button.style.padding = '5px'; ok_button.style.margin = '10px'; @@ -1348,6 +1349,7 @@ schematic = (function() { cancel_button.appendChild(document.createTextNode('Cancel')); cancel_button.dialog = dialog; // for the handler to use cancel_button.addEventListener('click',dialog_cancel,false); + cancel_button.style.display = 'inline'; cancel_button.style.border = '1px solid'; cancel_button.style.padding = '5px'; cancel_button.style.margin = '10px'; From eb7b3e3a900c31a85186b0b3d8eb10f3a3c51152 Mon Sep 17 00:00:00 2001 From: cjt Date: Sat, 4 Feb 2012 11:31:36 -0500 Subject: [PATCH 3/9] defend against None as parameter value in schematic tool --- js/schematic.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/js/schematic.js b/js/schematic.js index 29b935eaf8..338639418c 100644 --- a/js/schematic.js +++ b/js/schematic.js @@ -113,7 +113,7 @@ schematic = (function() { // else just populate parts bin with all the parts this.edits_allowed = true; var parts = input.getAttribute('parts'); - if (parts == undefined) { + if (parts == undefined || parts == 'None') { parts = new Array(); for (var p in parts_map) parts.push(p); } else if (parts == '') { @@ -133,7 +133,8 @@ schematic = (function() { // use user-supplied list of analyses, otherwise provide them all // analyses="" means no analyses var analyses = input.getAttribute('analyses'); - if (analyses == undefined) analyses = ['dc','ac','tran']; + if (analyses == undefined || analyses == 'None') + analyses = ['dc','ac','tran']; else if (analyses == '') analyses = []; else analyses = analyses.split(','); From 332f498616b4f850145bc63c522be3b3a5358f02 Mon Sep 17 00:00:00 2001 From: Piotr Mitros Date: Sat, 4 Feb 2012 15:27:01 -0500 Subject: [PATCH 4/9] Groundwork for going back to same place in video --- js/video_player.js | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/js/video_player.js b/js/video_player.js index e91813b5f1..d71103ba81 100644 --- a/js/video_player.js +++ b/js/video_player.js @@ -48,6 +48,17 @@ function postJSON(url, data, callback) { }); } +function postJSONAsync(url, data, callback) { + $.ajax({type:'POST', + url: url, + dataType: 'json', + data: data, + success: callback, + headers : {'X-CSRFToken':getCookie('csrftoken')}, + async:true + }); +} + // For easy embedding of CSRF in forms $(function() { $('#csrfmiddlewaretoken').attr("value", getCookie('csrftoken')) @@ -212,7 +223,10 @@ function onPlayerStateChange(event) { var switched_tab = false; // switch to true when we destroy so we know to call onYouTubePlayerAPIReady() // clear pings to video status when we switch to a different sequence tab with ajax -function videoDestroy() { +function videoDestroy(id) { + postJSON('/modx/video/'+id+'/goto_position', + {'position' : ytplayer.getCurrentTime()}); + load_id = 0; clearInterval(updateytplayerInfoInterval); clearInterval(ajax_videoInterval); @@ -318,6 +332,8 @@ function loadNewVideo(id, startSeconds) { catch(e) { window['console'].log(JSON.stringify(e)); } + $("#slider").slider("option","value",startSeconds); + //seekTo(startSeconds); } function cueNewVideo(id, startSeconds) { From 45f3fe7ee02eb706537ef07c86cc5aa5a239ad49 Mon Sep 17 00:00:00 2001 From: cjt Date: Sun, 5 Feb 2012 10:23:06 -0500 Subject: [PATCH 5/9] fix pop-up window positioning --- js/schematic.js | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/js/schematic.js b/js/schematic.js index 338639418c..dac06794f3 100644 --- a/js/schematic.js +++ b/js/schematic.js @@ -194,7 +194,6 @@ schematic = (function() { this.canvas.style.borderStyle = 'solid'; this.canvas.style.borderWidth = '1px'; this.canvas.style.borderColor = grid_style; - //this.canvas.style.position = 'absolute'; this.canvas.style.outline = 'none'; } @@ -274,6 +273,9 @@ schematic = (function() { tr = document.createElement('tr'); table.appendChild(tr); td = document.createElement('td'); + td.style.position = 'relative'; // so we can position subwindows + td.style.left = '0'; + td.style.top = '0'; tr.appendChild(td); td.appendChild(this.canvas); td = document.createElement('td'); @@ -1233,6 +1235,7 @@ schematic = (function() { // just redraw dynamic components sch.redraw(); + //sch.message(sch.canvas.page_x + ',' + sch.canvas.page_y + ';' + sch.canvas.mouse_x + ',' + sch.canvas.mouse_y + ';' + sch.cursor_x + ',' + sch.cursor_y); return false; } @@ -1474,9 +1477,9 @@ schematic = (function() { win.appendChild(content); content.win = win; // so content can contact us - // compute location in top-level div - win.left = this.canvas.page_x; - win.top = this.canvas.page_y; + // compute location relative to canvas + win.left = this.canvas.mouse_x; + win.top = this.canvas.mouse_y; // add to DOM win.style.background = 'white'; @@ -1486,7 +1489,8 @@ schematic = (function() { win.style.top = win.top + 'px'; win.style.border = '2px solid'; - this.input.parentNode.insertBefore(win,this.input.nextSibling); + this.canvas.parentNode.insertBefore(win,this.canvas); + //this.input.parentNode.insertBefore(win,this.input.nextSibling); } // close the window @@ -1631,7 +1635,10 @@ schematic = (function() { if (!event) event = window.event; var tool = (window.event) ? event.srcElement : event.target; - if (tool.enabled) tool.callback.call(tool.sch); + if (tool.enabled) { + tool.sch.canvas.relMouseCoords(event); // so we can position pop-up window correctly + tool.callback.call(tool.sch); + } } cut_icon = 'data:image/gif;base64,R0lGODlhEAAQALMAAAAAAIAAAACAAICAAAAAgIAAgACAgMDAwICAgP8AAAD/AP//AAAA//8A/wD//////yH5BAEAAAcALAAAAAAQABAAAAQu8MhJqz1g5qs7lxv2gRkQfuWomarXEgDRHjJhf3YtyRav0xcfcFgR0nhB5OwTAQA7'; From da032ac6b0cd2786838716fe60233c8c1dc9b962 Mon Sep 17 00:00:00 2001 From: cjt Date: Sun, 5 Feb 2012 14:47:32 -0500 Subject: [PATCH 6/9] update schematic tool --- .DS_Store | Bin 6148 -> 6148 bytes js/schematic.js | 4 ++-- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.DS_Store b/.DS_Store index 52e46d90053605e803adb0f2f82721f81fb5013c..b1e2c6344b66b7dc4feb294fa28621a4a91c38e3 100644 GIT binary patch delta 169 zcmZoMXfc=|#>B!ku~2NHo+2aj#(>?7i#IScF)~l)VLGkD#*oR7%aF*B&XCGboK#+1 zkd%|3#K6F?F{vOYv$({-;2I+nGYcylI|nD{pLK5rh8ycG?S1`*nwrsw_l*Y7~or9kP=#b3|nZGkn V<`;3~U}Rum0$RneIYML&GXSTADz5+l delta 69 zcmZoMXfc=|#>B)qu~2NHo+2aD#(>?7lMO^zCiAnL*t~=_nQ3FgS*FeG9Q+(WMVkdV XzB5ne7jfiZ00Kq^2A0hcB5Rldo)QsU diff --git a/js/schematic.js b/js/schematic.js index dac06794f3..d4a2f37964 100644 --- a/js/schematic.js +++ b/js/schematic.js @@ -817,8 +817,8 @@ schematic = (function() { ckt.parse_number(sch.tran_tstop), probe_names, false); // save a copy of the results for submission - this.transient_results = {}; - for (var i in results) this.transient_results[i] = results[i]; + sch.transient_results = {}; + for (var i in results) sch.transient_results[i] = results[i]; if (typeof results == 'string') sch.message(results); From 0038e8e4f08b2492dcac6a55e0a70484bd21ef8b Mon Sep 17 00:00:00 2001 From: Piotr Mitros Date: Sun, 5 Feb 2012 16:23:57 -0500 Subject: [PATCH 7/9] Removed instrumentation --- js/video_player.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/js/video_player.js b/js/video_player.js index d71103ba81..3eb8461492 100644 --- a/js/video_player.js +++ b/js/video_player.js @@ -224,8 +224,8 @@ function onPlayerStateChange(event) { var switched_tab = false; // switch to true when we destroy so we know to call onYouTubePlayerAPIReady() // clear pings to video status when we switch to a different sequence tab with ajax function videoDestroy(id) { - postJSON('/modx/video/'+id+'/goto_position', - {'position' : ytplayer.getCurrentTime()}); +// postJSON('/modx/video/'+id+'/goto_position', +// {'position' : ytplayer.getCurrentTime()}); load_id = 0; clearInterval(updateytplayerInfoInterval); @@ -332,7 +332,7 @@ function loadNewVideo(id, startSeconds) { catch(e) { window['console'].log(JSON.stringify(e)); } - $("#slider").slider("option","value",startSeconds); + //$("#slider").slider("option","value",startSeconds); //seekTo(startSeconds); } From afe72b59ad0c258510de1c7c508906625f1cb226 Mon Sep 17 00:00:00 2001 From: Piotr Mitros Date: Sun, 5 Feb 2012 18:33:51 -0500 Subject: [PATCH 8/9] No annoying error message --- js/video_player.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/js/video_player.js b/js/video_player.js index 3eb8461492..e33919c86f 100644 --- a/js/video_player.js +++ b/js/video_player.js @@ -297,7 +297,7 @@ function onytplayerStateChange(newState) { } function onPlayerError(errorCode) { - alert("An error occured: " + errorCode); + // alert("An error occured: " + errorCode); } function updateytplayerInfo() { From b15e7c19d9a18088b72fdd2e83b2bf631e702de2 Mon Sep 17 00:00:00 2001 From: cjt Date: Sun, 5 Feb 2012 23:36:38 -0500 Subject: [PATCH 9/9] fix problem with labeled ground nodes --- js/cktsim.js | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/js/cktsim.js b/js/cktsim.js index cbbcb21a1d..2c8e42cdb5 100755 --- a/js/cktsim.js +++ b/js/cktsim.js @@ -96,9 +96,15 @@ 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 - var gnd_label = '0'; - this.node_map[gnd_label] = this.gnd_node(); + // set up mapping for all ground connections + for (var i = netlist.length - 1; i >= 0; --i) { + var component = netlist[i]; + var type = component[0]; + if (type == 'g') { + var connections = component[3]; + this.node_map[connections[0]] = this.gnd_node(); + } + } // process each component in the JSON netlist (see schematic.js for format) var found_ground = false; @@ -120,9 +126,9 @@ 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); + else if (index == this.gnd_node()) found_ground = true; connections[j] = index; } @@ -146,7 +152,8 @@ cktsim = (function() { 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 + + if (!found_ground) { // No ground on schematic alert('Please make at least one connection to ground (inverted T symbol)'); return false; }