separate disjunct portions of circuit

This commit is contained in:
Patrick Haßel 2024-05-22 13:43:46 +02:00
parent 4a335353b9
commit a4d8f9cb2a
12 changed files with 117 additions and 72 deletions

View File

@ -10,8 +10,10 @@ import lombok.NonNull;
import lombok.extern.slf4j.Slf4j;
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.Set;
import static java.lang.Math.max;
@ -19,11 +21,15 @@ import static java.lang.Math.max;
@Getter
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 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;
@ -31,29 +37,49 @@ public class Calculation {
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) {
junctions = Collections.emptyList();
matrix = new Array2DRowRealMatrix(numNodes, numNodes);
currents = new ArrayRealVector(numNodes);
}
public Calculation(final Circuit circuit) {
final PartBattery pivot = circuit.streamParts().flatMap(PartBattery::filterCast).findFirst().orElseThrow(RuntimeException::new);
junctions = circuit.streamJunctions().filter(junction -> junction != pivot.getMinus()).toList(); // pivot.minus is GND and cannot be part of the matrix (linear dependency)
matrix = new Array2DRowRealMatrix(junctions.size(), junctions.size());
currents = new ArrayRealVector(junctions.size());
fromSchematic(circuit);
private Calculation(final Set<Junction> connectedJunctions, final PartBattery pivot) {
for (final Junction junction : connectedJunctions) {
parts.add(junction.getOwner());
if (!junctions.contains(junction) && junction != pivot.getMinus()) {
// pivot.minus is GND and cannot be part of the matrix (linear dependency)
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();
toSchematic(circuit);
toSchematic();
}
private void fromSchematic(final Circuit circuit) {
circuit.streamWires().forEach(
private void fromSchematic() {
wires.forEach(
wire -> addResistor(wire.getA(), wire.getB(), NO_RESISTANCE)
);
circuit.streamParts().forEach(part -> {
parts.forEach(part -> {
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) {
addBattery(battery);
@ -63,10 +89,12 @@ public class Calculation {
});
}
private void toSchematic(final Circuit circuit) {
circuit.streamJunctions().forEach(junction -> junction.setVoltage(getPotential(junction)));
circuit.streamWires().forEach(wire -> wire.setCurrent(getCurrent(wire)));
circuit.streamParts().forEach(Part::postCalculate);
private void toSchematic() {
wires.forEach(wire -> wire.setCurrent(getCurrent(wire)));
parts.forEach(part -> {
part.getJunctions().forEach(junction -> junction.setVoltage(getPotential(junction)));
part.postCalculate();
});
}
private double getPotential(final @NonNull Junction junction) {

View File

@ -17,8 +17,6 @@ public class Circuit {
private final List<Part> parts = new ArrayList<>();
private final List<Junction> junctions = new ArrayList<>();
private final List<Wire> wires = new ArrayList<>();
public Circuit(final CircuitDto dto) {
@ -42,7 +40,7 @@ public class Circuit {
}
public void evaluateAndRender() {
new Calculation(this);
Calculation.calculate(this);
parts.forEach(Part::render);
}
@ -52,7 +50,6 @@ public class Circuit {
}
if (isFree(part.getPosition())) {
parts.add(part);
junctions.addAll(part.getJunctions());
part.render();
}
return part;
@ -75,10 +72,6 @@ public class Circuit {
return parts.stream();
}
public Stream<Junction> streamJunctions() {
return junctions.stream();
}
public Stream<Wire> streamWires() {
return wires.stream();
}

View File

@ -17,19 +17,10 @@ public class CircuitPanel extends JPanel {
public CircuitPanel() {
new CircuitPanelDropTarget(this, circuit);
final PartBattery battery = circuit.addPart(new PartBattery(Position.ofRaster(1, 0)));
final PartLight light0 = circuit.addPart(new PartLight(Position.ofRaster(0, 2)));
light0.clockwise();
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());
final PartBattery battery = circuit.addPart(new PartBattery(Position.ofRaster(0, 0)));
final PartLight light = circuit.addPart(new PartLight(Position.ofRaster(0, 1)));
circuit.connect(battery.getMinus(), light.getA());
circuit.connect(light.getB(), battery.getPlus());
}
@Override

View File

@ -1,14 +1,28 @@
package de.ph87.electro.circuit.part;
import java.util.stream.Stream;
public class InnerConnection {
public final Junction a;
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.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();
}
}

View File

@ -74,4 +74,13 @@ public class Junction {
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));
}
}

View File

@ -110,6 +110,10 @@ public abstract class Part {
// may be overwritten
}
public List<InnerConnection> getInnerConnections() {
return Collections.emptyList();
}
public static Part of(final PartDto abstractDto) {
return switch (abstractDto) {
case final PartBatteryDto dto -> new PartBattery(dto);
@ -124,8 +128,4 @@ public abstract class Part {
};
}
public List<InnerConnection> getInnerConnections() {
return Collections.emptyList();
}
}

View File

@ -45,8 +45,8 @@ public class PartBattery extends Part {
public PartBattery(final Position position) {
super("Batterie", position);
minus = newJunction(this, "PLUS", P10, P50);
plus = newJunction(this, "MINUS", P90, P50);
minus = newJunction(this, "MINUS", P10, P50);
plus = newJunction(this, "PLUS", P90, P50);
}
public PartBattery(final PartBatteryDto dto) {

View File

@ -1,13 +1,12 @@
package de.ph87.electro.circuit.part.parts;
import de.ph87.electro.circuit.part.Junction;
import de.ph87.electro.circuit.part.Orientation;
import de.ph87.electro.circuit.part.PartOther;
import de.ph87.electro.circuit.part.Position;
import de.ph87.electro.circuit.part.*;
import lombok.Getter;
import lombok.ToString;
import java.awt.*;
import java.util.Collections;
import java.util.List;
import static de.ph87.electro.CONFIG.*;
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));
}
}

View File

@ -12,6 +12,7 @@ import java.awt.*;
import java.util.List;
import static de.ph87.electro.CONFIG.*;
import static de.ph87.electro.circuit.Calculation.NO_RESISTANCE;
@Getter
@ToString(callSuper = true)
@ -59,7 +60,7 @@ public class PartSwitch1x1 extends PartOther {
@Override
public List<InnerConnection> getInnerConnections() {
if (state) {
return List.of(new InnerConnection(common, output));
return List.of(new InnerConnection(common, output, NO_RESISTANCE));
}
return super.getInnerConnections();
}

View File

@ -11,6 +11,7 @@ import lombok.ToString;
import java.util.List;
import static de.ph87.electro.CONFIG.*;
import static de.ph87.electro.circuit.Calculation.NO_RESISTANCE;
@Getter
@ToString(callSuper = true)
@ -61,9 +62,9 @@ public class PartSwitch1x2 extends PartOther {
@Override
public List<InnerConnection> getInnerConnections() {
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));
}
}

View File

@ -11,6 +11,7 @@ import lombok.ToString;
import java.util.List;
import static de.ph87.electro.CONFIG.*;
import static de.ph87.electro.circuit.Calculation.NO_RESISTANCE;
@Getter
@ToString(callSuper = true)
@ -68,13 +69,13 @@ public class PartSwitchCross extends PartOther {
public List<InnerConnection> getInnerConnections() {
if (state) {
return List.of(
new InnerConnection(common0, output1),
new InnerConnection(common1, output0)
new InnerConnection(common0, output1, NO_RESISTANCE),
new InnerConnection(common1, output0, NO_RESISTANCE)
);
}
return List.of(
new InnerConnection(common0, output0),
new InnerConnection(common1, output1)
new InnerConnection(common0, output0, NO_RESISTANCE),
new InnerConnection(common1, output1, NO_RESISTANCE)
);
}

View File

@ -20,21 +20,21 @@ class CalculationServiceTest {
circuit.connect(battery.getMinus(), light.getA());
circuit.connect(battery.getPlus(), light.getB());
final Calculation calculation = new Calculation(circuit);
calculation.toString().lines().forEach(log::info);
circuit.streamParts().forEach(part -> {
log.info("");
log.info(part.toString());
for (final Junction junction : part.getJunctions()) {
log.info(" \"%s\" = %.2f V".formatted(junction.getName(), junction.getVoltage()));
for (final Wire wire : junction.getWires()) {
final Junction opposite = wire.getOpposite(junction);
log.info(" -> %s.%s = %.2f A".formatted(opposite.getOwner().getName(), opposite.getName(), wire.getCurrent(junction)));
for (final Calculation calculation : Calculation.calculate(circuit)) {
calculation.toString().lines().forEach(log::info);
circuit.streamParts().forEach(part -> {
log.info("");
log.info(part.toString());
for (final Junction junction : part.getJunctions()) {
log.info(" \"%s\" = %.2f V".formatted(junction.getName(), junction.getVoltage()));
for (final Wire wire : junction.getWires()) {
final Junction opposite = wire.getOpposite(junction);
log.info(" -> %s.%s = %.2f A".formatted(opposite.getOwner().getName(), opposite.getName(), wire.getCurrent(junction)));
}
}
}
});
log.info("");
});
log.info("");
}
}
}