separate disjunct portions of circuit
This commit is contained in:
parent
4a335353b9
commit
a4d8f9cb2a
@ -10,8 +10,10 @@ import lombok.NonNull;
|
|||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.apache.commons.math3.linear.*;
|
import org.apache.commons.math3.linear.*;
|
||||||
|
|
||||||
import java.util.Collections;
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
import static java.lang.Math.max;
|
import static java.lang.Math.max;
|
||||||
|
|
||||||
@ -19,11 +21,15 @@ import static java.lang.Math.max;
|
|||||||
@Getter
|
@Getter
|
||||||
public class Calculation {
|
public class Calculation {
|
||||||
|
|
||||||
private static final double NO_RESISTANCE = 1e-12;
|
public static final double NO_RESISTANCE = 1e-12;
|
||||||
|
|
||||||
private static final double FULL_ADMITTANCE = 1 / NO_RESISTANCE;
|
private static final double FULL_ADMITTANCE = 1 / NO_RESISTANCE;
|
||||||
|
|
||||||
private final List<Junction> junctions;
|
private final List<Junction> junctions = new ArrayList<>();
|
||||||
|
|
||||||
|
private final Set<Part> parts = new HashSet<>();
|
||||||
|
|
||||||
|
private final Set<Wire> wires = new HashSet<>();
|
||||||
|
|
||||||
private final RealMatrix matrix;
|
private final RealMatrix matrix;
|
||||||
|
|
||||||
@ -31,29 +37,49 @@ public class Calculation {
|
|||||||
|
|
||||||
private RealVector potentials = null;
|
private RealVector potentials = null;
|
||||||
|
|
||||||
|
public static List<Calculation> calculate(final Circuit circuit) {
|
||||||
|
final List<Calculation> calculations = new ArrayList<>();
|
||||||
|
final List<PartBattery> batteries = new ArrayList<>(circuit.streamParts().flatMap(PartBattery::filterCast).toList());
|
||||||
|
while (!batteries.isEmpty()) {
|
||||||
|
final PartBattery pivot = batteries.removeFirst();
|
||||||
|
final Set<Junction> connectedJunctions = new HashSet<>();
|
||||||
|
pivot.getPlus().collectConnectedJunctions(connectedJunctions);
|
||||||
|
pivot.getMinus().collectConnectedJunctions(connectedJunctions);
|
||||||
|
connectedJunctions.stream().map(Junction::getOwner).flatMap(PartBattery::filterCast).forEach(batteries::remove);
|
||||||
|
calculations.add(new Calculation(connectedJunctions, pivot));
|
||||||
|
}
|
||||||
|
return calculations;
|
||||||
|
}
|
||||||
|
|
||||||
public Calculation(final int numNodes) {
|
public Calculation(final int numNodes) {
|
||||||
junctions = Collections.emptyList();
|
|
||||||
matrix = new Array2DRowRealMatrix(numNodes, numNodes);
|
matrix = new Array2DRowRealMatrix(numNodes, numNodes);
|
||||||
currents = new ArrayRealVector(numNodes);
|
currents = new ArrayRealVector(numNodes);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Calculation(final Circuit circuit) {
|
private Calculation(final Set<Junction> connectedJunctions, final PartBattery pivot) {
|
||||||
final PartBattery pivot = circuit.streamParts().flatMap(PartBattery::filterCast).findFirst().orElseThrow(RuntimeException::new);
|
for (final Junction junction : connectedJunctions) {
|
||||||
junctions = circuit.streamJunctions().filter(junction -> junction != pivot.getMinus()).toList(); // pivot.minus is GND and cannot be part of the matrix (linear dependency)
|
parts.add(junction.getOwner());
|
||||||
matrix = new Array2DRowRealMatrix(junctions.size(), junctions.size());
|
if (!junctions.contains(junction) && junction != pivot.getMinus()) {
|
||||||
currents = new ArrayRealVector(junctions.size());
|
// pivot.minus is GND and cannot be part of the matrix (linear dependency)
|
||||||
fromSchematic(circuit);
|
this.junctions.add(junction);
|
||||||
|
}
|
||||||
|
wires.addAll(junction.getWires());
|
||||||
|
}
|
||||||
|
|
||||||
|
matrix = new Array2DRowRealMatrix(this.junctions.size(), this.junctions.size());
|
||||||
|
currents = new ArrayRealVector(this.junctions.size());
|
||||||
|
fromSchematic();
|
||||||
solve();
|
solve();
|
||||||
toSchematic(circuit);
|
toSchematic();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void fromSchematic(final Circuit circuit) {
|
private void fromSchematic() {
|
||||||
circuit.streamWires().forEach(
|
wires.forEach(
|
||||||
wire -> addResistor(wire.getA(), wire.getB(), NO_RESISTANCE)
|
wire -> addResistor(wire.getA(), wire.getB(), NO_RESISTANCE)
|
||||||
);
|
);
|
||||||
circuit.streamParts().forEach(part -> {
|
parts.forEach(part -> {
|
||||||
for (final InnerConnection innerConnection : part.getInnerConnections()) {
|
for (final InnerConnection innerConnection : part.getInnerConnections()) {
|
||||||
addResistor(innerConnection.a, innerConnection.b, NO_RESISTANCE);
|
addResistor(innerConnection.a, innerConnection.b, innerConnection.resistance);
|
||||||
}
|
}
|
||||||
if (part instanceof final PartBattery battery) {
|
if (part instanceof final PartBattery battery) {
|
||||||
addBattery(battery);
|
addBattery(battery);
|
||||||
@ -63,10 +89,12 @@ public class Calculation {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private void toSchematic(final Circuit circuit) {
|
private void toSchematic() {
|
||||||
circuit.streamJunctions().forEach(junction -> junction.setVoltage(getPotential(junction)));
|
wires.forEach(wire -> wire.setCurrent(getCurrent(wire)));
|
||||||
circuit.streamWires().forEach(wire -> wire.setCurrent(getCurrent(wire)));
|
parts.forEach(part -> {
|
||||||
circuit.streamParts().forEach(Part::postCalculate);
|
part.getJunctions().forEach(junction -> junction.setVoltage(getPotential(junction)));
|
||||||
|
part.postCalculate();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private double getPotential(final @NonNull Junction junction) {
|
private double getPotential(final @NonNull Junction junction) {
|
||||||
|
|||||||
@ -17,8 +17,6 @@ public class Circuit {
|
|||||||
|
|
||||||
private final List<Part> parts = new ArrayList<>();
|
private final List<Part> parts = new ArrayList<>();
|
||||||
|
|
||||||
private final List<Junction> junctions = new ArrayList<>();
|
|
||||||
|
|
||||||
private final List<Wire> wires = new ArrayList<>();
|
private final List<Wire> wires = new ArrayList<>();
|
||||||
|
|
||||||
public Circuit(final CircuitDto dto) {
|
public Circuit(final CircuitDto dto) {
|
||||||
@ -42,7 +40,7 @@ public class Circuit {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void evaluateAndRender() {
|
public void evaluateAndRender() {
|
||||||
new Calculation(this);
|
Calculation.calculate(this);
|
||||||
parts.forEach(Part::render);
|
parts.forEach(Part::render);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -52,7 +50,6 @@ public class Circuit {
|
|||||||
}
|
}
|
||||||
if (isFree(part.getPosition())) {
|
if (isFree(part.getPosition())) {
|
||||||
parts.add(part);
|
parts.add(part);
|
||||||
junctions.addAll(part.getJunctions());
|
|
||||||
part.render();
|
part.render();
|
||||||
}
|
}
|
||||||
return part;
|
return part;
|
||||||
@ -75,10 +72,6 @@ public class Circuit {
|
|||||||
return parts.stream();
|
return parts.stream();
|
||||||
}
|
}
|
||||||
|
|
||||||
public Stream<Junction> streamJunctions() {
|
|
||||||
return junctions.stream();
|
|
||||||
}
|
|
||||||
|
|
||||||
public Stream<Wire> streamWires() {
|
public Stream<Wire> streamWires() {
|
||||||
return wires.stream();
|
return wires.stream();
|
||||||
}
|
}
|
||||||
|
|||||||
@ -17,19 +17,10 @@ public class CircuitPanel extends JPanel {
|
|||||||
|
|
||||||
public CircuitPanel() {
|
public CircuitPanel() {
|
||||||
new CircuitPanelDropTarget(this, circuit);
|
new CircuitPanelDropTarget(this, circuit);
|
||||||
final PartBattery battery = circuit.addPart(new PartBattery(Position.ofRaster(1, 0)));
|
final PartBattery battery = circuit.addPart(new PartBattery(Position.ofRaster(0, 0)));
|
||||||
|
final PartLight light = circuit.addPart(new PartLight(Position.ofRaster(0, 1)));
|
||||||
final PartLight light0 = circuit.addPart(new PartLight(Position.ofRaster(0, 2)));
|
circuit.connect(battery.getMinus(), light.getA());
|
||||||
light0.clockwise();
|
circuit.connect(light.getB(), battery.getPlus());
|
||||||
|
|
||||||
final PartLight light1 = circuit.addPart(new PartLight(Position.ofRaster(1, 2)));
|
|
||||||
light1.clockwise();
|
|
||||||
light1.clockwise();
|
|
||||||
light1.clockwise();
|
|
||||||
|
|
||||||
circuit.connect(battery.getMinus(), light0.getA());
|
|
||||||
circuit.connect(light0.getB(), light1.getA());
|
|
||||||
circuit.connect(light1.getB(), battery.getPlus());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@ -1,14 +1,28 @@
|
|||||||
package de.ph87.electro.circuit.part;
|
package de.ph87.electro.circuit.part;
|
||||||
|
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
public class InnerConnection {
|
public class InnerConnection {
|
||||||
|
|
||||||
public final Junction a;
|
public final Junction a;
|
||||||
|
|
||||||
public final Junction b;
|
public final Junction b;
|
||||||
|
|
||||||
public InnerConnection(final Junction a, final Junction b) {
|
public final double resistance;
|
||||||
|
|
||||||
|
public InnerConnection(final Junction a, final Junction b, final double resistance) {
|
||||||
this.a = a;
|
this.a = a;
|
||||||
this.b = b;
|
this.b = b;
|
||||||
|
this.resistance = resistance;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Stream<Junction> filter(final Junction junction) {
|
||||||
|
if (a == junction) {
|
||||||
|
return Stream.of(b);
|
||||||
|
} else if (b == junction) {
|
||||||
|
return Stream.of(a);
|
||||||
|
}
|
||||||
|
return Stream.empty();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -74,4 +74,13 @@ public class Junction {
|
|||||||
return this.position.distance(position) <= JUNCTION_RADIUS_HOVER;
|
return this.position.distance(position) <= JUNCTION_RADIUS_HOVER;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void collectConnectedJunctions(final Set<Junction> connected) {
|
||||||
|
if (connected.contains(this)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
connected.add(this);
|
||||||
|
wires.forEach(wire -> wire.getOpposite(this).collectConnectedJunctions(connected));
|
||||||
|
owner.getInnerConnections().stream().flatMap(innerConnection -> innerConnection.filter(this)).forEach(opposite -> opposite.collectConnectedJunctions(connected));
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -110,6 +110,10 @@ public abstract class Part {
|
|||||||
// may be overwritten
|
// may be overwritten
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public List<InnerConnection> getInnerConnections() {
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
|
||||||
public static Part of(final PartDto abstractDto) {
|
public static Part of(final PartDto abstractDto) {
|
||||||
return switch (abstractDto) {
|
return switch (abstractDto) {
|
||||||
case final PartBatteryDto dto -> new PartBattery(dto);
|
case final PartBatteryDto dto -> new PartBattery(dto);
|
||||||
@ -124,8 +128,4 @@ public abstract class Part {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<InnerConnection> getInnerConnections() {
|
|
||||||
return Collections.emptyList();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -45,8 +45,8 @@ public class PartBattery extends Part {
|
|||||||
|
|
||||||
public PartBattery(final Position position) {
|
public PartBattery(final Position position) {
|
||||||
super("Batterie", position);
|
super("Batterie", position);
|
||||||
minus = newJunction(this, "PLUS", P10, P50);
|
minus = newJunction(this, "MINUS", P10, P50);
|
||||||
plus = newJunction(this, "MINUS", P90, P50);
|
plus = newJunction(this, "PLUS", P90, P50);
|
||||||
}
|
}
|
||||||
|
|
||||||
public PartBattery(final PartBatteryDto dto) {
|
public PartBattery(final PartBatteryDto dto) {
|
||||||
|
|||||||
@ -1,13 +1,12 @@
|
|||||||
package de.ph87.electro.circuit.part.parts;
|
package de.ph87.electro.circuit.part.parts;
|
||||||
|
|
||||||
import de.ph87.electro.circuit.part.Junction;
|
import de.ph87.electro.circuit.part.*;
|
||||||
import de.ph87.electro.circuit.part.Orientation;
|
|
||||||
import de.ph87.electro.circuit.part.PartOther;
|
|
||||||
import de.ph87.electro.circuit.part.Position;
|
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import lombok.ToString;
|
import lombok.ToString;
|
||||||
|
|
||||||
import java.awt.*;
|
import java.awt.*;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
import static de.ph87.electro.CONFIG.*;
|
import static de.ph87.electro.CONFIG.*;
|
||||||
import static java.lang.Math.abs;
|
import static java.lang.Math.abs;
|
||||||
@ -115,4 +114,12 @@ public class PartLight extends PartOther {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<InnerConnection> getInnerConnections() {
|
||||||
|
if (defect) {
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
return List.of(new InnerConnection(a, b, resistance));
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -12,6 +12,7 @@ import java.awt.*;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import static de.ph87.electro.CONFIG.*;
|
import static de.ph87.electro.CONFIG.*;
|
||||||
|
import static de.ph87.electro.circuit.Calculation.NO_RESISTANCE;
|
||||||
|
|
||||||
@Getter
|
@Getter
|
||||||
@ToString(callSuper = true)
|
@ToString(callSuper = true)
|
||||||
@ -59,7 +60,7 @@ public class PartSwitch1x1 extends PartOther {
|
|||||||
@Override
|
@Override
|
||||||
public List<InnerConnection> getInnerConnections() {
|
public List<InnerConnection> getInnerConnections() {
|
||||||
if (state) {
|
if (state) {
|
||||||
return List.of(new InnerConnection(common, output));
|
return List.of(new InnerConnection(common, output, NO_RESISTANCE));
|
||||||
}
|
}
|
||||||
return super.getInnerConnections();
|
return super.getInnerConnections();
|
||||||
}
|
}
|
||||||
|
|||||||
@ -11,6 +11,7 @@ import lombok.ToString;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import static de.ph87.electro.CONFIG.*;
|
import static de.ph87.electro.CONFIG.*;
|
||||||
|
import static de.ph87.electro.circuit.Calculation.NO_RESISTANCE;
|
||||||
|
|
||||||
@Getter
|
@Getter
|
||||||
@ToString(callSuper = true)
|
@ToString(callSuper = true)
|
||||||
@ -61,9 +62,9 @@ public class PartSwitch1x2 extends PartOther {
|
|||||||
@Override
|
@Override
|
||||||
public List<InnerConnection> getInnerConnections() {
|
public List<InnerConnection> getInnerConnections() {
|
||||||
if (state) {
|
if (state) {
|
||||||
return List.of(new InnerConnection(common, output1));
|
return List.of(new InnerConnection(common, output1, NO_RESISTANCE));
|
||||||
}
|
}
|
||||||
return List.of(new InnerConnection(common, output0));
|
return List.of(new InnerConnection(common, output0, NO_RESISTANCE));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -11,6 +11,7 @@ import lombok.ToString;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import static de.ph87.electro.CONFIG.*;
|
import static de.ph87.electro.CONFIG.*;
|
||||||
|
import static de.ph87.electro.circuit.Calculation.NO_RESISTANCE;
|
||||||
|
|
||||||
@Getter
|
@Getter
|
||||||
@ToString(callSuper = true)
|
@ToString(callSuper = true)
|
||||||
@ -68,13 +69,13 @@ public class PartSwitchCross extends PartOther {
|
|||||||
public List<InnerConnection> getInnerConnections() {
|
public List<InnerConnection> getInnerConnections() {
|
||||||
if (state) {
|
if (state) {
|
||||||
return List.of(
|
return List.of(
|
||||||
new InnerConnection(common0, output1),
|
new InnerConnection(common0, output1, NO_RESISTANCE),
|
||||||
new InnerConnection(common1, output0)
|
new InnerConnection(common1, output0, NO_RESISTANCE)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
return List.of(
|
return List.of(
|
||||||
new InnerConnection(common0, output0),
|
new InnerConnection(common0, output0, NO_RESISTANCE),
|
||||||
new InnerConnection(common1, output1)
|
new InnerConnection(common1, output1, NO_RESISTANCE)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -20,21 +20,21 @@ class CalculationServiceTest {
|
|||||||
circuit.connect(battery.getMinus(), light.getA());
|
circuit.connect(battery.getMinus(), light.getA());
|
||||||
circuit.connect(battery.getPlus(), light.getB());
|
circuit.connect(battery.getPlus(), light.getB());
|
||||||
|
|
||||||
final Calculation calculation = new Calculation(circuit);
|
for (final Calculation calculation : Calculation.calculate(circuit)) {
|
||||||
|
calculation.toString().lines().forEach(log::info);
|
||||||
calculation.toString().lines().forEach(log::info);
|
circuit.streamParts().forEach(part -> {
|
||||||
circuit.streamParts().forEach(part -> {
|
log.info("");
|
||||||
log.info("");
|
log.info(part.toString());
|
||||||
log.info(part.toString());
|
for (final Junction junction : part.getJunctions()) {
|
||||||
for (final Junction junction : part.getJunctions()) {
|
log.info(" \"%s\" = %.2f V".formatted(junction.getName(), junction.getVoltage()));
|
||||||
log.info(" \"%s\" = %.2f V".formatted(junction.getName(), junction.getVoltage()));
|
for (final Wire wire : junction.getWires()) {
|
||||||
for (final Wire wire : junction.getWires()) {
|
final Junction opposite = wire.getOpposite(junction);
|
||||||
final Junction opposite = wire.getOpposite(junction);
|
log.info(" -> %s.%s = %.2f A".formatted(opposite.getOwner().getName(), opposite.getName(), wire.getCurrent(junction)));
|
||||||
log.info(" -> %s.%s = %.2f A".formatted(opposite.getOwner().getName(), opposite.getName(), wire.getCurrent(junction)));
|
}
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
});
|
log.info("");
|
||||||
log.info("");
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user