Skip to content

Commit 139d0ec

Browse files
committed
started adding op amp
1 parent eb694bd commit 139d0ec

6 files changed

Lines changed: 194 additions & 84 deletions

File tree

filterAnalyzer/index.html

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,17 +2,13 @@
22
<html lang="en">
33

44
<head>
5-
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/katex@0.16.3/dist/katex.min.css" integrity="sha384-Juol1FqnotbkyZUT5Z7gUPjQ9gzlwCENvUZTpQBAPxtusdwFLRy382PSDx5UUJ4/" crossorigin="anonymous">
6-
7-
<!-- The loading of KaTeX is deferred to speed up page rendering -->
8-
<script defer src="https://cdn.jsdelivr.net/npm/katex@0.16.3/dist/katex.min.js" integrity="sha384-97gW6UIJxnlKemYavrqDHSX3SiygeOwIZhwyOKRfSaf0JWKRVj9hLASHgFTzT+0O" crossorigin="anonymous"></script>
9-
105
<meta charset="utf-8">
116
<meta name="viewport" content="width=device-width, initial-scale=1">
127
<title>Circuit Solver</title>
138
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.2.1/dist/css/bootstrap.min.css" rel="stylesheet"
149
integrity="sha384-iYQeCzEYFbKjA/T2uDLTpkwGzCiq6soy8tYaI1GyVh/UjpbCx/TYkiZhlZB6+fzT" crossorigin="anonymous">
15-
<script src="https://cdn.plot.ly/plotly-2.14.0.min.js"></script>
10+
<!-- <script src="https://cdn.plot.ly/plotly-2.14.0.min.js"></script> -->
11+
<script src="js/plotly-2.14.0.min.js"></script>
1612
<script src="js/algebrite.bundle-for-browser-min.js"></script>
1713
<!-- <script src="js/algebrite_v1p2.bundle-for-browser-min.js"></script> -->
1814
<script src="js/startupSchematic.js"></script>

filterAnalyzer/js/plotly-2.14.0.min.js

Lines changed: 65 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

filterAnalyzer/modules/View.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ export class View extends draw2d.Canvas {
4545
}
4646

4747
addShapeToSchem(type, x, y) {
48-
console.log(type, x, y)
48+
// console.log(type, x, y)
4949

5050
var MyInputPortLocator = draw2d.layout.locator.PortLocator.extend({
5151
init:function(x,y){

filterAnalyzer/modules/main.js

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -408,7 +408,7 @@ class Game extends React.Component {
408408

409409
handleCanvasChange(canvasState) {
410410
// console.log("Inside handleCanvasChange");
411-
// console.log(canvasState);
411+
console.log(canvasState);
412412
var latexResult, deleteMeLatex;
413413
var newElementMap;
414414
var elements = this.state.elements;
@@ -417,7 +417,7 @@ class Game extends React.Component {
417417

418418
//add new elements
419419
for (const key in newElementMap) {
420-
if ((key == 'gnd') || (key == 'vout') || (key == 'vin')) continue;
420+
if ((key == 'gnd') || (key == 'vout') || (key == 'vin') || (key == 'op')) continue;
421421
if (!(key in elements)) {
422422
var firstLetter = Array.from(key)[0];
423423
if (firstLetter == 'R') {
@@ -558,8 +558,8 @@ class Game extends React.Component {
558558
// Update the DOM
559559
return html`
560560
<${navBar} title="ONLINE ELECTRONIC CIRCUIT LAPLACE SOLVER" key="navBar"/>
561-
<div className="w-100 p-3 bg-green">
562-
<div className="container-xl">
561+
<div className="w-100 p-3 bg-green" key="wrapper">
562+
<div className="container-xl" key="topContainer">
563563
<${SchematicComponents} key="schemComp"/>
564564
<${Schematic} key="schem"/>
565565
<${SchematicVal} key="schemVal" schematicReadiness=${this.schematicReadiness}/>

filterAnalyzer/modules/mna.js

Lines changed: 112 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,41 @@
11
import simplify_algebra from './simplify_algebra.js'
2+
3+
function arrayContains (list1, item) {
4+
return list1.findIndex((elem) => (elem.el == item.el) && (elem.port == item.port))
5+
}
6+
7+
function includesElement (list1, item) {
8+
return list1.findIndex((elem) => (elem.el == item))
9+
}
10+
211
function processCanvasState(canvasState) {
312
var newElementMap = {};
413
// var elementsOnNodes = [];
514
var nodeMap = [];
615
var createNode;
716
var end1, end2, i, j, k;
817
var optimized;
18+
var idx;
19+
var cnt;
20+
var firstLetter;
921

1022

1123
//Create a new node for each component
1224
canvasState.forEach(item => {
1325
if (item.type == "draw2d.Connection") {
1426
//get both ends of the connection
15-
end1 = `${item.source.node}.${item.source.port}`
16-
end2 = `${item.target.node}.${item.target.port}`
17-
nodeMap.push([end1, end2])
27+
// end1 = `${item.source.node}.${item.source.port}`
28+
// end2 = `${item.target.node}.${item.target.port}`
29+
nodeMap.push([{el: item.source.node, port: item.source.port}, {el: item.target.node, port: item.target.port}])
1830
// console.log(end1, end2);
1931
} else {
2032
//if its not a connection its an element
21-
newElementMap[item.id] = {};
33+
firstLetter = Array.from(item.id)[0];
34+
//cnt is how many connections it's expected
35+
if ((firstLetter=='L') || (firstLetter=='R') || (firstLetter=='C')) cnt = 2;
36+
else if (firstLetter=='o') cnt = 3;
37+
else cnt = 1;
38+
newElementMap[item.id] = {cnt: cnt};
2239
}
2340
});
2441

@@ -29,13 +46,17 @@ function processCanvasState(canvasState) {
2946
for (i = 0; i < nodeMap.length; i++) {
3047
for (j = 0; j < nodeMap[i].length; j++) {
3148
for (k = i+1; k < nodeMap.length; k++) {
32-
if (nodeMap[k].includes(nodeMap[i][j])) {
49+
// console.log('looking for ',nodeMap[i][j], ' inside ', nodeMap[k])
50+
// if (nodeMap[k].includes(nodeMap[i][j])) {
51+
idx = arrayContains(nodeMap[k], nodeMap[i][j])
52+
if (idx >= 0) {
53+
// console.log('common node')
3354
optimized = true;
3455
//Before concat with K, must remove the element that is about to be duplicated
35-
const index = nodeMap[k].indexOf(nodeMap[i][j]);
36-
if (index > -1) { // only splice array when item is found
37-
nodeMap[k].splice(index, 1); // 2nd parameter means remove one item only
38-
}
56+
// const index = nodeMap[k].indexOf(nodeMap[i][j]);
57+
// if (index > -1) { // only splice array when item is found
58+
nodeMap[k].splice(idx, 1); // 2nd parameter means remove one item only
59+
// }
3960
nodeMap[i] = nodeMap[i].concat(nodeMap[k]);
4061
nodeMap.splice(k, 1);
4162
break loop1;
@@ -45,50 +66,56 @@ function processCanvasState(canvasState) {
4566
}
4667
} while (optimized==true);
4768

48-
// //check if either end exists in the nodemap, create a new entry or add to existing entry
49-
// createNode = true;
50-
// for (i = 0; i < nodeMap.length; i++) {
51-
// if (nodeMap[i].includes(end1) && !nodeMap[i].includes(end2)) {
52-
// nodeMap[i].push(end2);
53-
// createNode = false;
54-
// break;
55-
// }
56-
// else if (!nodeMap[i].includes(end1) && nodeMap[i].includes(end2)) {
57-
// nodeMap[i].push(end1);
58-
// createNode = false;
59-
// break;
60-
// }
61-
// }
62-
// if (createNode) {
63-
// nodeMap.push([end1, end2])
64-
// }
65-
// //Fixme - there needs to be some code here to merge nodes
66-
67-
// } else {
68-
// //if its not a connection its an element
69-
// newElementMap[item.id] = {};
70-
// }
71-
72-
// });
73-
74-
var elementsOnNodes =[];
75-
var t;
69+
//loop thru nodemap and remove elements which don't have both ports connected
7670
for (i = 0; i < nodeMap.length; i++) {
77-
elementsOnNodes[i] = [];
7871
for (j = 0; j < nodeMap[i].length; j++) {
79-
t = nodeMap[i][j].split('.')
80-
elementsOnNodes[i].push(t[0])
72+
newElementMap[nodeMap[i][j].el].cnt -= 1;
8173
}
8274
}
75+
for (const key in newElementMap) {
76+
if(newElementMap[key].cnt > 0) {
77+
console.log('removing', key)
78+
//element must be removed!
79+
for (i = 0; i < nodeMap.length; i++) {
80+
for (j = 0; j < nodeMap[i].length; j++) {
81+
do {
82+
cnt = includesElement(nodeMap[i], key)
83+
if (cnt>=0) nodeMap[i].splice(cnt,1)
84+
} while (cnt >= 0)
85+
// cnt = includesElement(nodeMap[i], key)
86+
// newElementMap[nodeMap[i][j].el].cnt -= 1;
87+
}
88+
}
89+
delete newElementMap[key]
90+
}
91+
}
92+
console.log(newElementMap);
93+
94+
//remove 2-port and 3-port elements that aren't fully connected
95+
//FIXME - here
96+
//[x]1 - Change nodemap to an array of object. Kind of dumb to have to keep splitting
97+
//[x]1a - remove elementsOnNodes
98+
//[x]2 - create a counter array and count occurances of each element
99+
//[x]3 - loop thru count array and remove anything which isn't 2 or 3
100+
101+
//list of elements on nodes, not specifying port
102+
// var elementsOnNodes = [];
103+
// var t;
104+
// for (i = 0; i < nodeMap.length; i++) {
105+
// elementsOnNodes[i] = [];
106+
// for (j = 0; j < nodeMap[i].length; j++) {
107+
// t = nodeMap[i][j]['el']
108+
// elementsOnNodes[i].push(t)
109+
// }
110+
// }
83111
// console.log('newElementMap', newElementMap)
84112

85-
return [elementsOnNodes, nodeMap, newElementMap]
113+
return [nodeMap, newElementMap]
86114

87115
}
88116

89117

90118
export function calculateMNA(canvasState, schematicReadiness) {
91-
var elementsOnNodes = [];
92119
var nodeMap = [];
93120
var i, j;
94121
var vinNode, gndNode, voutNode;
@@ -97,8 +124,8 @@ export function calculateMNA(canvasState, schematicReadiness) {
97124
var element;
98125
var latexResult = null;
99126

100-
[elementsOnNodes, nodeMap, newElementMap] = processCanvasState(canvasState);
101-
console.log("bp1", elementsOnNodes, nodeMap, newElementMap)
127+
[nodeMap, newElementMap] = processCanvasState(canvasState);
128+
console.log("bp1", nodeMap, newElementMap)
102129

103130
//verify how ready the schematic is
104131
// All this code is just for that! Can't it be done later, for free? //FIXME
@@ -109,29 +136,30 @@ export function calculateMNA(canvasState, schematicReadiness) {
109136
gnd: false,
110137
};
111138
var tmp;
112-
for (i = 0; i < elementsOnNodes.length; i++) {
113-
if (elementsOnNodes[i].includes('vout')) {
139+
for (i = 0; i < nodeMap.length; i++) {
140+
// if (elementsOnNodes[i].includes('vout')) {
141+
if (includesElement(nodeMap[i], 'vout') >= 0) {
114142
schematicReadiness.vout = true;
115143
//See which nodes are connected together
116144
var crushedNodes = [i], zz, moreNodes, jj, kk, newNode, elementsOnThisNode = [];
117145
zz = i;
118146
moreNodes = [i];
119-
elementsOnThisNode = [].concat(elementsOnThisNode + elementsOnNodes[i]);
147+
elementsOnThisNode = [].concat(elementsOnThisNode + nodeMap[i]);
120148
while (moreNodes.length > 0) {
121149
moreNodes = [];
122150
newNode = moreNodes.pop();
123151
//Search through the node for elements with two ports (starting with the node tied to vout)
124-
for (jj = 0; jj < elementsOnNodes[i].length; jj++) {
125-
if (elementsOnNodes[i][jj] == 'vout') tmp = i;
126-
else if (elementsOnNodes[i][jj] == 'vin') tmp = i;
127-
else if (elementsOnNodes[i][jj] == 'gnd') tmp = i;
152+
for (jj = 0; jj < nodeMap[i].length; jj++) {
153+
if (nodeMap[i][jj].el == 'vout') tmp = i;
154+
else if (nodeMap[i][jj].el == 'vin') tmp = i;
155+
else if (nodeMap[i][jj].el == 'gnd') tmp = i;
128156
else {
129157
//found a two ported element. Add the node on the other end if it isn't already added.
130-
for (kk = 0; kk < elementsOnNodes.length; kk++) {
158+
for (kk = 0; kk < nodeMap.length; kk++) {
131159
if (!crushedNodes.includes(kk)) {
132160
crushedNodes.push(kk);
133161
moreNodes.push(kk);
134-
elementsOnThisNode = [].concat(elementsOnThisNode, elementsOnNodes[kk]);
162+
elementsOnThisNode = [].concat(elementsOnThisNode, nodeMap[kk]);
135163
}
136164
}
137165
moreNodes = 1; //wtf does this line do!
@@ -140,8 +168,8 @@ export function calculateMNA(canvasState, schematicReadiness) {
140168
}
141169

142170

143-
if (elementsOnThisNode.includes('gnd')) schematicReadiness.gnd = true;
144-
if (elementsOnThisNode.includes('vin')) schematicReadiness.vin = true;
171+
if (includesElement(elementsOnThisNode, 'gnd') >= 0) schematicReadiness.gnd = true;
172+
if (includesElement(elementsOnThisNode, 'vin') >= 0) schematicReadiness.vin = true;
145173

146174
break;
147175
}
@@ -157,22 +185,24 @@ export function calculateMNA(canvasState, schematicReadiness) {
157185

158186
// Build MNA array
159187
if (schematicReadiness.vout && schematicReadiness.vin && schematicReadiness.gnd) {
188+
var numOpAmps=0;
189+
for(const key in newElementMap) if (Array.from(key)[0] == 'o') numOpAmps+=1;
160190
// Create 2D modified nodal analysis array
161-
var mnaMatrix = new Array(nodeMap.length);
162-
for (i = 0; i < nodeMap.length; i++) mnaMatrix[i] = new Array(nodeMap.length).fill("0");
191+
var mnaMatrix = new Array(nodeMap.length + numOpAmps);
192+
for (i = 0; i < mnaMatrix.length; i++) mnaMatrix[i] = new Array(mnaMatrix.length).fill("0");
163193
//create node map without gnd node. All nodes might need to shift
164-
for (i = 0; i < elementsOnNodes.length; i++) {
165-
if (elementsOnNodes[i].includes('gnd')) gndNode = i;
194+
for (i = 0; i < nodeMap.length; i++) {
195+
if (includesElement(nodeMap[i], 'gnd') >= 0) gndNode = i;
166196
}
167197
var nodeMapNoGnd = nodeMap;
168-
var rem = nodeMapNoGnd.splice(gndNode, 1);
198+
nodeMapNoGnd.splice(gndNode, 1); //removes the ground node so MNA is arranged properly
169199

170200
// Step 1 - create map of every element and which node it connects too. Doing this here, after node map is complete and ground node is removed
171201
for (i = 0; i < nodeMapNoGnd.length; i++) {
172202
for (j = 0; j < nodeMapNoGnd[i].length; j++) {
173-
element = nodeMapNoGnd[i][j].split('.')
174-
if (element[0] in elementMap) elementMap[element[0]].push(i)
175-
else elementMap[element[0]] = [i]
203+
element = nodeMapNoGnd[i][j]['el']
204+
if (element in elementMap) elementMap[element].push(i)
205+
else elementMap[element] = [i]
176206
}
177207
}
178208
voutNode = elementMap['vout'][0];
@@ -181,7 +211,7 @@ export function calculateMNA(canvasState, schematicReadiness) {
181211
// Step 2 - loop thru elementMap and start adding things to the MNA
182212
var laplaceElement, firstLetter;
183213
for (const key2 in elementMap) {
184-
if ((key2 != 'vin') && (key2 != 'vout') && (key2 != 'gnd')) {
214+
if ((key2 != 'vin') && (key2 != 'vout') && (key2 != 'gnd') && (key2 != 'op')) {
185215
firstLetter = Array.from(key2)[0];
186216
if (firstLetter == 'R') laplaceElement = key2;
187217
else if (firstLetter == 'L') laplaceElement = "(S*" + key2 + ")";
@@ -198,15 +228,28 @@ export function calculateMNA(canvasState, schematicReadiness) {
198228
}
199229
}
200230
}
201-
//2.3 Add a 1 in the bottom column indicating which node is Vin connected too
202-
mnaMatrix[mnaMatrix.length - 1][vinNode] = '1';
231+
//2.3 Add a 1 in the bottom row indicating which node is Vin connected too
232+
mnaMatrix[mnaMatrix.length - 1 - numOpAmps][vinNode] = '1';
203233

204234
//2.4 Add a 1 in the node connected to Vin to indicate that Iin flows into that node
205-
mnaMatrix[vinNode][mnaMatrix.length - 1] = '1';
235+
mnaMatrix[vinNode][mnaMatrix.length - 1 - numOpAmps] = '1';
236+
237+
//2.5 For each op-amp add some 1's. It says that 2 nodes are equal to each other, and that 1 node has a new ideal current source
238+
numOpAmps = 0;
239+
for(const key in elementMap) {
240+
if (Array.from(key)[0] == 'o') {
241+
numOpAmps = numOpAmps + 1;
242+
console.log("bp3",numOpAmps,key,elementMap[key] )
243+
mnaMatrix[nodeMapNoGnd.length + numOpAmps][elementMap[key][0]] = '-1';
244+
mnaMatrix[nodeMapNoGnd.length + numOpAmps][elementMap[key][1]] = '1';
245+
mnaMatrix[elementMap[key][2]][nodeMapNoGnd.length + numOpAmps] = '1';
246+
}
247+
}
248+
206249

207-
// console.log('elementMap', elementMap);
250+
console.log('elementMap', elementMap);
208251
// console.log('vin, vout and gnd node', vinNode, voutNode, gndNode);
209-
// console.log('mna ', mnaMatrix);
252+
console.log('mna ', mnaMatrix);
210253

211254
var nerdStrArr = [];
212255
var nerdStr = "";

filterAnalyzer/toDo.md

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -43,19 +43,25 @@
4343
- [x] add min-to-max frequency range
4444
- [x] Update when user changes value or unit
4545
- [x] Use units
46-
- Add a hold button
4746
- [x] Add x-y cursors
48-
- Make graph background transparent
4947
- [x] Prevent user adding multiple Vin or Vout
5048
- [x] Stop it crashing when user drags multiple elements
5149
#### Remaining
50+
- [ ] Add a hold button
51+
- [ ] Make graph background transparent
5252
- [ ] Add color switcher in top bar
5353
- [ ] Separate page into those nice boxes each with shadow
5454
- [ ] Add comments section
5555
- [ ] Make draggable things into images, not text boxes
5656
- [ ] Add option to rotate components
57-
- [ ] displaying frequency response
58-
- [ ] Add an op-amp
57+
- [x] displaying frequency response
58+
- [ ] Add an op-amp -> done a lot of this already
59+
- [ ] the element map has an array of port connections. That needs to go in a specific order, so later we know which op amp port is which
60+
- [ ] Move sanity checking into processCanvasState function, add all components fully connected?
61+
- [ ] processCanvasState() must also remove nodes that aren't connected to vout (it's already removing elements)
62+
- [ ] device can't connect to itself?
63+
- [ ] have a separate array just to hold op amps
64+
- [ ] Create object of elements, connect each end to a new node. Then delete elements who aren't fully connected, optimize the nodes, and remove nodes that don't have a path to vout
5965

6066

6167

0 commit comments

Comments
 (0)