Baixe o app para aproveitar ainda mais
Esta é uma pré-visualização de arquivo. Entre para ver o arquivo original
ACRailElm.java class ACRailElm extends RailElm { public ACRailElm(int xx, int yy) { super(xx, yy, WF_AC); } Class getDumpClass() { return RailElm.class; } int getShortcut() { return 0; } } ACVoltageElm.java class ACVoltageElm extends VoltageElm { public ACVoltageElm(int xx, int yy) { super(xx, yy, WF_AC); } Class getDumpClass() { return VoltageElm.class; } } CC2Elm.java import java.awt.*; import java.util.StringTokenizer; class CC2Elm extends ChipElm { double gain; public CC2Elm(int xx, int yy) { super(xx, yy); gain = 1; } public CC2Elm(int xx, int yy, int g) { super(xx, yy); gain = g; } public CC2Elm(int xa, int ya, int xb, int yb, int f, StringTokenizer st) { super(xa, ya, xb, yb, f, st); gain = new Double(st.nextToken()).doubleValue(); } String dump() { return super.dump() + " " + gain; } String getChipName() { return "CC2"; } void setupPins() { sizeX = 2; sizeY = 3; pins = new Pin[3]; pins[0] = new Pin(0, SIDE_W, "X"); pins[0].output = true; pins[1] = new Pin(2, SIDE_W, "Y"); pins[2] = new Pin(1, SIDE_E, "Z"); } void getInfo(String arr[]) { arr[0] = (gain == 1) ? "CCII+" : "CCII-"; arr[1] = "X,Y = " + getVoltageText(volts[0]); arr[2] = "Z = " + getVoltageText(volts[2]); arr[3] = "I = " + getCurrentText(pins[0].current); } //boolean nonLinear() { return true; } void stamp() { // X voltage = Y voltage sim.stampVoltageSource(0, nodes[0], pins[0].voltSource); sim.stampVCVS(0, nodes[1], 1, pins[0].voltSource); // Z current = gain * X current sim.stampCCCS(0, nodes[2], pins[0].voltSource, gain); } void draw(Graphics g) { pins[2].current = pins[0].current * gain; drawChip(g); } int getPostCount() { return 3; } int getVoltageSourceCount() { return 1; } int getDumpType() { return 179; } } class CC2NegElm extends CC2Elm { public CC2NegElm(int xx, int yy) { super(xx, yy, -1); } Class getDumpClass() { return CC2Elm.class; } } ADCElm.java import java.awt.*; import java.util.StringTokenizer; class ADCElm extends ChipElm { public ADCElm(int xx, int yy) { super(xx, yy); } public ADCElm(int xa, int ya, int xb, int yb, int f, StringTokenizer st) { super(xa, ya, xb, yb, f, st); } String getChipName() { return "ADC"; } boolean needsBits() { return true; } void setupPins() { sizeX = 2; sizeY = bits > 2 ? bits : 2; pins = new Pin[getPostCount()]; int i; for (i = 0; i != bits; i++) { pins[i] = new Pin(bits-1-i, SIDE_E, "D" + i); pins[i].output = true; } pins[bits] = new Pin(0, SIDE_W, "In"); pins[bits+1] = new Pin(sizeY-1, SIDE_W, "V+"); allocNodes(); } void execute() { int imax = (1<<bits)-1; // if we round, the half-flash doesn't work double val = imax*volts[bits]/volts[bits+1]; // + .5; int ival = (int) val; ival = min(imax, max(0, ival)); int i; for (i = 0; i != bits; i++) pins[i].value = ((ival & (1<<i)) != 0); } int getVoltageSourceCount() { return bits; } int getPostCount() { return bits+2; } int getDumpType() { return 167; } } EditOptions.java class EditOptions implements Editable { CirSim sim; public EditOptions(CirSim s) { sim = s; } public EditInfo getEditInfo(int n) { if (n == 0) return new EditInfo("Time step size (s)", sim.timeStep, 0, 0); if (n == 1) return new EditInfo("Range for voltage color (V)", CircuitElm.voltageRange, 0, 0); return null; } public void setEditValue(int n, EditInfo ei) { if (n == 0 && ei.value > 0) sim.timeStep = ei.value; if (n == 1 && ei.value > 0) CircuitElm.voltageRange = ei.value; } }; AnalogSwitch2Elm.java import java.awt.*; import java.util.StringTokenizer; class AnalogSwitch2Elm extends AnalogSwitchElm { public AnalogSwitch2Elm(int xx, int yy) { super(xx, yy); } public AnalogSwitch2Elm(int xa, int ya, int xb, int yb, int f, StringTokenizer st) { super(xa, ya, xb, yb, f, st); } final int openhs = 16; Point swposts[], swpoles[], ctlPoint; void setPoints() { super.setPoints(); calcLeads(32); swposts = newPointArray(2); swpoles = newPointArray(2); interpPoint2(lead1, lead2, swpoles[0], swpoles[1], 1, openhs); interpPoint2(point1, point2, swposts[0], swposts[1], 1, openhs); ctlPoint = interpPoint(point1, point2, .5, openhs); } int getPostCount() { return 4; } void draw(Graphics g) { setBbox(point1, point2, openhs); // draw first lead setVoltageColor(g, volts[0]); drawThickLine(g, point1, lead1); // draw second lead setVoltageColor(g, volts[1]); drawThickLine(g, swpoles[0], swposts[0]); // draw third lead setVoltageColor(g, volts[2]); drawThickLine(g, swpoles[1], swposts[1]); // draw switch g.setColor(lightGrayColor); int position = (open) ? 1 : 0; drawThickLine(g, lead1, swpoles[position]); updateDotCount(); drawDots(g, point1, lead1, curcount); drawDots(g, swpoles[position], swposts[position], curcount); drawPosts(g); } Point getPost(int n) { return (n == 0) ? point1 : (n == 3) ? ctlPoint : swposts[n-1]; } int getDumpType() { return 160; } void calculateCurrent() { if (open) current = (volts[0]-volts[2])/r_on; else current = (volts[0]-volts[1])/r_on; } void stamp() { sim.stampNonLinear(nodes[0]); sim.stampNonLinear(nodes[1]); sim.stampNonLinear(nodes[2]); } void doStep() { open = (volts[3] < 2.5); if ((flags & FLAG_INVERT) != 0) open = !open; if (open) { sim.stampResistor(nodes[0], nodes[2], r_on); sim.stampResistor(nodes[0], nodes[1], r_off); } else { sim.stampResistor(nodes[0], nodes[1], r_on); sim.stampResistor(nodes[0], nodes[2], r_off); } } boolean getConnection(int n1, int n2) { if (n1 == 3 || n2 == 3) return false; return true; } void getInfo(String arr[]) { arr[0] = "analog switch (SPDT)"; arr[1] = "I = " + getCurrentDText(getCurrent()); } } AnalogSwitchElm.java import java.awt.*; import java.util.StringTokenizer; class AnalogSwitchElm extends CircuitElm { final int FLAG_INVERT = 1; double resistance, r_on, r_off; public AnalogSwitchElm(int xx, int yy) { super(xx, yy); r_on = 20; r_off = 1e10; } public AnalogSwitchElm(int xa, int ya, int xb, int yb, int f, StringTokenizer st) { super(xa, ya, xb, yb, f); r_on = 20; r_off = 1e10; try { r_on = new Double(st.nextToken()).doubleValue(); r_off = new Double(st.nextToken()).doubleValue(); } catch (Exception e) { } } String dump() { return super.dump() + " " + r_on + " " + r_off; } int getDumpType() { return 159; } boolean open; Point ps, point3, lead3; void setPoints() { super.setPoints(); calcLeads(32); ps = new Point(); int openhs = 16; point3 = interpPoint(point1, point2, .5, -openhs); lead3 = interpPoint(point1, point2, .5, -openhs/2); } void draw(Graphics g) { int openhs = 16; int hs = (open) ? openhs : 0; setBbox(point1, point2, openhs); draw2Leads(g); g.setColor(lightGrayColor); interpPoint(lead1, lead2, ps, 1, hs); drawThickLine(g, lead1, ps); setVoltageColor(g, volts[2]); drawThickLine(g, point3, lead3); if (!open) doDots(g); drawPosts(g); } void calculateCurrent() { current = (volts[0]-volts[1])/resistance; } // we need this to be able to change the matrix for each step boolean nonLinear() { return true; } void stamp() { sim.stampNonLinear(nodes[0]); sim.stampNonLinear(nodes[1]); } void doStep() { open = (volts[2] < 2.5); if ((flags & FLAG_INVERT) != 0) open = !open; resistance = (open) ? r_off : r_on; sim.stampResistor(nodes[0], nodes[1], resistance); } void drag(int xx, int yy) { xx = sim.snapGrid(xx); yy = sim.snapGrid(yy); if (abs(x-xx) < abs(y-yy)) xx = x; else yy = y; int q1 = abs(x-xx)+abs(y-yy); int q2 = (q1/2) % sim.gridSize; if (q2 != 0) return; x2 = xx; y2 = yy; setPoints(); } int getPostCount() { return 3; } Point getPost(int n) { return (n == 0) ? point1 : (n == 1) ? point2 : point3; } void getInfo(String arr[]) { arr[0] = "analog switch"; arr[1] = open ? "open" : "closed"; arr[2] = "Vd = " + getVoltageDText(getVoltageDiff()); arr[3] = "I = " + getCurrentDText(getCurrent()); arr[4] = "Vc = " + getVoltageText(volts[2]); } // we have to just assume current will flow either way, even though that // might cause singular matrix errors boolean getConnection(int n1, int n2) { if (n1 == 2 || n2 == 2) return false; return true; } public EditInfo getEditInfo(int n) { if (n == 0) { EditInfo ei = new EditInfo("", 0, -1, -1); ei.checkbox = new Checkbox("Normally closed", (flags & FLAG_INVERT) != 0); return ei; } if (n == 1) return new EditInfo("On Resistance (ohms)", r_on, 0, 0); if (n == 2) return new EditInfo("Off Resistance (ohms)", r_off, 0, 0); return null; } public void setEditValue(int n, EditInfo ei) { if (n == 0) flags = (ei.checkbox.getState()) ? (flags | FLAG_INVERT) : (flags & ~FLAG_INVERT); if (n == 1 && ei.value > 0) r_on = ei.value; if (n == 2 && ei.value > 0) r_off = ei.value; } } AndGateElm.java import java.awt.*; import java.util.StringTokenizer; class AndGateElm extends GateElm { public AndGateElm(int xx, int yy) { super(xx, yy); } public AndGateElm(int xa, int ya, int xb, int yb, int f, StringTokenizer st) { super(xa, ya, xb, yb, f, st); } void setPoints() { super.setPoints(); // 0=topleft, 1-10 = top curve, 11 = right, 12-21=bottom curve, // 22 = bottom left Point triPoints[] = newPointArray(23); interpPoint2(lead1, lead2, triPoints[0], triPoints[22], 0, hs2); int i; for (i = 0; i != 10; i++) { double a = i*.1; double b = Math.sqrt(1-a*a); interpPoint2(lead1, lead2, triPoints[i+1], triPoints[21-i], .5+a/2, b*hs2); } triPoints[11] = new Point(lead2); if (isInverting()) { pcircle = interpPoint(point1, point2, .5+(ww+4)/dn); lead2 = interpPoint(point1, point2, .5+(ww+8)/dn); } gatePoly = createPolygon(triPoints); } String getGateName() { return "AND gate"; } boolean calcFunction() { int i; boolean f = true; for (i = 0; i != inputCount; i++) f &= getInput(i); return f; } int getDumpType() { return 150; } int getShortcut() { return '2'; } } AntennaElm.java import java.awt.*; import java.util.StringTokenizer; class AntennaElm extends RailElm { public AntennaElm(int xx, int yy) { super(xx, yy, WF_DC); } public AntennaElm(int xa, int ya, int xb, int yb, int f, StringTokenizer st) { super(xa, ya, xb, yb, f, st); waveform = WF_DC; } double fmphase; void stamp() { sim.stampVoltageSource(0, nodes[0], voltSource); } void doStep() { sim.updateVoltageSource(0, nodes[0], voltSource, getVoltage()); } double getVoltage() { fmphase += 2*pi*(2200+Math.sin(2*pi*sim.t*13)*100)*sim.timeStep; double fm = 3*Math.sin(fmphase); return Math.sin(2*pi*sim.t*3000)*(1.3+Math.sin(2*pi*sim.t*12))*3 + Math.sin(2*pi*sim.t*2710)*(1.3+Math.sin(2*pi*sim.t*13))*3 + Math.sin(2*pi*sim.t*2433)*(1.3+Math.sin(2*pi*sim.t*14))*3 + fm; } int getDumpType() { return 'A'; } int getShortcut() { return 0; } } BoxElm.java import java.awt.*; import java.util.StringTokenizer; import java.util.Vector; class BoxElm extends GraphicElm { public BoxElm(int xx, int yy) { super(xx, yy); x2 = xx + 16; y2 = yy + 16; setBbox(x, y, x2, y2); } public BoxElm(int xa, int ya, int xb, int yb, int f, StringTokenizer st) { super(xa, ya, xb, yb, f); x2 = xb; y2 = yb; /* if ( st.hasMoreTokens() ) x = new Integer(st.nextToken()).intValue(); if ( st.hasMoreTokens() ) y = new Integer(st.nextToken()).intValue(); if ( st.hasMoreTokens() ) x2 = new Integer(st.nextToken()).intValue(); if ( st.hasMoreTokens() ) y2 = new Integer(st.nextToken()).intValue();*/ setBbox(x, y, x2, y2); } String dump() { return super.dump(); } int getDumpType() { return 'b'; } void drag(int xx, int yy) { x = xx; y = yy; } void draw(Graphics g) { //g.setColor(needsHighlight() ? selectColor : lightGrayColor); g.setColor(needsHighlight() ? selectColor : Color.GRAY); setBbox(x, y, x2, y2); if ( x < x2 && y < y2 ) g.fillRect(x,y, x2-x, y2-y); else if ( x > x2 && y < y2 ) g.fillRect(x2,y, x-x2, y2-y); else if ( x < x2 && y > y2 ) g.fillRect(x, y2, x2-x, y-y2); else g.fillRect(x2, y2, x-x2, y-y2); } public EditInfo getEditInfo(int n) { return null; } public void setEditValue(int n, EditInfo ei) { } void getInfo(String arr[]) { } @Override int getShortcut() { return 0; } } CapacitorElm.java import java.awt.*; import java.util.StringTokenizer; class CapacitorElm extends CircuitElm { double capacitance; double compResistance, voltdiff; Point plate1[], plate2[]; public static final int FLAG_BACK_EULER = 2; public CapacitorElm(int xx, int yy) { super(xx, yy); capacitance = 1e-5; } public CapacitorElm(int xa, int ya, int xb, int yb, int f, StringTokenizer st) { super(xa, ya, xb, yb, f); capacitance = new Double(st.nextToken()).doubleValue(); voltdiff = new Double(st.nextToken()).doubleValue(); } boolean isTrapezoidal() { return (flags & FLAG_BACK_EULER) == 0; } void setNodeVoltage(int n, double c) { super.setNodeVoltage(n, c); voltdiff = volts[0]-volts[1]; } void reset() { current = curcount = 0; // put small charge on caps when reset to start oscillators voltdiff = 1e-3; } int getDumpType() { return 'c'; } String dump() { return super.dump() + " " + capacitance + " " + voltdiff; } void setPoints() { super.setPoints(); double f = (dn/2-4)/dn; // calc leads lead1 = interpPoint(point1, point2, f); lead2 = interpPoint(point1, point2, 1-f); // calc plates plate1 = newPointArray(2); plate2 = newPointArray(2); interpPoint2(point1, point2, plate1[0], plate1[1], f, 12); interpPoint2(point1, point2, plate2[0], plate2[1], 1-f, 12); } void draw(Graphics g) { int hs = 12; setBbox(point1, point2, hs); // draw first lead and plate setVoltageColor(g, volts[0]); drawThickLine(g, point1, lead1); setPowerColor(g, false); drawThickLine(g, plate1[0], plate1[1]); if (sim.powerCheckItem.getState()) g.setColor(Color.gray); // draw second lead and plate setVoltageColor(g, volts[1]); drawThickLine(g, point2, lead2); setPowerColor(g, false); drawThickLine(g, plate2[0], plate2[1]); updateDotCount(); if (sim.dragElm != this) { drawDots(g, point1, lead1, curcount); drawDots(g, point2, lead2, -curcount); } drawPosts(g); if (sim.showValuesCheckItem.getState()) { String s = getShortUnitText(capacitance, "F"); drawValues(g, s, hs); } } void stamp() { // capacitor companion model using trapezoidal approximation // (Norton equivalent) consists of a current source in // parallel with a resistor. Trapezoidal is more accurate // than backward euler but can cause oscillatory behavior // if RC is small relative to the timestep. if (isTrapezoidal()) compResistance = sim.timeStep/(2*capacitance); else compResistance = sim.timeStep/capacitance; sim.stampResistor(nodes[0], nodes[1], compResistance); sim.stampRightSide(nodes[0]); sim.stampRightSide(nodes[1]); } void startIteration() { if (isTrapezoidal()) curSourceValue = -voltdiff/compResistance-current; else curSourceValue = -voltdiff/compResistance; //System.out.println("cap " + compResistance + " " + curSourceValue + " " + current + " " + voltdiff); } void calculateCurrent() { double voltdiff = volts[0] - volts[1]; // we check compResistance because this might get called // before stamp(), which sets compResistance, causing // infinite current if (compResistance > 0) current = voltdiff/compResistance + curSourceValue; } double curSourceValue; void doStep() { sim.stampCurrentSource(nodes[0], nodes[1], curSourceValue); } void getInfo(String arr[]) { arr[0] = "capacitor"; getBasicInfo(arr); arr[3] = "C = " + getUnitText(capacitance, "F"); arr[4] = "P = " + getUnitText(getPower(), "W"); //double v = getVoltageDiff(); //arr[4] = "U = " + getUnitText(.5*capacitance*v*v, "J"); } public EditInfo getEditInfo(int n) { if (n == 0) return new EditInfo("Capacitance (F)", capacitance, 0, 0); if (n == 1) { EditInfo ei = new EditInfo("", 0, -1, -1); ei.checkbox = new Checkbox("Trapezoidal Approximation", isTrapezoidal()); return ei; } return null; } public void setEditValue(int n, EditInfo ei) { if (n == 0 && ei.value > 0) capacitance = ei.value; if (n == 1) { if (ei.checkbox.getState()) flags &= ~FLAG_BACK_EULER; else flags |= FLAG_BACK_EULER; } } int getShortcut() { return 'c'; } } ChipElm.java import java.awt.*; import java.util.StringTokenizer; abstract class ChipElm extends CircuitElm { int csize, cspc, cspc2; int bits; final int FLAG_SMALL = 1; final int FLAG_FLIP_X = 1024; final int FLAG_FLIP_Y = 2048; public ChipElm(int xx, int yy) { super(xx, yy); if (needsBits()) bits = (this instanceof DecadeElm) ? 10 : 4; noDiagonal = true; setupPins(); setSize(sim.smallGridCheckItem.getState() ? 1 : 2); } public ChipElm(int xa, int ya, int xb, int yb, int f, StringTokenizer st) { super(xa, ya, xb, yb, f); if (needsBits()) bits = new Integer(st.nextToken()).intValue(); noDiagonal = true; setupPins(); setSize((f & FLAG_SMALL) != 0 ? 1 : 2); int i; for (i = 0; i != getPostCount(); i++) { if (pins[i].state) { volts[i] = new Double(st.nextToken()).doubleValue(); pins[i].value = volts[i] > 2.5; } } } boolean needsBits() { return false; } void setSize(int s) { csize = s; cspc = 8*s; cspc2 = cspc*2; flags &= ~FLAG_SMALL; flags |= (s == 1) ? FLAG_SMALL : 0; } abstract void setupPins(); void draw(Graphics g) { drawChip(g); } void drawChip(Graphics g) { int i; Font f = new Font("SansSerif", 0, 10*csize); g.setFont(f); FontMetrics fm = g.getFontMetrics(); for (i = 0; i != getPostCount(); i++) { Pin p = pins[i]; setVoltageColor(g, volts[i]); Point a = p.post; Point b = p.stub; drawThickLine(g, a, b); p.curcount = updateDotCount(p.current, p.curcount); drawDots(g, b, a, p.curcount); if (p.bubble) { g.setColor(sim.printableCheckItem.getState() ? Color.white : Color.black); drawThickCircle(g, p.bubbleX, p.bubbleY, 1); g.setColor(lightGrayColor); drawThickCircle(g, p.bubbleX, p.bubbleY, 3); } g.setColor(whiteColor); int sw = fm.stringWidth(p.text); g.drawString(p.text, p.textloc.x-sw/2, p.textloc.y+fm.getAscent()/2); if (p.lineOver) { int ya = p.textloc.y-fm.getAscent()/2; g.drawLine(p.textloc.x-sw/2, ya, p.textloc.x+sw/2, ya); } } g.setColor(needsHighlight() ? selectColor : lightGrayColor); drawThickPolygon(g, rectPointsX, rectPointsY, 4); if (clockPointsX != null) g.drawPolyline(clockPointsX, clockPointsY, 3); for (i = 0; i != getPostCount(); i++) drawPost(g, pins[i].post.x, pins[i].post.y, nodes[i]); } int rectPointsX[], rectPointsY[]; int clockPointsX[], clockPointsY[]; Pin pins[]; int sizeX, sizeY; boolean lastClock; void drag(int xx, int yy) { yy = sim.snapGrid(yy); if (xx < x) { xx = x; yy = y; } else { y = y2 = yy; x2 = sim.snapGrid(xx); } setPoints(); } void setPoints() { if (x2-x > sizeX*cspc2 && this == sim.dragElm) setSize(2); int hs = cspc; int x0 = x+cspc2; int y0 = y; int xr = x0-cspc; int yr = y0-cspc; int xs = sizeX*cspc2; int ys = sizeY*cspc2; rectPointsX = new int[] { xr, xr+xs, xr+xs, xr }; rectPointsY = new int[] { yr, yr, yr+ys, yr+ys }; setBbox(xr, yr, rectPointsX[2], rectPointsY[2]); int i; for (i = 0; i != getPostCount(); i++) { Pin p = pins[i]; switch (p.side) { case SIDE_N: p.setPoint(x0, y0, 1, 0, 0, -1, 0, 0); break; case SIDE_S: p.setPoint(x0, y0, 1, 0, 0, 1, 0, ys-cspc2);break; case SIDE_W: p.setPoint(x0, y0, 0, 1, -1, 0, 0, 0); break; case SIDE_E: p.setPoint(x0, y0, 0, 1, 1, 0, xs-cspc2, 0);break; } } } Point getPost(int n) { return pins[n].post; } abstract int getVoltageSourceCount(); // output count void setVoltageSource(int j, int vs) { int i; for (i = 0; i != getPostCount(); i++) { Pin p = pins[i]; if (p.output && j-- == 0) { p.voltSource = vs; return; } } System.out.println("setVoltageSource failed for " + this); } void stamp() { int i; for (i = 0; i != getPostCount(); i++) { Pin p = pins[i]; if (p.output) sim.stampVoltageSource(0, nodes[i], p.voltSource); } } void execute() {} void doStep() { int i; for (i = 0; i != getPostCount(); i++) { Pin p = pins[i]; if (!p.output) p.value = volts[i] > 2.5; } execute(); for (i = 0; i != getPostCount(); i++) { Pin p = pins[i]; if (p.output) sim.updateVoltageSource(0, nodes[i], p.voltSource, p.value ? 5 : 0); } } void reset() { int i; for (i = 0; i != getPostCount(); i++) { pins[i].value = false; pins[i].curcount = 0; volts[i] = 0; } lastClock = false; } String dump() { int t = getDumpType(); String s = super.dump(); if (needsBits()) s += " " + bits; int i; for (i = 0; i != getPostCount(); i++) { if (pins[i].state) s += " " + volts[i]; } return s; } void getInfo(String arr[]) { arr[0] = getChipName(); int i, a = 1; for (i = 0; i != getPostCount(); i++) { Pin p = pins[i]; if (arr[a] != null) arr[a] += "; "; else arr[a] = ""; String t = p.text; if (p.lineOver) t += '\''; if (p.clock) t = "Clk"; arr[a] += t + " = " + getVoltageText(volts[i]); if (i % 2 == 1) a++; } } void setCurrent(int x, double c) { int i; for (i = 0; i != getPostCount(); i++) if (pins[i].output && pins[i].voltSource == x) pins[i].current = c; } String getChipName() { return "chip"; } boolean getConnection(int n1, int n2) { return false; } boolean hasGroundConnection(int n1) { return pins[n1].output; } public EditInfo getEditInfo(int n) { if (n == 0) { EditInfo ei = new EditInfo("", 0, -1, -1); ei.checkbox = new Checkbox("Flip X", (flags & FLAG_FLIP_X) != 0); return ei; } if (n == 1) { EditInfo ei = new EditInfo("", 0, -1, -1); ei.checkbox = new Checkbox("Flip Y", (flags & FLAG_FLIP_Y) != 0); return ei; } return null; } public void setEditValue(int n, EditInfo ei) { if (n == 0) { if (ei.checkbox.getState()) flags |= FLAG_FLIP_X; else flags &= ~FLAG_FLIP_X; setPoints(); } if (n == 1) { if (ei.checkbox.getState()) flags |= FLAG_FLIP_Y; else flags &= ~FLAG_FLIP_Y; setPoints(); } } final int SIDE_N = 0; final int SIDE_S = 1; final int SIDE_W = 2; final int SIDE_E = 3; class Pin { Pin(int p, int s, String t) { pos = p; side = s; text = t; } Point post, stub; Point textloc; int pos, side, voltSource, bubbleX, bubbleY; String text; boolean lineOver, bubble, clock, output, value, state; double curcount, current; void setPoint(int px, int py, int dx, int dy, int dax, int day, int sx, int sy) { if ((flags & FLAG_FLIP_X) != 0) { dx = -dx; dax = -dax; px += cspc2*(sizeX-1); sx = -sx; } if ((flags & FLAG_FLIP_Y) != 0) { dy = -dy; day = -day; py += cspc2*(sizeY-1); sy = -sy; } int xa = px+cspc2*dx*pos+sx; int ya = py+cspc2*dy*pos+sy; post = new Point(xa+dax*cspc2, ya+day*cspc2); stub = new Point(xa+dax*cspc , ya+day*cspc ); textloc = new Point(xa , ya ); if (bubble) { bubbleX = xa+dax*10*csize; bubbleY = ya+day*10*csize; } if (clock) { clockPointsX = new int[3]; clockPointsY = new int[3]; clockPointsX[0] = xa+dax*cspc-dx*cspc/2; clockPointsY[0] = ya+day*cspc-dy*cspc/2; clockPointsX[1] = xa; clockPointsY[1] = ya; clockPointsX[2] = xa+dax*cspc+dx*cspc/2; clockPointsY[2] = ya+day*cspc+dy*cspc/2; } } } } CirSim.java // CirSim.java (c) 2010 by Paul Falstad // For information about the theory behind this, see Electronic Circuit & System Simulation Methods by Pillage import java.io.InputStream; import java.awt.*; import java.awt.image.*; import java.applet.Applet; import java.util.Vector; import java.io.File; import java.util.Random; import java.util.Arrays; import java.lang.Math; import java.net.URL; import java.awt.event.*; import java.io.FilterInputStream; import java.io.ByteArrayOutputStream; import java.util.StringTokenizer; import java.text.DecimalFormat; import java.text.NumberFormat; import java.lang.reflect.Constructor; import java.lang.reflect.Method; import java.net.URLDecoder; import java.net.URLEncoder; public class CirSim extends Frame implements ComponentListener, ActionListener, AdjustmentListener, MouseMotionListener, MouseListener, ItemListener, KeyListener { Thread engine = null; Dimension winSize; Image dbimage; Random random; public static final int sourceRadius = 7; public static final double freqMult = 3.14159265*2*4; public String getAppletInfo() { return "Circuit by Paul Falstad"; } static Container main; Label titleLabel; Button resetButton; Button dumpMatrixButton; MenuItem exportItem, exportLinkItem, importItem, exitItem, undoItem, redoItem, cutItem, copyItem, pasteItem, selectAllItem, optionsItem; Menu optionsMenu; Checkbox stoppedCheck; CheckboxMenuItem dotsCheckItem; CheckboxMenuItem voltsCheckItem; CheckboxMenuItem powerCheckItem; CheckboxMenuItem smallGridCheckItem; CheckboxMenuItem showValuesCheckItem; CheckboxMenuItem conductanceCheckItem; CheckboxMenuItem euroResistorCheckItem; CheckboxMenuItem printableCheckItem; CheckboxMenuItem conventionCheckItem; Scrollbar speedBar; Scrollbar currentBar; Label powerLabel; Scrollbar powerBar; PopupMenu elmMenu; MenuItem elmEditMenuItem; MenuItem elmCutMenuItem; MenuItem elmCopyMenuItem; MenuItem elmDeleteMenuItem; MenuItem elmScopeMenuItem; PopupMenu scopeMenu; PopupMenu transScopeMenu; PopupMenu mainMenu; CheckboxMenuItem scopeVMenuItem; CheckboxMenuItem scopeIMenuItem; CheckboxMenuItem scopeMaxMenuItem; CheckboxMenuItem scopeMinMenuItem; CheckboxMenuItem scopeFreqMenuItem; CheckboxMenuItem scopePowerMenuItem; CheckboxMenuItem scopeIbMenuItem; CheckboxMenuItem scopeIcMenuItem; CheckboxMenuItem scopeIeMenuItem; CheckboxMenuItem scopeVbeMenuItem; CheckboxMenuItem scopeVbcMenuItem; CheckboxMenuItem scopeVceMenuItem; CheckboxMenuItem scopeVIMenuItem; CheckboxMenuItem scopeXYMenuItem; CheckboxMenuItem scopeResistMenuItem; CheckboxMenuItem scopeVceIcMenuItem; MenuItem scopeSelectYMenuItem; Class addingClass; int mouseMode = MODE_SELECT; int tempMouseMode = MODE_SELECT; String mouseModeStr = "Select"; static final double pi = 3.14159265358979323846; static final int MODE_ADD_ELM = 0; static final int MODE_DRAG_ALL = 1; static final int MODE_DRAG_ROW = 2; static final int MODE_DRAG_COLUMN = 3; static final int MODE_DRAG_SELECTED = 4; static final int MODE_DRAG_POST = 5; static final int MODE_SELECT = 6; static final int infoWidth = 120; int dragX, dragY, initDragX, initDragY; int selectedSource; Rectangle selectedArea; int gridSize, gridMask, gridRound; boolean dragging; boolean analyzeFlag; boolean dumpMatrix; boolean useBufferedImage; boolean isMac; String ctrlMetaKey; double t; int pause = 10; int scopeSelected = -1; int menuScope = -1; int hintType = -1, hintItem1, hintItem2; String stopMessage; double timeStep; static final int HINT_LC = 1; static final int HINT_RC = 2; static final int HINT_3DB_C = 3; static final int HINT_TWINT = 4; static final int HINT_3DB_L = 5; Vector<CircuitElm> elmList; // Vector setupList; CircuitElm dragElm, menuElm, mouseElm, stopElm; boolean didSwitch = false; int mousePost = -1; CircuitElm plotXElm, plotYElm; int draggingPost; SwitchElm heldSwitchElm; double circuitMatrix[][], circuitRightSide[], origRightSide[], origMatrix[][]; RowInfo circuitRowInfo[]; int circuitPermute[]; boolean circuitNonLinear; int voltageSourceCount; int circuitMatrixSize, circuitMatrixFullSize; boolean circuitNeedsMap; public boolean useFrame; int scopeCount; Scope scopes[]; int scopeColCount[]; static EditDialog editDialog; static ImportExportDialog impDialog, expDialog; Class dumpTypes[], shortcuts[]; static String muString = "u"; static String ohmString = "ohm"; String clipboard; Rectangle circuitArea; int circuitBottom; Vector<String> undoStack, redoStack; int getrand(int x) { int q = random.nextInt(); if (q < 0) q = -q; return q % x; } CircuitCanvas cv; Circuit applet; CirSim(Circuit a) { super("Circuit Simulator v1.6i"); applet = a; useFrame = false; } String startCircuit = null; String startLabel = null; String startCircuitText = null; String baseURL = "http://www.falstad.com/circuit/"; public void init() { String euroResistor = null; String useFrameStr = null; boolean printable = false; boolean convention = true; CircuitElm.initClass(this); try { baseURL = applet.getDocumentBase().getFile(); // look for circuit embedded in URL String doc = applet.getDocumentBase().toString(); int in = doc.indexOf('#'); if (in > 0) { String x = null; try { x = doc.substring(in+1); x = URLDecoder.decode(x); startCircuitText = x; } catch (Exception e) { System.out.println("can't decode " + x); e.printStackTrace(); } } in = doc.lastIndexOf('/'); if (in > 0) baseURL = doc.substring(0, in+1); String param = applet.getParameter("PAUSE"); if (param != null) pause = Integer.parseInt(param); startCircuit = applet.getParameter("startCircuit"); startLabel = applet.getParameter("startLabel"); euroResistor = applet.getParameter("euroResistors"); useFrameStr = applet.getParameter("useFrame"); String x = applet.getParameter("whiteBackground"); if (x != null && x.equalsIgnoreCase("true")) printable = true; x = applet.getParameter("conventionalCurrent"); if (x != null && x.equalsIgnoreCase("true")) convention = false; } catch (Exception e) { } boolean euro = (euroResistor != null && euroResistor.equalsIgnoreCase("true")); useFrame = (useFrameStr == null || !useFrameStr.equalsIgnoreCase("false")); if (useFrame) main = this; else main = applet; String os = System.getProperty("os.name"); isMac = (os.indexOf("Mac ") == 0); ctrlMetaKey = (isMac) ? "\u2318" : "Ctrl"; String jv = System.getProperty("java.class.version"); double jvf = new Double(jv).doubleValue(); if (jvf >= 48) { muString = "\u03bc"; ohmString = "\u03a9"; useBufferedImage = true; } dumpTypes = new Class[300]; shortcuts = new Class[127]; // these characters are reserved dumpTypes[(int)'o'] = Scope.class; dumpTypes[(int)'h'] = Scope.class; dumpTypes[(int)'$'] = Scope.class; dumpTypes[(int)'%'] = Scope.class; dumpTypes[(int)'?'] = Scope.class; dumpTypes[(int)'B'] = Scope.class; main.setLayout(new CircuitLayout()); cv = new CircuitCanvas(this); cv.addComponentListener(this); cv.addMouseMotionListener(this); cv.addMouseListener(this); cv.addKeyListener(this); main.add(cv); mainMenu = new PopupMenu(); MenuBar mb = null; if (useFrame) mb = new MenuBar(); Menu m = new Menu("File"); if (useFrame) mb.add(m); else mainMenu.add(m); m.add(importItem = getMenuItem("Import")); m.add(exportItem = getMenuItem("Export")); m.add(exportLinkItem = getMenuItem("Export Link")); m.addSeparator(); m.add(exitItem = getMenuItem("Exit")); m = new Menu("Edit"); m.add(undoItem = getMenuItem("Undo")); undoItem.setShortcut(new MenuShortcut(KeyEvent.VK_Z)); m.add(redoItem = getMenuItem("Redo")); redoItem.setShortcut(new MenuShortcut(KeyEvent.VK_Z, true)); m.addSeparator(); m.add(cutItem = getMenuItem("Cut")); cutItem.setShortcut(new MenuShortcut(KeyEvent.VK_X)); m.add(copyItem = getMenuItem("Copy")); copyItem.setShortcut(new MenuShortcut(KeyEvent.VK_C)); m.add(pasteItem = getMenuItem("Paste")); pasteItem.setShortcut(new MenuShortcut(KeyEvent.VK_V)); pasteItem.setEnabled(false); m.add(selectAllItem = getMenuItem("Select All")); selectAllItem.setShortcut(new MenuShortcut(KeyEvent.VK_A)); if (useFrame) mb.add(m); else mainMenu.add(m); m = new Menu("Scope"); if (useFrame) mb.add(m); else mainMenu.add(m); m.add(getMenuItem("Stack All", "stackAll")); m.add(getMenuItem("Unstack All", "unstackAll")); optionsMenu = m = new Menu("Options"); if (useFrame) mb.add(m); else mainMenu.add(m); m.add(dotsCheckItem = getCheckItem("Show Current")); dotsCheckItem.setState(true); m.add(voltsCheckItem = getCheckItem("Show Voltage")); voltsCheckItem.setState(true); m.add(powerCheckItem = getCheckItem("Show Power")); m.add(showValuesCheckItem = getCheckItem("Show Values")); showValuesCheckItem.setState(true); //m.add(conductanceCheckItem = getCheckItem("Show Conductance")); m.add(smallGridCheckItem = getCheckItem("Small Grid")); m.add(euroResistorCheckItem = getCheckItem("European Resistors")); euroResistorCheckItem.setState(euro); m.add(printableCheckItem = getCheckItem("White Background")); printableCheckItem.setState(printable); m.add(conventionCheckItem = getCheckItem("Conventional Current Motion")); conventionCheckItem.setState(convention); m.add(optionsItem = getMenuItem("Other Options...")); Menu circuitsMenu = new Menu("Circuits"); if (useFrame) mb.add(circuitsMenu); else mainMenu.add(circuitsMenu); mainMenu.add(getClassCheckItem("Add Wire", "WireElm")); mainMenu.add(getClassCheckItem("Add Resistor", "ResistorElm")); Menu passMenu = new Menu("Passive Components"); mainMenu.add(passMenu); passMenu.add(getClassCheckItem("Add Capacitor", "CapacitorElm")); passMenu.add(getClassCheckItem("Add Inductor", "InductorElm")); passMenu.add(getClassCheckItem("Add Switch", "SwitchElm")); passMenu.add(getClassCheckItem("Add Push Switch", "PushSwitchElm")); passMenu.add(getClassCheckItem("Add SPDT Switch", "Switch2Elm")); passMenu.add(getClassCheckItem("Add Potentiometer", "PotElm")); passMenu.add(getClassCheckItem("Add Transformer", "TransformerElm")); passMenu.add(getClassCheckItem("Add Tapped Transformer", "TappedTransformerElm")); passMenu.add(getClassCheckItem("Add Transmission Line", "TransLineElm")); passMenu.add(getClassCheckItem("Add Relay", "RelayElm")); passMenu.add(getClassCheckItem("Add Memristor", "MemristorElm")); passMenu.add(getClassCheckItem("Add Spark Gap", "SparkGapElm")); Menu inputMenu = new Menu("Inputs/Outputs"); mainMenu.add(inputMenu); inputMenu.add(getClassCheckItem("Add Ground", "GroundElm")); inputMenu.add(getClassCheckItem("Add Voltage Source (2-terminal)", "DCVoltageElm")); inputMenu.add(getClassCheckItem("Add A/C Source (2-terminal)", "ACVoltageElm")); inputMenu.add(getClassCheckItem("Add Voltage Source (1-terminal)", "RailElm")); inputMenu.add(getClassCheckItem("Add A/C Source (1-terminal)", "ACRailElm")); inputMenu.add(getClassCheckItem("Add Square Wave (1-terminal)", "SquareRailElm")); inputMenu.add(getClassCheckItem("Add Analog Output", "OutputElm")); inputMenu.add(getClassCheckItem("Add Logic Input", "LogicInputElm")); inputMenu.add(getClassCheckItem("Add Logic Output", "LogicOutputElm")); inputMenu.add(getClassCheckItem("Add Clock", "ClockElm")); inputMenu.add(getClassCheckItem("Add A/C Sweep", "SweepElm")); inputMenu.add(getClassCheckItem("Add Var. Voltage", "VarRailElm")); inputMenu.add(getClassCheckItem("Add Antenna", "AntennaElm")); inputMenu.add(getClassCheckItem("Add AM source", "AMElm")); inputMenu.add(getClassCheckItem("Add FM source", "FMElm")); inputMenu.add(getClassCheckItem("Add Current Source", "CurrentElm")); inputMenu.add(getClassCheckItem("Add LED", "LEDElm")); inputMenu.add(getClassCheckItem("Add Lamp (beta)", "LampElm")); inputMenu.add(getClassCheckItem("Add LED Matrix", "LEDMatrixElm")); //inputMenu.add(getClassCheckItem("Add Microphone Input", "SignalInElm")); //inputMenu.add(getClassCheckItem("Add Speaker Output", "SignalOutElm")); Menu activeMenu = new Menu("Active Components"); mainMenu.add(activeMenu); activeMenu.add(getClassCheckItem("Add Diode", "DiodeElm")); activeMenu.add(getClassCheckItem("Add Zener Diode", "ZenerElm")); activeMenu.add(getClassCheckItem("Add Transistor (bipolar, NPN)", "NTransistorElm")); activeMenu.add(getClassCheckItem("Add Transistor (bipolar, PNP)", "PTransistorElm")); activeMenu.add(getClassCheckItem("Add Op Amp (- on top)", "OpAmpElm")); activeMenu.add(getClassCheckItem("Add Op Amp (+ on top)", "OpAmpSwapElm")); activeMenu.add(getClassCheckItem("Add MOSFET (n-channel)", "NMosfetElm")); activeMenu.add(getClassCheckItem("Add MOSFET (p-channel)", "PMosfetElm")); activeMenu.add(getClassCheckItem("Add JFET (n-channel)", "NJfetElm")); activeMenu.add(getClassCheckItem("Add JFET (p-channel)", "PJfetElm")); activeMenu.add(getClassCheckItem("Add Analog Switch (SPST)", "AnalogSwitchElm")); activeMenu.add(getClassCheckItem("Add Analog Switch (SPDT)", "AnalogSwitch2Elm")); activeMenu.add(getClassCheckItem("Add Tristate buffer", "TriStateElm")); activeMenu.add(getClassCheckItem("Add Schmitt Trigger", "SchmittElm")); activeMenu.add(getClassCheckItem("Add Schmitt Trigger (Inverting)", "InvertingSchmittElm")); activeMenu.add(getClassCheckItem("Add SCR", "SCRElm")); //activeMenu.add(getClassCheckItem("Add Varactor/Varicap", "VaractorElm")); activeMenu.add(getClassCheckItem("Add Tunnel Diode", "TunnelDiodeElm")); activeMenu.add(getClassCheckItem("Add Triode", "TriodeElm")); //activeMenu.add(getClassCheckItem("Add Diac", "DiacElm")); //activeMenu.add(getClassCheckItem("Add Triac", "TriacElm")); //activeMenu.add(getClassCheckItem("Add Photoresistor", "PhotoResistorElm")); //activeMenu.add(getClassCheckItem("Add Thermistor", "ThermistorElm")); activeMenu.add(getClassCheckItem("Add CCII+", "CC2Elm")); activeMenu.add(getClassCheckItem("Add CCII-", "CC2NegElm")); Menu gateMenu = new Menu("Logic Gates"); mainMenu.add(gateMenu); gateMenu.add(getClassCheckItem("Add Inverter", "InverterElm")); gateMenu.add(getClassCheckItem("Add NAND Gate", "NandGateElm")); gateMenu.add(getClassCheckItem("Add NOR Gate", "NorGateElm")); gateMenu.add(getClassCheckItem("Add AND Gate", "AndGateElm")); gateMenu.add(getClassCheckItem("Add OR Gate", "OrGateElm")); gateMenu.add(getClassCheckItem("Add XOR Gate", "XorGateElm")); Menu chipMenu = new Menu("Chips"); mainMenu.add(chipMenu); chipMenu.add(getClassCheckItem("Add D Flip-Flop", "DFlipFlopElm")); chipMenu.add(getClassCheckItem("Add JK Flip-Flop", "JKFlipFlopElm")); chipMenu.add(getClassCheckItem("Add T Flip-Flop", "TFlipFlopElm")); chipMenu.add(getClassCheckItem("Add 7 Segment LED", "SevenSegElm")); chipMenu.add(getClassCheckItem("Add 7 Segment Decoder", "SevenSegDecoderElm")); chipMenu.add(getClassCheckItem("Add Multiplexer", "MultiplexerElm")); chipMenu.add(getClassCheckItem("Add Demultiplexer", "DeMultiplexerElm")); chipMenu.add(getClassCheckItem("Add SIPO shift register", "SipoShiftElm")); chipMenu.add(getClassCheckItem("Add PISO shift register", "PisoShiftElm")); chipMenu.add(getClassCheckItem("Add Phase Comparator", "PhaseCompElm")); chipMenu.add(getClassCheckItem("Add Counter", "CounterElm")); chipMenu.add(getClassCheckItem("Add Decade Counter", "DecadeElm")); chipMenu.add(getClassCheckItem("Add 555 Timer", "TimerElm")); chipMenu.add(getClassCheckItem("Add DAC", "DACElm")); chipMenu.add(getClassCheckItem("Add ADC", "ADCElm")); chipMenu.add(getClassCheckItem("Add Latch", "LatchElm")); //chipMenu.add(getClassCheckItem("Add Static RAM", "SRAMElm")); chipMenu.add(getClassCheckItem("Add Sequence generator", "SeqGenElm")); chipMenu.add(getClassCheckItem("Add VCO", "VCOElm")); chipMenu.add(getClassCheckItem("Add Full Adder", "FullAdderElm")); chipMenu.add(getClassCheckItem("Add Half Adder", "HalfAdderElm")); chipMenu.add(getClassCheckItem("Add Monostable", "MonostableElm")); Menu otherMenu = new Menu("Other"); mainMenu.add(otherMenu); otherMenu.add(getClassCheckItem("Add Text", "TextElm")); otherMenu.add(getClassCheckItem("Add Box", "BoxElm")); otherMenu.add(getClassCheckItem("Add Scope Probe", "ProbeElm")); otherMenu.add(getCheckItem("Drag All (Alt-drag)", "DragAll")); otherMenu.add(getCheckItem( isMac ? "Drag Row (Alt-S-drag, S-right)" : "Drag Row (S-right)", "DragRow")); otherMenu.add(getCheckItem( isMac ? "Drag Column (Alt-\u2318-drag, \u2318-right)" : "Drag Column (C-right)", "DragColumn")); otherMenu.add(getCheckItem("Drag Selected", "DragSelected")); otherMenu.add(getCheckItem("Drag Post (" + ctrlMetaKey + "-drag)", "DragPost")); mainMenu.add(getCheckItem("Select/Drag Selected (space or Shift-drag)", "Select")); main.add(mainMenu); main.add(resetButton = new Button("Reset")); resetButton.addActionListener(this); dumpMatrixButton = new Button("Dump Matrix"); //main.add(dumpMatrixButton); dumpMatrixButton.addActionListener(this); stoppedCheck = new Checkbox("Stopped"); stoppedCheck.addItemListener(this); main.add(stoppedCheck); main.add(new Label("Simulation Speed", Label.CENTER)); // was max of 140 main.add(speedBar = new Scrollbar(Scrollbar.HORIZONTAL, 3, 1, 0, 260)); speedBar.addAdjustmentListener(this); main.add(new Label("Current Speed", Label.CENTER)); currentBar = new Scrollbar(Scrollbar.HORIZONTAL, 50, 1, 1, 100); currentBar.addAdjustmentListener(this); main.add(currentBar); main.add(powerLabel = new Label("Power Brightness", Label.CENTER)); main.add(powerBar = new Scrollbar(Scrollbar.HORIZONTAL, 50, 1, 1, 100)); powerBar.addAdjustmentListener(this); powerBar.disable(); powerLabel.disable(); main.add(new Label("www.falstad.com")); if (useFrame) main.add(new Label("")); Font f = new Font("SansSerif", 0, 10); Label l; l = new Label("Current Circuit:"); l.setFont(f); titleLabel = new Label("Label"); titleLabel.setFont(f); if (useFrame) { main.add(l); main.add(titleLabel); } setGrid(); elmList = new Vector<CircuitElm>(); // setupList = new Vector(); undoStack = new Vector<String>(); redoStack = new Vector<String>(); scopes = new Scope[20]; scopeColCount = new int[20]; scopeCount = 0; random = new Random(); cv.setBackground(Color.black); cv.setForeground(Color.lightGray); elmMenu = new PopupMenu(); elmMenu.add(elmEditMenuItem = getMenuItem("Edit")); elmMenu.add(elmScopeMenuItem = getMenuItem("View in Scope")); elmMenu.add(elmCutMenuItem = getMenuItem("Cut")); elmMenu.add(elmCopyMenuItem = getMenuItem("Copy")); elmMenu.add(elmDeleteMenuItem = getMenuItem("Delete")); main.add(elmMenu); scopeMenu = buildScopeMenu(false); transScopeMenu = buildScopeMenu(true); getSetupList(circuitsMenu, false); if (useFrame) setMenuBar(mb); if (startCircuitText != null) readSetup(startCircuitText); else if (stopMessage == null && startCircuit != null) readSetupFile(startCircuit, startLabel); else readSetup(null, 0, false); if (useFrame) { Dimension screen = getToolkit().getScreenSize(); resize(860, 640); handleResize(); Dimension x = getSize(); setLocation((screen.width - x.width)/2, (screen.height - x.height)/2); show(); } else { if (!powerCheckItem.getState()) { main.remove(powerBar); main.remove(powerLabel); main.validate(); } hide(); handleResize(); applet.validate(); } requestFocus(); addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent we) { destroyFrame(); } } ); } boolean shown = false; public void triggerShow() { if (!shown) show(); shown = true; } public void requestFocus() { super.requestFocus(); cv.requestFocus(); } PopupMenu buildScopeMenu(boolean t) { PopupMenu m = new PopupMenu(); m.add(getMenuItem("Remove", "remove")); m.add(getMenuItem("Speed 2x", "speed2")); m.add(getMenuItem("Speed 1/2x", "speed1/2")); m.add(getMenuItem("Scale 2x", "scale")); m.add(getMenuItem("Max Scale", "maxscale")); m.add(getMenuItem("Stack", "stack")); m.add(getMenuItem("Unstack", "unstack")); m.add(getMenuItem("Reset", "reset")); if (t) { m.add(scopeIbMenuItem = getCheckItem("Show Ib")); m.add(scopeIcMenuItem = getCheckItem("Show Ic")); m.add(scopeIeMenuItem = getCheckItem("Show Ie")); m.add(scopeVbeMenuItem = getCheckItem("Show Vbe")); m.add(scopeVbcMenuItem = getCheckItem("Show Vbc")); m.add(scopeVceMenuItem = getCheckItem("Show Vce")); m.add(scopeVceIcMenuItem = getCheckItem("Show Vce vs Ic")); } else { m.add(scopeVMenuItem = getCheckItem("Show Voltage")); m.add(scopeIMenuItem = getCheckItem("Show Current")); m.add(scopePowerMenuItem = getCheckItem("Show Power Consumed")); m.add(scopeMaxMenuItem = getCheckItem("Show Peak Value")); m.add(scopeMinMenuItem = getCheckItem("Show Negative Peak Value")); m.add(scopeFreqMenuItem = getCheckItem("Show Frequency")); m.add(scopeVIMenuItem = getCheckItem("Show V vs I")); m.add(scopeXYMenuItem = getCheckItem("Plot X/Y")); m.add(scopeSelectYMenuItem = getMenuItem("Select Y", "selecty")); m.add(scopeResistMenuItem = getCheckItem("Show Resistance")); } main.add(m); return m; } MenuItem getMenuItem(String s) { MenuItem mi = new MenuItem(s); mi.addActionListener(this); return mi; } MenuItem getMenuItem(String s, String ac) { MenuItem mi = new MenuItem(s); mi.setActionCommand(ac); mi.addActionListener(this); return mi; } CheckboxMenuItem getCheckItem(String s) { CheckboxMenuItem mi = new CheckboxMenuItem(s); mi.addItemListener(this); mi.setActionCommand(""); return mi; } CheckboxMenuItem getClassCheckItem(String s, String t) { try { Class c = Class.forName(t); CircuitElm elm = constructElement(c, 0, 0); register(c, elm); if ( elm.needsShortcut() ) { s += " (" + (char)elm.getShortcut() + ")"; } elm.delete(); } catch (Exception ee) { ee.printStackTrace(); } return getCheckItem(s, t); } CheckboxMenuItem getCheckItem(String s, String t) { CheckboxMenuItem mi = new CheckboxMenuItem(s); mi.addItemListener(this); mi.setActionCommand(t); return mi; } void register(Class c, CircuitElm elm) { int t = elm.getDumpType(); if (t == 0) { System.out.println("no dump type: " + c); return; } int s = elm.getShortcut(); if ( elm.needsShortcut() && s == 0 ) { if ( s == 0 ) { System.err.println("no shortcut " + c + " for " + c); return; } else if ( s <= ' ' || s >= 127 ) { System.err.println("invalid shortcut " + c + " for " + c); return; } } Class dclass = elm.getDumpClass(); if ( dumpTypes[t] != null && dumpTypes[t] != dclass ) { System.out.println("dump type conflict: " + c + " " + dumpTypes[t]); return; } dumpTypes[t] = dclass; Class sclass = elm.getClass(); if ( elm.needsShortcut() && shortcuts[s] != null && shortcuts[s] != sclass ) { System.err.println("shortcut conflict: " + c + " (previously assigned to " + shortcuts[s] + ")"); } else { shortcuts[s] = sclass; } } void handleResize() { winSize = cv.getSize(); if (winSize.width == 0) return; dbimage = main.createImage(winSize.width, winSize.height); int h = winSize.height / 5; /*if (h < 128 && winSize.height > 300) h = 128;*/ circuitArea = new Rectangle(0, 0, winSize.width, winSize.height-h); int i; int minx = 1000, maxx = 0, miny = 1000, maxy = 0; for (i = 0; i != elmList.size(); i++) { CircuitElm ce = getElm(i); // centered text causes problems when trying to center the circuit, // so we special-case it here if (!ce.isCenteredText()) { minx = min(ce.x, min(ce.x2, minx)); maxx = max(ce.x, max(ce.x2, maxx)); } miny = min(ce.y, min(ce.y2, miny)); maxy = max(ce.y, max(ce.y2, maxy)); } // center circuit; we don't use snapGrid() because that rounds int dx = gridMask & ((circuitArea.width -(maxx-minx))/2-minx); int dy = gridMask & ((circuitArea.height-(maxy-miny))/2-miny); if (dx+minx < 0) dx = gridMask & (-minx); if (dy+miny < 0) dy = gridMask & (-miny); for (i = 0; i != elmList.size(); i++) { CircuitElm ce = getElm(i); ce.move(dx, dy); } // after moving elements, need this to avoid singular matrix probs needAnalyze(); circuitBottom = 0; } void destroyFrame() { if (applet == null) { dispose(); System.exit(0); } else { applet.destroyFrame(); } } public boolean handleEvent(Event ev) { if (ev.id == Event.WINDOW_DESTROY) { destroyFrame(); return true; } return super.handleEvent(ev); } public void paint(Graphics g) { cv.repaint(); } static final int resct = 6; long lastTime = 0, lastFrameTime, lastIterTime, secTime = 0; int frames = 0; int steps = 0; int framerate = 0, steprate = 0; public void updateCircuit(Graphics realg) { CircuitElm realMouseElm; if (winSize == null || winSize.width == 0) return; if (analyzeFlag) { analyzeCircuit(); analyzeFlag = false; } if (editDialog != null && editDialog.elm instanceof CircuitElm) mouseElm = (CircuitElm) (editDialog.elm); realMouseElm = mouseElm; if (mouseElm == null) mouseElm = stopElm; setupScopes(); Graphics2D g = null; // hausen: changed to Graphics2D g = (Graphics2D)dbimage.getGraphics(); g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); CircuitElm.selectColor = Color.cyan; if (printableCheckItem.getState()) { CircuitElm.whiteColor = Color.black; CircuitElm.lightGrayColor = Color.black; g.setColor(Color.white); } else { CircuitElm.whiteColor = Color.white; CircuitElm.lightGrayColor = Color.lightGray; g.setColor(Color.black); } g.fillRect(0, 0, winSize.width, winSize.height); if (!stoppedCheck.getState()) { try { runCircuit(); } catch (Exception e) { e.printStackTrace(); analyzeFlag = true; cv.repaint(); return; } } if (!stoppedCheck.getState()) { long sysTime = System.currentTimeMillis(); if (lastTime != 0) { int inc = (int) (sysTime-lastTime); double c = currentBar.getValue(); c = java.lang.Math.exp(c/3.5-14.2); CircuitElm.currentMult = 1.7 * inc * c; if (!conventionCheckItem.getState()) CircuitElm.currentMult = -CircuitElm.currentMult; } if (sysTime-secTime >= 1000) { framerate = frames; steprate = steps; frames = 0; steps = 0; secTime = sysTime; } lastTime = sysTime; } else lastTime = 0; CircuitElm.powerMult = Math.exp(powerBar.getValue()/4.762-7); int i; Font oldfont = g.getFont(); for (i = 0; i != elmList.size(); i++) { if (powerCheckItem.getState()) g.setColor(Color.gray); /*else if (conductanceCheckItem.getState()) g.setColor(Color.white);*/ getElm(i).draw(g); } if (tempMouseMode == MODE_DRAG_ROW || tempMouseMode == MODE_DRAG_COLUMN || tempMouseMode == MODE_DRAG_POST || tempMouseMode == MODE_DRAG_SELECTED) for (i = 0; i != elmList.size(); i++) { CircuitElm ce = getElm(i); ce.drawPost(g, ce.x , ce.y ); ce.drawPost(g, ce.x2, ce.y2); } int badnodes = 0; // find bad connections, nodes not connected to other elements which // intersect other elements' bounding boxes // debugged by hausen: nullPointerException if ( nodeList != null ) for (i = 0; i != nodeList.size(); i++) { CircuitNode cn = getCircuitNode(i); if (!cn.internal && cn.links.size() == 1) { int bb = 0, j; CircuitNodeLink cnl = cn.links.elementAt(0); for (j = 0; j != elmList.size(); j++) { // TODO: (hausen) see if this change does not break stuff CircuitElm ce = getElm(j); if ( ce instanceof GraphicElm ) continue; if (cnl.elm != ce && getElm(j).boundingBox.contains(cn.x, cn.y)) bb++; } if (bb > 0) { g.setColor(Color.red); g.fillOval(cn.x-3, cn.y-3, 7, 7); badnodes++; } } } /*if (mouseElm != null) { g.setFont(oldfont); g.drawString("+", mouseElm.x+10, mouseElm.y); }*/ if (dragElm != null && (dragElm.x != dragElm.x2 || dragElm.y != dragElm.y2)) dragElm.draw(g); g.setFont(oldfont); int ct = scopeCount; if (stopMessage != null) ct = 0; for (i = 0; i != ct; i++) scopes[i].draw(g); g.setColor(CircuitElm.whiteColor); if (stopMessage != null) { g.drawString(stopMessage, 10, circuitArea.height); } else { if (circuitBottom == 0) calcCircuitBottom(); String info[] = new String[10]; if (mouseElm != null) { if (mousePost == -1) mouseElm.getInfo(info); else info[0] = "V = " + CircuitElm.getUnitText(mouseElm.getPostVoltage(mousePost), "V"); /* //shownodes for (i = 0; i != mouseElm.getPostCount(); i++) info[0] += " " + mouseElm.nodes[i]; if (mouseElm.getVoltageSourceCount() > 0) info[0] += ";" + (mouseElm.getVoltageSource()+nodeList.size()); */ } else { CircuitElm.showFormat.setMinimumFractionDigits(2); info[0] = "t = " + CircuitElm.getUnitText(t, "s"); CircuitElm.showFormat.setMinimumFractionDigits(0); } if (hintType != -1) { for (i = 0; info[i] != null; i++) ; String s = getHint(); if (s == null) hintType = -1; else info[i] = s; } int x = 0; if (ct != 0) x = scopes[ct-1].rightEdge() + 20; x = max(x, winSize.width*2/3); // count lines of data for (i = 0; info[i] != null; i++) ; if (badnodes > 0) info[i++] = badnodes + ((badnodes == 1) ? " bad connection" : " bad connections"); // find where to show data; below circuit, not too high unless we need it int ybase = winSize.height-15*i-5; ybase = min(ybase, circuitArea.height); ybase = max(ybase, circuitBottom); for (i = 0; info[i] != null; i++) g.drawString(info[i], x, ybase+15*(i+1)); } if (selectedArea != null) { g.setColor(CircuitElm.selectColor); g.drawRect(selectedArea.x, selectedArea.y, selectedArea.width, selectedArea.height); } mouseElm = realMouseElm; frames++; /* g.setColor(Color.white); g.drawString("Framerate: " + framerate, 10, 10); g.drawString("Steprate: " + steprate, 10, 30); g.drawString("Steprate/iter: " + (steprate/getIterCount()), 10, 50); g.drawString("iterc: " + (getIterCount()), 10, 70); */ realg.drawImage(dbimage, 0, 0, this); if (!stoppedCheck.getState() && circuitMatrix != null) { // Limit to 50 fps (thanks to Jurgen Klotzer for this) long delay = 1000/50 - (System.currentTimeMillis() - lastFrameTime); //realg.drawString("delay: " + delay, 10, 90); if (delay > 0) { try { Thread.sleep(delay); } catch (InterruptedException e) { } } cv.repaint(0); } lastFrameTime = lastTime; } void setupScopes() { int i; // check scopes to make sure the elements still exist, and remove // unused scopes/columns int pos = -1; for (i = 0; i < scopeCount; i++) { if (locateElm(scopes[i].elm) < 0) scopes[i].setElm(null); if (scopes[i].elm == null) { int j; for (j = i; j != scopeCount; j++) scopes[j] = scopes[j+1]; scopeCount--; i--; continue; } if (scopes[i].position > pos+1) scopes[i].position = pos+1; pos = scopes[i].position; } while (scopeCount > 0 && scopes[scopeCount-1].elm == null) scopeCount--; int h = winSize.height - circuitArea.height; pos = 0; for (i = 0; i != scopeCount; i++) scopeColCount[i] = 0; for (i = 0; i != scopeCount; i++) { pos = max(scopes[i].position, pos); scopeColCount[scopes[i].position]++; } int colct = pos+1; int iw = infoWidth; if (colct <= 2) iw = iw*3/2; int w = (winSize.width-iw) / colct; int marg = 10; if (w < marg*2) w = marg*2; pos = -1; int colh = 0; int row = 0; int speed = 0; for (i = 0; i != scopeCount; i++) { Scope s = scopes[i]; if (s.position > pos) { pos = s.position; colh = h / scopeColCount[pos]; row = 0; speed = s.speed; } if (s.speed != speed) { s.speed = speed; s.resetGraph(); } Rectangle r = new Rectangle(pos*w, winSize.height-h+colh*row, w-marg, colh); row++; if (!r.equals(s.rect)) s.setRect(r); } } String getHint() { CircuitElm c1 = getElm(hintItem1); CircuitElm c2 = getElm(hintItem2); if (c1 == null || c2 == null) return null; if (hintType == HINT_LC) { if (!(c1 instanceof InductorElm)) return null; if (!(c2 instanceof CapacitorElm)) return null; InductorElm ie = (InductorElm) c1; CapacitorElm ce = (CapacitorElm) c2; return "res.f = " + CircuitElm.getUnitText(1/(2*pi*Math.sqrt(ie.inductance* ce.capacitance)), "Hz"); } if (hintType == HINT_RC) { if (!(c1 instanceof ResistorElm)) return null; if (!(c2 instanceof CapacitorElm)) return null; ResistorElm re = (ResistorElm) c1; CapacitorElm ce = (CapacitorElm) c2; return "RC = " + CircuitElm.getUnitText(re.resistance*ce.capacitance, "s"); } if (hintType == HINT_3DB_C) { if (!(c1 instanceof ResistorElm)) return null; if (!(c2 instanceof CapacitorElm)) return null; ResistorElm re = (ResistorElm) c1; CapacitorElm ce = (CapacitorElm) c2; return "f.3db = " + CircuitElm.getUnitText(1/(2*pi*re.resistance*ce.capacitance), "Hz"); } if (hintType == HINT_3DB_L) { if (!(c1 instanceof ResistorElm)) return null; if (!(c2 instanceof InductorElm)) return null; ResistorElm re = (ResistorElm) c1; InductorElm ie = (InductorElm) c2; return "f.3db = " + CircuitElm.getUnitText(re.resistance/(2*pi*ie.inductance), "Hz"); } if (hintType == HINT_TWINT) { if (!(c1 instanceof ResistorElm)) return null; if (!(c2 instanceof CapacitorElm)) return null; ResistorElm re = (ResistorElm) c1; CapacitorElm ce = (CapacitorElm) c2; return "fc = " + CircuitElm.getUnitText(1/(2*pi*re.resistance*ce.capacitance), "Hz"); } return null; } public void toggleSwitch(int n) { int i; for (i = 0; i != elmList.size(); i++) { CircuitElm ce = getElm(i); if (ce instanceof SwitchElm) { n--; if (n == 0) { ((SwitchElm) ce).toggle(); analyzeFlag = true; cv.repaint(); return; } } } } void needAnalyze() { analyzeFlag = true; cv.repaint(); } Vector<CircuitNode> nodeList; CircuitElm voltageSources[]; public CircuitNode getCircuitNode(int n) { if (n >= nodeList.size()) return null; return nodeList.elementAt(n); } public CircuitElm getElm(int n) { if (n >= elmList.size()) return null; return elmList.elementAt(n); } void analyzeCircuit() { calcCircuitBottom(); if (elmList.isEmpty()) return; stopMessage = null; stopElm = null; int i, j; int vscount = 0; nodeList = new Vector<CircuitNode>(); boolean gotGround = false; boolean gotRail = false; CircuitElm volt = null; //System.out.println("ac1"); // look for voltage or ground element for (i = 0; i != elmList.size(); i++) { CircuitElm ce = getElm(i); if (ce instanceof GroundElm) { gotGround = true; break; } if (ce instanceof RailElm) gotRail = true; if (volt == null && ce instanceof VoltageElm) volt = ce; } // if no ground, and no rails, then the voltage elm's first terminal // is ground if (!gotGround && volt != null && !gotRail) { CircuitNode cn = new CircuitNode(); Point pt = volt.getPost(0); cn.x = pt.x; cn.y = pt.y; nodeList.addElement(cn); } else { // otherwise allocate extra node for ground CircuitNode cn = new CircuitNode(); cn.x = cn.y = -1; nodeList.addElement(cn); } //System.out.println("ac2"); // allocate nodes and voltage sources for (i = 0; i != elmList.size(); i++) { CircuitElm ce = getElm(i); int inodes = ce.getInternalNodeCount(); int ivs = ce.getVoltageSourceCount(); int posts = ce.getPostCount(); // allocate a node for each post and match posts to nodes for (j = 0; j != posts; j++) { Point pt = ce.getPost(j); int k; for (k = 0; k != nodeList.size(); k++) { CircuitNode cn = getCircuitNode(k); if (pt.x == cn.x && pt.y == cn.y) break; } if (k == nodeList.size()) { CircuitNode cn = new CircuitNode(); cn.x = pt.x; cn.y = pt.y; CircuitNodeLink cnl = new CircuitNodeLink(); cnl.num = j; cnl.elm = ce; cn.links.addElement(cnl); ce.setNode(j, nodeList.size()); nodeList.addElement(cn); } else { CircuitNodeLink cnl = new CircuitNodeLink(); cnl.num = j; cnl.elm = ce; getCircuitNode(k).links.addElement(cnl); ce.setNode(j, k); // if it's the ground node, make sure the node voltage is 0, // cause it may not get set later if (k == 0) ce.setNodeVoltage(j, 0); } } for (j = 0; j != inodes; j++) { CircuitNode cn = new CircuitNode(); cn.x = cn.y = -1; cn.internal = true; CircuitNodeLink cnl = new CircuitNodeLink(); cnl.num = j+posts; cnl.elm = ce; cn.links.addElement(cnl); ce.setNode(cnl.num, nodeList.size()); nodeList.addElement(cn); } vscount += ivs; } voltageSources = new CircuitElm[vscount]; vscount = 0; circuitNonLinear = false; //System.out.println("ac3"); // determine if circuit is nonlinear for (i = 0; i != elmList.size(); i++) { CircuitElm ce = getElm(i); if (ce.nonLinear()) circuitNonLinear = true; int ivs = ce.getVoltageSourceCount(); for (j = 0; j != ivs; j++) { voltageSources[vscount] = ce; ce.setVoltageSource(j, vscount++); } } voltageSourceCount = vscount; int matrixSize = nodeList.size()-1 + vscount; circuitMatrix = new double[matrixSize][matrixSize]; circuitRightSide = new double[matrixSize]; origMatrix = new double[matrixSize][matrixSize]; origRightSide = new double[matrixSize]; circuitMatrixSize = circuitMatrixFullSize = matrixSize; circuitRowInfo = new RowInfo[matrixSize]; circuitPermute = new int[matrixSize]; int vs = 0; for (i = 0; i != matrixSize; i++) circuitRowInfo[i] = new RowInfo(); circuitNeedsMap = false; // stamp linear circuit elements for (i = 0; i != elmList.size(); i++) { CircuitElm ce = getElm(i); ce.stamp(); } //System.out.println("ac4"); // determine nodes that are unconnected boolean closure[] = new boolean[nodeList.size()]; boolean tempclosure[] = new boolean[nodeList.size()]; boolean changed = true; closure[0] = true; while (changed) { changed = false; for (i = 0; i != elmList.size(); i++) { CircuitElm ce = getElm(i); // loop through all ce's nodes to see if they are connected // to other nodes not in closure for (j = 0; j < ce.getPostCount(); j++) { if (!closure[ce.getNode(j)]) { if (ce.hasGroundConnection(j)) closure[ce.getNode(j)] = changed = true; continue; } int k; for (k = 0; k != ce.getPostCount(); k++) { if (j == k) continue; int kn = ce.getNode(k); if (ce.getConnection(j, k) && !closure[kn]) { closure[kn] = true; changed = true; } } } } if (changed) continue; // connect unconnected nodes for (i = 0; i != nodeList.size(); i++) if (!closure[i] && !getCircuitNode(i).internal) { System.out.println("node " + i + " unconnected"); stampResistor(0, i, 1e8); closure[i] = true; changed = true; break; } } //System.out.println("ac5"); for (i = 0; i != elmList.size(); i++) { CircuitElm ce = getElm(i); // look for inductors with no current path if (ce instanceof InductorElm) { FindPathInfo fpi = new FindPathInfo(FindPathInfo.INDUCT, ce, ce.getNode(1)); // first try findPath with maximum depth of 5, to avoid slowdowns if (!fpi.findPath(ce.getNode(0), 5) && !fpi.findPath(ce.getNode(0))) { System.out.println(ce + " no path"); ce.reset(); } } // look for current sources with no current path if (ce instanceof CurrentElm) { FindPathInfo fpi = new FindPathInfo(FindPathInfo.INDUCT, ce, ce.getNode(1)); if (!fpi.findPath(ce.getNode(0))) { stop("No path for current source!", ce); return; } } // look for voltage source loops if ((ce instanceof VoltageElm && ce.getPostCount() == 2) || ce instanceof WireElm) { FindPathInfo fpi = new FindPathInfo(FindPathInfo.VOLTAGE, ce, ce.getNode(1)); if (fpi.findPath(ce.getNode(0))) { stop("Voltage source/wire loop with no resistance!", ce); return; } } // look for shorted caps, or caps w/ voltage but no R if (ce instanceof CapacitorElm) { FindPathInfo fpi = new FindPathInfo(FindPathInfo.SHORT, ce, ce.getNode(1)); if (fpi.findPath(ce.getNode(0))) { System.out.println(ce + " shorted"); ce.reset(); } else { fpi = new FindPathInfo(FindPathInfo.CAP_V, ce, ce.getNode(1)); if (fpi.findPath(ce.getNode(0))) { stop("Capacitor loop with no resistance!", ce); return; } } } } //System.out.println("ac6"); // simplify the matrix; this speeds things up quite a bit for (i = 0; i != matrixSize; i++) { int qm = -1, qp = -1; double qv = 0; RowInfo re = circuitRowInfo[i]; /*System.out.println("row " + i + " " + re.lsChanges + " " + re.rsChanges + " " + re.dropRow);*/ if (re.lsChanges || re.dropRow || re.rsChanges) continue; double rsadd = 0; // look for rows that can be removed for (j = 0; j != matrixSize; j++) { double q = circuitMatrix[i][j]; if (circuitRowInfo[j].type == RowInfo.ROW_CONST) { // keep a running total of const values that have been // removed already rsadd -= circuitRowInfo[j].value*q; continue; } if (q == 0) continue; if (qp == -1) { qp = j; qv = q; continue; } if (qm == -1 && q == -qv) { qm = j; continue; } break; } //System.out.println("line " + i + " " + qp + " " + qm + " " + j); /*if (qp != -1 && circuitRowInfo[qp].lsChanges) { System.out.println("lschanges"); continue; } if (qm != -1 && circuitRowInfo[qm].lsChanges) { System.out.println("lschanges"); continue; }*/ if (j == matrixSize) { if (qp == -1) { stop("Matrix error", null); return; } RowInfo elt = circuitRowInfo[qp]; if (qm == -1) { // we found a row with only one nonzero entry; that value // is a constant int k; for (k = 0; elt.type == RowInfo.ROW_EQUAL && k < 100; k++) { // follow the chain /*System.out.println("following equal chain from " + i + " " + qp + " to " + elt.nodeEq);*/ qp = elt.nodeEq; elt = circuitRowInfo[qp]; } if (elt.type == RowInfo.ROW_EQUAL) { // break equal chains //System.out.println("Break equal chain"); elt.type = RowInfo.ROW_NORMAL; continue; } if (elt.type != RowInfo.ROW_NORMAL) { System.out.println("type already " + elt.type + " for " + qp + "!"); continue; } elt.type = RowInfo.ROW_CONST; elt.value = (circuitRightSide[i]+rsadd)/qv; circuitRowInfo[i].dropRow = true; //System.out.println(qp + " * " + qv + " = const " + elt.value); i = -1; // start over from scratch } else if (circuitRightSide[i]+rsadd == 0) { // we found a row with only two nonzero entries, and one // is the negative of the other; the values are equal if (elt.type != RowInfo.ROW_NORMAL) { //System.out.println("swapping"); int qq = qm; qm = qp; qp = qq; elt = circuitRowInfo[qp]; if (elt.type != RowInfo.ROW_NORMAL) { // we should follow the chain here, but this // hardly ever happens so it's not worth worrying // about System.out.println("swap failed"); continue; } } elt.type = RowInfo.ROW_EQUAL; elt.nodeEq = qm; circuitRowInfo[i].dropRow = true; //System.out.println(qp + " = " + qm); } } } //System.out.println("ac7"); // find size of new matrix int nn = 0; for (i = 0; i != matrixSize; i++) { RowInfo elt = circuitRowInfo[i]; if (elt.type == RowInfo.ROW_NORMAL) { elt.mapCol = nn++; //System.out.println("col " + i + " maps to " + elt.mapCol); continue; } if (elt.type == RowInfo.ROW_EQUAL) { RowInfo e2 = null; // resolve chains of equality; 100 max steps to avoid loops for (j = 0; j != 100; j++) { e2 = circuitRowInfo[elt.nodeEq]; if (e2.type != RowInfo.ROW_EQUAL) break; if (i == e2.nodeEq) break; elt.nodeEq = e2.nodeEq; } } if (elt.type == RowInfo.ROW_CONST) elt.mapCol = -1; } for (i = 0; i != matrixSize; i++) { RowInfo elt = circuitRowInfo[i]; if (elt.type == RowInfo.ROW_EQUAL) { RowInfo e2 = circuitRowInfo[elt.nodeEq]; if (e2.type == RowInfo.ROW_CONST) { // if something is equal to a const, it's a const elt.type = e2.type; elt.value = e2.value; elt.mapCol = -1; //System.out.println(i + " = [late]const " + elt.value); } else { elt.mapCol = e2.mapCol; //System.out.println(i + " maps to: " + e2.mapCol); } } } //System.out.println("ac8"); /*System.out.println("matrixSize = " + matrixSize); for (j = 0; j != circuitMatrixSize; j++) { System.out.println(j + ": "); for (i = 0; i != circuitMatrixSize; i++) System.out.print(circuitMatrix[j][i] + " "); System.out.print(" " + circuitRightSide[j] + "\n"); } System.out.print("\n");*/ // make the new, simplified matrix int newsize = nn; double newmatx[][] = new double[newsize][newsize]; double newrs [] = new double[newsize]; int ii = 0; for (i = 0; i != matrixSize; i++) { RowInfo rri = circuitRowInfo[i]; if (rri.dropRow) { rri.mapRow = -1; continue; } newrs[ii] = circuitRightSide[i]; rri.mapRow = ii; //System.out.println("Row " + i + " maps to " + ii); for (j = 0; j != matrixSize; j++) { RowInfo ri = circuitRowInfo[j]; if (ri.type == RowInfo.ROW_CONST) newrs[ii] -= ri.value*circuitMatrix[i][j]; else newmatx[ii][ri.mapCol] += circuitMatrix[i][j]; } ii++; } circuitMatrix = newmatx; circuitRightSide = newrs; matrixSize = circuitMatrixSize = newsize; for (i = 0; i != matrixSize; i++) origRightSide[i] = circuitRightSide[i]; for (i = 0; i != matrixSize; i++) for (j = 0; j != matrixSize; j++) origMatrix[i][j] = circuitMatrix[i][j]; circuitNeedsMap = true; /* System.out.println("matrixSize = " + matrixSize + " " + circuitNonLinear); for (j = 0; j != circuitMatrixSize; j++) { for (i = 0; i != circuitMatrixSize; i++) System.out.print(circuitMatrix[j][i] + " "); System.out.print(" " + circuitRightSide[j] + "\n"); } System.out.print("\n");*/ // if a matrix is linear, we can do the lu_factor here instead of // needing to do it every frame if (!circuitNonLinear) { if (!lu_factor(circuitMatrix, circuitMatrixSize, circuitPermute)) { stop("Singular matrix!", null); return; } } } void calcCircuitBottom() { int i; circuitBottom = 0; for (i = 0; i != elmList.size(); i++) { Rectangle rect = getElm(i).boundingBox; int bottom = rect.height + rect.y; if (bottom > circuitBottom) circuitBottom = bottom; } } class FindPathInfo { static final int INDUCT = 1; static final int VOLTAGE = 2; static final int SHORT = 3; static final int CAP_V = 4; boolean used[]; int dest; CircuitElm firstElm; int type; FindPathInfo(int t, CircuitElm e, int d) { dest = d; type = t; firstElm = e; used = new boolean[nodeList.size()]; } boolean findPath(int n1) { return findPath(n1, -1); } boolean findPath(int n1, int depth) { if (n1 == dest) return true; if (depth-- == 0) return false; if (used[n1]) { //System.out.println("used " + n1); return false; } used[n1] = true; int i; for (i = 0; i != elmList.size(); i++) { CircuitElm ce = getElm(i); if (ce == firstElm) continue; if (type == INDUCT) { if (ce instanceof CurrentElm) continue; } if (type == VOLTAGE) { if (!(ce.isWire() || ce instanceof VoltageElm)) continue; } if (type == SHORT && !ce.isWire()) continue; if (type == CAP_V) { if (!(ce.isWire() || ce instanceof CapacitorElm || ce instanceof VoltageElm)) continue; } if (n1 == 0) { // look for posts which have a ground connection; // our path can go through ground int j; for (j = 0; j != ce.getPostCount(); j++) if (ce.hasGroundConnection(j) && findPath(ce.getNode(j), depth)) { used[n1] = false; return true; } } int j; for (j = 0; j != ce.getPostCount(); j++) { //System.out.println(ce + " " + ce.getNode(j)); if (ce.getNode(j) == n1) break; } if (j == ce.getPostCount()) continue; if (ce.hasGroundConnection(j) && findPath(0, depth)) { //System.out.println(ce + " has ground"); used[n1] = false; return true; } if (type == INDUCT && ce instanceof InductorElm) { double c = ce.getCurrent(); if (j == 0) c = -c; //System.out.println("matching " + c + " to " + firstElm.getCurrent()); //System.out.println(ce + " " + firstElm); if (Math.abs(c-firstElm.getCurrent()) > 1e-10) continue; } int k; for (k = 0; k != ce.getPostCount(); k++) { if (j == k) continue; //System.out.println(ce + " " + ce.getNode(j) + "-" + ce.getNode(k)); if (ce.getConnection(j, k) && findPath(ce.getNode(k), depth)) { //System.out.println("got findpath " + n1); used[n1] = false; return true; } //System.out.println("back on findpath " + n1); } } used[n1] = false; //System.out.println(n1 + " failed"); return false; } } void stop(String s, CircuitElm ce) { stopMessage = s; circuitMatrix = null; stopElm = ce; stoppedCheck.setState(true); analyzeFlag = false; cv.repaint(); } // control voltage source vs with voltage from n1 to n2 (must // also call stampVoltageSource()) void stampVCVS(int n1, int n2, double coef, int vs) { int vn = nodeList.size()+vs; stampMatrix(vn, n1, coef); stampMatrix(vn, n2, -coef); } // stamp independent voltage source #vs, from n1 to n2, amount v void stampVoltageSource(int n1, int n2, int vs, double v) { int vn = nodeList.size()+vs; stampMatrix(vn, n1, -1); stampMatrix(vn, n2, 1); stampRightSide(vn, v); stampMatrix(n1, vn, 1); stampMatrix(n2, vn, -1); } // use this if the amount of voltage is going to be updated in doStep() void stampVoltageSource(int n1, int n2, int vs) { int vn = nodeList.size()+vs; stampMatrix(vn, n1, -1); stampMatrix(vn, n2, 1); stampRightSide(vn); stampMatrix(n1, vn, 1); stampMatrix(n2, vn, -1); } void updateVoltageSource(int n1, int n2, int vs, double v) { int vn = nodeList.size()+vs; stampRightSide(vn, v); } void stampResistor(int n1, int n2, double r) { double r0 = 1/r; if (Double.isNaN(r0) || Double.isInfinite(r0)) { System.out.print("bad resistance " + r + " " + r0 + "\n"); int a = 0; a /= a; } stampMatrix(n1, n1, r0); stampMatrix(n2, n2, r0); stampMatrix(n1, n2, -r0); stampMatrix(n2, n1, -r0); } void stampConductance(int n1, int n2, double r0) { stampMatrix(n1, n1, r0); stampMatrix(n2, n2, r0); stampMatrix(n1, n2, -r0); stampMatrix(n2, n1, -r0); } // current from cn1 to cn2 is equal to voltage from vn1 to 2, divided by g void stampVCCurrentSource(int cn1, int cn2, int vn1, int vn2, double g) { stampMatrix(cn1, vn1, g); stampMatrix(cn2, vn2, g); stampMatrix(cn1, vn2, -g); stampMatrix(cn2, vn1, -g); } void stampCurrentSource(int n1, int n2, double i) { stampRightSide(n1, -i); stampRightSide(n2, i); } // stamp a current source from n1 to n2 depending on current through vs void stampCCCS(int
Compartilhar