diff --git a/edg/abstract_parts/AbstractAnalogSwitch.py b/edg/abstract_parts/AbstractAnalogSwitch.py index b31375ee8..e58678ff2 100644 --- a/edg/abstract_parts/AbstractAnalogSwitch.py +++ b/edg/abstract_parts/AbstractAnalogSwitch.py @@ -129,14 +129,12 @@ def __init__(self) -> None: self.control = self.Export(self.device.control) self.inputs = self.Port(Vector(AnalogSink.empty())) - self.out = self.Export( - self.device.com.adapt_to( - AnalogSource( - voltage_out=self.inputs.hull(lambda x: x.link().voltage), - signal_out=self.inputs.hull(lambda x: x.link().signal), - current_limits=self.device.analog_current_limits, # this device only, current draw propagated - impedance=self.device.analog_on_resistance + self.inputs.hull(lambda x: x.link().source_impedance), - ) + self.out = self.Port( + AnalogSource( + voltage_out=self.inputs.hull(lambda x: x.link().voltage), + signal_out=self.inputs.hull(lambda x: x.link().signal), + current_limits=self.device.analog_current_limits, # this device only, current draw propagated + impedance=self.device.analog_on_resistance + self.inputs.hull(lambda x: x.link().source_impedance), ) ) @@ -145,18 +143,20 @@ def __init__(self) -> None: @override def generate(self) -> None: super().generate() + + self.connect(self.out.net, self.device.com) + self.inputs.defined() for elt in self.get(self.inputs.requested()): - self.connect( - self.inputs.append_elt(AnalogSink.empty(), elt), - self.device.inputs.request(elt).adapt_to( - AnalogSink( - voltage_limits=self.device.analog_voltage_limits, # this device only, voltages propagated - current_draw=self.out.link().current_drawn, - impedance=self.out.link().sink_impedance + self.device.analog_on_resistance, - ) + input = self.inputs.append_elt( + AnalogSink( + voltage_limits=self.device.analog_voltage_limits, # this device only, voltages propagated + current_draw=self.out.link().current_drawn, + impedance=self.out.link().sink_impedance + self.device.analog_on_resistance, ), + elt, ) + self.connect(input.net, self.device.inputs.request(elt)) if self.get(self.control_gnd.is_connected()): self.connect(self.control_gnd, self.device.control_gnd) @@ -182,13 +182,11 @@ def __init__(self) -> None: self.control = self.Export(self.device.control) self.outputs = self.Port(Vector(AnalogSource.empty())) - self.input = self.Export( - self.device.com.adapt_to( - AnalogSink( - voltage_limits=self.device.analog_voltage_limits, # this device only, voltages propagated - current_draw=self.outputs.hull(lambda x: x.link().current_drawn), - impedance=self.device.analog_on_resistance + self.outputs.hull(lambda x: x.link().sink_impedance), - ) + self.input = self.Port( + AnalogSink( + voltage_limits=self.device.analog_voltage_limits, # this device only, voltages propagated + current_draw=self.outputs.hull(lambda x: x.link().current_drawn), + impedance=self.device.analog_on_resistance + self.outputs.hull(lambda x: x.link().sink_impedance), ) ) @@ -197,19 +195,21 @@ def __init__(self) -> None: @override def generate(self) -> None: super().generate() + + self.connect(self.input.net, self.device.com) + self.outputs.defined() for elt in self.get(self.outputs.requested()): - self.connect( - self.outputs.append_elt(AnalogSource.empty(), elt), - self.device.inputs.request(elt).adapt_to( - AnalogSource( - voltage_out=self.input.link().voltage, - signal_out=self.input.link().signal, - current_limits=self.device.analog_current_limits, # this device only, voltages propagated - impedance=self.input.link().source_impedance + self.device.analog_on_resistance, - ) + output = self.outputs.append_elt( + AnalogSource( + voltage_out=self.input.link().voltage, + signal_out=self.input.link().signal, + current_limits=self.device.analog_current_limits, # this device only, voltages propagated + impedance=self.input.link().source_impedance + self.device.analog_on_resistance, ), + elt, ) + self.connect(output.net, self.device.inputs.request(elt)) def demux_to( self, input: Optional[Port[AnalogLink]] = None, outputs: Optional[List[Port[AnalogLink]]] = None diff --git a/edg/abstract_parts/AbstractCapacitor.py b/edg/abstract_parts/AbstractCapacitor.py index 84ca3352a..bdf39aca9 100644 --- a/edg/abstract_parts/AbstractCapacitor.py +++ b/edg/abstract_parts/AbstractCapacitor.py @@ -403,10 +403,12 @@ def __init__(self, capacitance: RangeLike, *, exact_capacitance: BoolLike = Fals super().__init__() self.cap = self.Block(Capacitor(capacitance, voltage=RangeExpr(), exact_capacitance=exact_capacitance)) - self.gnd = self.Export(self.cap.neg.adapt_to(Ground()), [Common]) - self.io = self.Export(self.cap.pos.adapt_to(AnalogSink()), [InOut]) # ideal open port + self.gnd = self.Port(Ground.empty(), [Common]) + self.io = self.Port(AnalogSink(), [InOut]) # ideal open port self.assign(self.cap.voltage, self.io.link().voltage - self.gnd.link().voltage) + self.connect(self.cap.neg.adapt_to(Ground()), self.gnd) # TODO refactor #114 + self.connect(self.io.net, self.cap.pos) def connected( self, gnd: Optional[Port[GroundLink]] = None, io: Optional[Port[AnalogLink]] = None diff --git a/edg/abstract_parts/AbstractDiodes.py b/edg/abstract_parts/AbstractDiodes.py index 1f9f76144..0c8b1f452 100644 --- a/edg/abstract_parts/AbstractDiodes.py +++ b/edg/abstract_parts/AbstractDiodes.py @@ -1,9 +1,7 @@ -from typing import Dict, Any +from typing import Dict from deprecated import deprecated -from typing_extensions import override from ..electronics_model import * -from .DummyDevices import ForcedAnalogVoltage from .Categories import * from .PartsTable import PartsTableColumn, PartsTableRow from .PartsTablePart import PartsTableSelector @@ -222,27 +220,22 @@ class AnalogClampZenerDiode(Protection, KiCadImportableBlock): def __init__(self, voltage: RangeLike): super().__init__() - self.signal_in = self.Port(AnalogSink.empty(), [Input]) - self.signal_out = self.Port(AnalogSource.empty(), [Output]) - self.gnd = self.Port(Ground.empty(), [Common]) - - self.voltage = self.ArgParameter(voltage) - - @override - def contents(self) -> None: - super().contents() + self.diode = self.Block(ZenerDiode(zener_voltage=voltage)) - self.diode = self.Block(ZenerDiode(zener_voltage=self.voltage)) - - self.forced = self.Block( - ForcedAnalogVoltage( - forced_voltage=self.signal_in.link().voltage.intersect( + self.gnd = self.Port(Ground.empty(), [Common]) + self.signal_in = self.Port(AnalogSink(), [Input]) + self.signal_out = self.Port( + AnalogSource( + voltage_out=self.signal_in.link().voltage.intersect( self.gnd.link().voltage + (0, self.diode.actual_zener_voltage.upper()) - ) - ) + ), + signal_out=self.signal_in.link().signal, + ), + [Output], ) - self.connect(self.signal_in, self.forced.signal_in) - self.connect(self.signal_out, self.forced.signal_out, self.diode.cathode.adapt_to(AnalogSink())) + self.assign(self.signal_in.current_draw, self.signal_out.link().current_drawn) + + self.connect(self.signal_in.net, self.signal_out.net, self.diode.cathode) self.connect(self.diode.anode.adapt_to(Ground()), self.gnd) @override diff --git a/edg/abstract_parts/AbstractResistor.py b/edg/abstract_parts/AbstractResistor.py index 264ab95a5..249ce3a82 100644 --- a/edg/abstract_parts/AbstractResistor.py +++ b/edg/abstract_parts/AbstractResistor.py @@ -392,14 +392,21 @@ def __init__( ): super().__init__() - self.signal_in = self.Port(AnalogSink.empty(), [Input]) - self.signal_out = self.Port(AnalogSource.empty(), [Output]) - self.clamp_target = self.ArgParameter(clamp_target) self.clamp_current = self.ArgParameter(clamp_current) self.protection_voltage = self.ArgParameter(protection_voltage) self.zero_out = self.ArgParameter(zero_out) + self.signal_in = self.Port(AnalogSink(), [Input]) + self.signal_out = self.Port( + AnalogSource( + voltage_out=self.signal_in.link().voltage.intersect(self.clamp_target), + signal_out=self.signal_in.link().signal, + impedance=RangeExpr(), + ), + [Output], + ) + @override def contents(self) -> None: super().contents() @@ -415,17 +422,9 @@ def contents(self) -> None: ) ) ) - self.connect(self.res.a.adapt_to(AnalogSink()), self.signal_in) - self.connect( - self.res.b.adapt_to( - AnalogSource( - voltage_out=self.signal_in.link().voltage.intersect(self.clamp_target), - signal_out=self.signal_in.link().signal, - impedance=self.signal_in.link().source_impedance + self.res.actual_resistance, - ) - ), - self.signal_out, - ) + self.connect(self.res.a, self.signal_in.net) + self.connect(self.res.b, self.signal_out.net) + self.assign(self.signal_out.impedance, self.signal_in.link().source_impedance + self.res.actual_resistance) @override def symbol_pinning(self, symbol_name: str) -> Dict[str, Port]: diff --git a/edg/abstract_parts/AbstractSolidStateRelay.py b/edg/abstract_parts/AbstractSolidStateRelay.py index f146e2439..54bba84d6 100644 --- a/edg/abstract_parts/AbstractSolidStateRelay.py +++ b/edg/abstract_parts/AbstractSolidStateRelay.py @@ -111,14 +111,22 @@ def symbol_pinning(self, symbol_name: str) -> Dict[str, BasePort]: def __init__(self) -> None: super().__init__() + self.ic = self.Block(SolidStateRelay()) + self.signal = self.Port(DigitalSink.empty()) self.gnd = self.Port(Ground.empty(), [Common]) self.apull = self.Port(AnalogSink.empty()) - self.ain = self.Port(AnalogSink.empty()) + self.ain = self.Port( + AnalogSink( + voltage_limits=RangeExpr(), + impedance=RangeExpr(), + ) + ) self.aout = self.Port(AnalogSource.empty()) + self.assign(self.ain.voltage_limits, self.apull.link().voltage + self.ic.load_voltage_limit) + self.assign(self.ain.impedance, self.aout.link().sink_impedance + self.ic.load_resistance) - self.ic = self.Block(SolidStateRelay()) self.res = self.Block( Resistor( resistance=( @@ -134,15 +142,7 @@ def __init__(self) -> None: self.connect(self.res.a, self.ic.ledk) self.connect(self.res.b.adapt_to(Ground()), self.gnd) - self.connect( - self.ain, - self.ic.feta.adapt_to( - AnalogSink( - voltage_limits=self.apull.link().voltage + self.ic.load_voltage_limit, - impedance=self.aout.link().sink_impedance + self.ic.load_resistance, - ) - ), - ) + self.connect(self.ain.net, self.ic.feta) self.pull_merge = self.Block(MergedAnalogSource()).connected_from( self.apull, self.ic.fetb.adapt_to( diff --git a/edg/abstract_parts/AbstractTestPoint.py b/edg/abstract_parts/AbstractTestPoint.py index 7776443fd..e3253c212 100644 --- a/edg/abstract_parts/AbstractTestPoint.py +++ b/edg/abstract_parts/AbstractTestPoint.py @@ -120,8 +120,8 @@ class AnalogTestPoint(BaseTypedTestPoint, Block): def __init__(self, *args: Any) -> None: super().__init__(*args) - self.io = self.Port(AnalogSink.empty(), [InOut]) - self.connect(self.io, self.tp.io.adapt_to(AnalogSink())) + self.io: AnalogSink = self.Port(AnalogSink(), [InOut]) + self.connect(self.io.net, self.tp.io) def connected(self, io: Port[AnalogLink]) -> "AnalogTestPoint": cast(Block, builder.get_enclosing_block()).connect(io, self.io) @@ -135,7 +135,8 @@ class AnalogCoaxTestPoint(BaseRfTestPoint, Block): def __init__(self, *args: Any) -> None: super().__init__(*args) - self.io = self.Export(self.conn.sig.adapt_to(AnalogSink()), [InOut]) + self.io: AnalogSink = self.Port(AnalogSink(), [InOut]) + self.connect(self.io.net, self.conn.sig) def connected(self, io: Port[AnalogLink]) -> "AnalogCoaxTestPoint": cast(Block, builder.get_enclosing_block()).connect(io, self.io) diff --git a/edg/abstract_parts/DummyDevices.py b/edg/abstract_parts/DummyDevices.py index 0ef9b3865..138e585c6 100644 --- a/edg/abstract_parts/DummyDevices.py +++ b/edg/abstract_parts/DummyDevices.py @@ -113,25 +113,11 @@ def __init__(self, forced_voltage: RangeLike, forced_current: RangeLike) -> None self.pwr_out = self.Port(VoltageSource(voltage_out=forced_voltage), [Output]) -class ForcedAnalogVoltage(DummyDevice, NetBlock): - def __init__(self, forced_voltage: RangeLike = RangeExpr()) -> None: - super().__init__() - - self.signal_in = self.Port(AnalogSink(current_draw=RangeExpr()), [Input]) - - self.signal_out = self.Port( - AnalogSource(voltage_out=forced_voltage, signal_out=self.signal_in.link().signal), [Output] - ) - - self.assign(self.signal_in.current_draw, self.signal_out.link().current_drawn) - - -class ForcedAnalogSignal(KiCadImportableBlock, DummyDevice, NetBlock): +class ForcedAnalogSignal(KiCadImportableBlock, DummyDevice): def __init__(self, forced_signal: RangeLike = RangeExpr()) -> None: super().__init__() self.signal_in = self.Port(AnalogSink(current_draw=RangeExpr()), [Input]) - self.signal_out = self.Port( AnalogSource( voltage_out=self.signal_in.link().voltage, @@ -142,6 +128,7 @@ def __init__(self, forced_signal: RangeLike = RangeExpr()) -> None: ) self.assign(self.signal_in.current_draw, self.signal_out.link().current_drawn) + self.connect(self.signal_in.net, self.signal_out.net) @override def symbol_pinning(self, symbol_name: str) -> Dict[str, BasePort]: diff --git a/edg/abstract_parts/IoController.py b/edg/abstract_parts/IoController.py index 85b4a2e1a..2695f23c5 100644 --- a/edg/abstract_parts/IoController.py +++ b/edg/abstract_parts/IoController.py @@ -1,5 +1,5 @@ from itertools import chain -from typing import List, Dict, Tuple, Type, Optional, Any +from typing import List, Dict, Tuple, Type, Optional, Any, Union from deprecated import deprecated from typing_extensions import override @@ -7,6 +7,7 @@ from ..electronics_model import * from .PinMappable import AllocatedResource, PinMappable, PinMapUtil from .Categories import ProgrammableController +from ..electronics_model.PassivePort import HasPassivePort @non_library @@ -97,12 +98,12 @@ def _export_ios_from(self, inner: "BaseIoController", excludes: List[BasePort] = @staticmethod def _instantiate_from( ios: List[BasePort], allocations: List[AllocatedResource] - ) -> Tuple[Dict[str, CircuitPort], RangeExpr]: + ) -> Tuple[Dict[str, Union[CircuitPort, HasPassivePort]], RangeExpr]: """Given a mapping of port types to IO ports and allocated resources from PinMapUtil, instantiate vector elements (if a vector) or init the port model (if a port) for the allocated resources using their data model and return the pin mapping.""" ios_by_type = {io.elt_type() if isinstance(io, Vector) else type(io): io for io in ios} - pinmap: Dict[str, CircuitPort] = {} + pinmap: Dict[str, Union[CircuitPort, HasPassivePort]] = {} ports_assigned = IdentitySet[Port]() io_current_draw_builder = RangeExpr._to_expr_type(RangeExpr.ZERO) @@ -141,14 +142,14 @@ def _instantiate_from( # TODO: recurse into bundles, really needs a more unified way of handling current draw if isinstance(allocation.pin, str): - assert isinstance(io_port, CircuitPort) + assert isinstance(io_port, (CircuitPort, HasPassivePort)) pinmap[allocation.pin] = io_port elif allocation.pin is None: - assert isinstance(io_port, CircuitPort) # otherwise discarded + assert isinstance(io_port, (CircuitPort, HasPassivePort)) # otherwise discarded elif isinstance(allocation.pin, dict): for subport_name, (pin_name, pin_resource) in allocation.pin.items(): subport = getattr(io_port, subport_name) - assert isinstance(subport, CircuitPort), f"bad sub-port {pin_name} {subport}" + assert isinstance(subport, (CircuitPort, HasPassivePort)), f"bad sub-port {pin_name} {subport}" pinmap[pin_name] = subport else: raise NotImplementedError(f"unknown allocation pin type {allocation.pin}") @@ -183,7 +184,7 @@ def _io_pinmap(self) -> PinMapUtil: """Implement me. Defines the assignable IO pinmaps.""" raise NotImplementedError - def _make_pinning(self) -> Dict[str, CircuitPort]: + def _make_pinning(self) -> Dict[str, Union[CircuitPort, HasPassivePort]]: allocation_list = [] for io_port in self._io_ports: if isinstance(io_port, Vector): # derive Vector connections from requested diff --git a/edg/abstract_parts/MergedBlocks.py b/edg/abstract_parts/MergedBlocks.py index 9adddd40a..4eb055bbb 100644 --- a/edg/abstract_parts/MergedBlocks.py +++ b/edg/abstract_parts/MergedBlocks.py @@ -69,7 +69,7 @@ def connected_from(self, *ins: Port[DigitalLink]) -> "MergedDigitalSource": return self -class MergedAnalogSource(KiCadImportableBlock, DummyDevice, NetBlock, GeneratorBlock): +class MergedAnalogSource(KiCadImportableBlock, DummyDevice, GeneratorBlock): @override def symbol_pinning(self, symbol_name: str) -> Dict[str, BasePort]: assert symbol_name.startswith("edg_importable:Merge") # can be any merge @@ -89,10 +89,11 @@ def generate(self) -> None: super().generate() self.inputs.defined() for in_request in self.get(self.inputs.requested()): - self.inputs.append_elt( + elt_port = self.inputs.append_elt( AnalogSink(current_draw=self.output.link().current_drawn, impedance=self.output.link().sink_impedance), in_request, ) + self.connect(self.output.net, elt_port.net) self.assign(self.output.voltage_out, self.inputs.hull(lambda x: x.link().voltage)) self.assign(self.output.signal_out, self.inputs.hull(lambda x: x.link().signal)) diff --git a/edg/abstract_parts/OpampCircuits.py b/edg/abstract_parts/OpampCircuits.py index 1cf848e41..8df355277 100644 --- a/edg/abstract_parts/OpampCircuits.py +++ b/edg/abstract_parts/OpampCircuits.py @@ -1,5 +1,5 @@ from math import ceil, log10 -from typing import List, Tuple, Dict, Mapping +from typing import List, Tuple, Dict, Mapping, Union from typing_extensions import override @@ -11,6 +11,7 @@ from .Categories import OpampApplication from .DummyDevices import ForcedAnalogSignal from .ESeriesUtil import ESeriesRatioUtil, ESeriesUtil, ESeriesRatioValue +from ..electronics_model.PassivePort import HasPassivePort class OpampFollower(OpampApplication, KiCadSchematicBlock, KiCadImportableBlock): @@ -156,8 +157,10 @@ def generate(self) -> None: self.r2 = self.Block(Resistor(Range.from_tolerance(bottom_resistance, self.get(self.tolerance)))) if self.get(self.reference.is_connected()): - reference_type: CircuitPort = AnalogSink(impedance=self.r1.actual_resistance + self.r2.actual_resistance) - reference_node: CircuitPort = self.reference + reference_type: Union[CircuitPort, HasPassivePort] = AnalogSink( + impedance=self.r1.actual_resistance + self.r2.actual_resistance + ) + reference_node: Union[CircuitPort, HasPassivePort] = self.reference reference_range = self.reference.link().signal else: reference_type = Ground() @@ -310,7 +313,7 @@ def generate(self) -> None: if self.get(self.output_reference.is_connected()): output_neg_signal = self.output_reference.link().signal output_neg_voltage = self.output_reference.link().voltage - output_neg_node: CircuitPort = self.output_reference + output_neg_node: Union[CircuitPort, HasPassivePort] = self.output_reference else: output_neg_voltage = output_neg_signal = self.gnd.link().voltage output_neg_node = self.gnd.as_analog_source() diff --git a/edg/abstract_parts/PassiveFilters.py b/edg/abstract_parts/PassiveFilters.py index b905bc97e..72f0deba7 100644 --- a/edg/abstract_parts/PassiveFilters.py +++ b/edg/abstract_parts/PassiveFilters.py @@ -76,17 +76,15 @@ class AnalogLowPassRc(DigitalFilter, Block): def __init__(self, impedance: RangeLike, cutoff_freq: RangeLike): super().__init__() - self.input = self.Port(AnalogSink.empty(), [Input]) - self.output = self.Port(AnalogSource.empty(), [Output]) + self.input = self.Port(AnalogSink(current_draw=RangeExpr()), [Input]) + self.output = self.Port( + AnalogSource(voltage_out=self.input.link().voltage, signal_out=self.input.link().signal), [Output] + ) + self.assign(self.input.current_draw, self.output.link().current_drawn) self.rc = self.Block(LowPassRc(impedance=impedance, cutoff_freq=cutoff_freq, voltage=self.input.link().voltage)) - self.connect(self.input, self.rc.input.adapt_to(AnalogSink(current_draw=self.output.link().current_drawn))) - self.connect( - self.output, - self.rc.output.adapt_to( - AnalogSource(voltage_out=self.input.link().voltage, signal_out=self.input.link().signal) - ), - ) + self.connect(self.input.net, self.rc.input) + self.connect(self.output.net, self.rc.output) self.gnd = self.Export(self.rc.gnd.adapt_to(Ground()), [Common]) @@ -156,20 +154,18 @@ class LowPassRcDac(DigitalToAnalog, Block): def __init__(self, impedance: RangeLike, cutoff_freq: RangeLike): super().__init__() self.input = self.Port(DigitalSink.empty(), [Input]) - self.output = self.Port(AnalogSource.empty(), [Output]) + self.output = self.Port( + AnalogSource( + voltage_out=self.input.link().voltage, + signal_out=self.input.link().voltage, + impedance=impedance, # TODO use selected resistance from RC filter + ), + [Output], + ) self.rc = self.Block(LowPassRc(impedance=impedance, cutoff_freq=cutoff_freq, voltage=self.input.link().voltage)) self.connect(self.input, self.rc.input.adapt_to(DigitalSink(current_draw=self.output.link().current_drawn))) - self.connect( - self.output, - self.rc.output.adapt_to( - AnalogSource( - voltage_out=self.input.link().voltage, - signal_out=self.input.link().voltage, - impedance=impedance, # TODO use selected resistance from RC filter - ) - ), - ) + self.connect(self.output.net, self.rc.output) self.gnd = self.Export(self.rc.gnd.adapt_to(Ground()), [Common]) @@ -185,10 +181,22 @@ def symbol_pinning(self, symbol_name: str) -> Mapping[str, BasePort]: def __init__(self, impedance: RangeLike, cutoff_freq: RangeLike): super().__init__() - self.inn = self.Port(AnalogSink.empty()) - self.inp = self.Port(AnalogSink.empty()) - self.outn = self.Port(AnalogSource.empty()) - self.outp = self.Port(AnalogSource.empty()) + self.inn = self.Port(AnalogSink(impedance=RangeExpr(), current_draw=RangeExpr())) + self.inp = self.Port(AnalogSink(impedance=RangeExpr(), current_draw=RangeExpr())) + self.outn = self.Port( + AnalogSource( + voltage_out=self.inn.link().voltage, + signal_out=self.inn.link().signal, + impedance=RangeExpr(), + ) + ) + self.outp = self.Port( + AnalogSource( + voltage_out=self.inp.link().voltage, + signal_out=self.inp.link().signal, + impedance=RangeExpr(), + ) + ) self.impedance = self.ArgParameter(impedance) self.cutoff_freq = self.ArgParameter(cutoff_freq) @@ -199,48 +207,19 @@ def contents(self) -> None: self.rp = self.Block(Resistor(resistance=self.impedance)) self.rn = self.Block(Resistor(resistance=self.impedance)) + self.assign(self.inn.impedance, self.rn.actual_resistance + self.outn.link().sink_impedance) + self.assign(self.inn.current_draw, self.outn.link().current_drawn) + self.assign(self.inp.impedance, self.rp.actual_resistance + self.outp.link().sink_impedance) + self.assign(self.inp.current_draw, self.outp.link().current_drawn) + self.assign(self.outn.impedance, self.rn.actual_resistance + self.inn.link().source_impedance) + self.assign(self.outp.impedance, self.rp.actual_resistance + self.inp.link().source_impedance) + capacitance = (1 / self.cutoff_freq).shrink_multiply(1 / (2 * pi * self.impedance)) # capacitance is single-ended, halve it for differential self.c = self.Block( Capacitor(capacitance=0.5 * capacitance, voltage=self.inp.link().voltage - self.inn.link().voltage) ) - self.connect( - self.inp, - self.rp.a.adapt_to( - AnalogSink( - impedance=self.rp.actual_resistance + self.outp.link().sink_impedance, - current_draw=self.outp.link().current_drawn, - ) - ), - ) - self.connect( - self.inn, - self.rn.a.adapt_to( - AnalogSink( - impedance=self.rn.actual_resistance + self.outn.link().sink_impedance, - current_draw=self.outn.link().current_drawn, - ) - ), - ) - self.connect( - self.outp, - self.rp.b.adapt_to( - AnalogSource( - voltage_out=self.inp.link().voltage, - signal_out=self.inp.link().signal, - impedance=self.rp.actual_resistance + self.inp.link().source_impedance, - ) - ), - self.c.pos.adapt_to(AnalogSink()), - ) - self.connect( - self.outn, - self.rn.b.adapt_to( - AnalogSource( - voltage_out=self.inn.link().voltage, - signal_out=self.inn.link().signal, - impedance=self.rn.actual_resistance + self.inn.link().source_impedance, - ) - ), - self.c.neg.adapt_to(AnalogSink()), - ) + self.connect(self.inp.net, self.rp.a) + self.connect(self.inn.net, self.rn.a) + self.connect(self.outp.net, self.rp.b, self.c.pos) + self.connect(self.outn.net, self.rn.b, self.c.neg) diff --git a/edg/abstract_parts/PinMappable.py b/edg/abstract_parts/PinMappable.py index 70fa4e29a..2746f1bd2 100644 --- a/edg/abstract_parts/PinMappable.py +++ b/edg/abstract_parts/PinMappable.py @@ -4,6 +4,7 @@ from typing_extensions import override from ..electronics_model import * +from ..electronics_model.PassivePort import HasPassivePort @non_library @@ -55,7 +56,7 @@ class BaseDelegatingPinMapResource(BasePinMapResource): class PinResource(BaseLeafPinMapResource): """A resource for a single chip pin, which can be one of several port types (eg, an ADC and DIO sharing a pin).""" - def __init__(self, pin: str, name_models: Dict[str, CircuitPort]): + def __init__(self, pin: str, name_models: Mapping[str, Union[CircuitPort, HasPassivePort]]): self.pin = pin self.name_models = name_models diff --git a/edg/abstract_parts/ResistiveDivider.py b/edg/abstract_parts/ResistiveDivider.py index 17ab56988..7bdb0e4fd 100644 --- a/edg/abstract_parts/ResistiveDivider.py +++ b/edg/abstract_parts/ResistiveDivider.py @@ -176,14 +176,12 @@ def __init__(self, impedance: RangeLike) -> None: output_voltage = ResistiveDivider.divider_output( self.input.link().voltage, self.gnd.link().voltage, self.div.actual_ratio ) - self.output = self.Export( - self.div.center.adapt_to( - AnalogSource( - voltage_out=output_voltage, - signal_out=output_voltage, - current_limits=RangeExpr.ALL, - impedance=self.div.actual_impedance, - ) + self.output = self.Port( + AnalogSource( + voltage_out=output_voltage, + signal_out=output_voltage, + current_limits=RangeExpr.ALL, + impedance=self.div.actual_impedance, ), [Output], ) @@ -193,6 +191,7 @@ def __init__(self, impedance: RangeLike) -> None: VoltageSink(current_draw=self.output.link().current_drawn, voltage_limits=RangeExpr.ALL) ), ) + self.connect(self.output.net, self.div.center) self.actual_rtop = self.Parameter(RangeExpr(self.div.actual_rtop)) self.actual_rbot = self.Parameter(RangeExpr(self.div.actual_rbot)) @@ -269,22 +268,20 @@ def __init__(self, ratio: RangeLike, impedance: RangeLike) -> None: self.div = self.Block(ResistiveDivider(ratio=ratio, impedance=impedance)) self.gnd = self.Export(self.div.bottom.adapt_to(Ground()), [Common]) - self.input = self.Port(AnalogSink.empty(), [Input]) # forward declaration + self.input = self.Port( + AnalogSink( + impedance=self.div.actual_series_impedance, + current_draw=RangeExpr(), + ), + [Input], + ) # forward declaration output_voltage = ResistiveDivider.divider_output( self.input.link().voltage, self.gnd.link().voltage, self.div.actual_ratio ) - self.output = self.Export( - self.div.center.adapt_to( - AnalogSource(voltage_out=output_voltage, signal_out=output_voltage, impedance=self.div.actual_impedance) - ), + self.output = self.Port( + AnalogSource(voltage_out=output_voltage, signal_out=output_voltage, impedance=self.div.actual_impedance), [Output], ) - self.connect( - self.input, - self.div.top.adapt_to( - AnalogSink( - impedance=self.div.actual_series_impedance, - current_draw=self.output.link().current_drawn, - ) - ), - ) + self.assign(self.input.current_draw, self.output.link().current_drawn) + self.connect(self.output.net, self.div.center) + self.connect(self.input.net, self.div.top) diff --git a/edg/abstract_parts/__init__.py b/edg/abstract_parts/__init__.py index 49cba6a7b..3e311e54f 100644 --- a/edg/abstract_parts/__init__.py +++ b/edg/abstract_parts/__init__.py @@ -203,7 +203,6 @@ ForcedVoltageCurrentLimit, ForcedVoltage, ForcedVoltageCurrent, - ForcedAnalogVoltage, ForcedAnalogSignal, ForcedDigitalSinkCurrentDraw, ) diff --git a/edg/core/Core.py b/edg/core/Core.py index 6eede21cb..9e901bda1 100644 --- a/edg/core/Core.py +++ b/edg/core/Core.py @@ -294,7 +294,7 @@ def _get_bases_of(cls, base_type: Type[BaseType]) -> Tuple[List[Type[BaseType]], superclasses order is not defined (but MRO in current practice). mypy currently does not allow passing in abstract types, so generally calls to this need type: ignore.""" - direct_bases: Set[Type[HasMetadata]] = set() + direct_bases: Set[Type[HasMetadata.BaseType]] = set() def process_direct_base(bcls: Type[HasMetadata.BaseType]) -> None: if not issubclass(bcls, base_type): diff --git a/edg/electronics_model/AnalogPort.py b/edg/electronics_model/AnalogPort.py index eaef510b5..802faee9c 100644 --- a/edg/electronics_model/AnalogPort.py +++ b/edg/electronics_model/AnalogPort.py @@ -5,12 +5,13 @@ from typing_extensions import override from ..core import * -from .CircuitBlock import CircuitLink, CircuitPortAdapter +from .PassivePort import HasPassivePort +from .CircuitBlock import CircuitPortAdapter, KicadImportablePortAdapter from .GroundPort import GroundLink -from .VoltagePorts import CircuitPort, CircuitPortBridge, VoltageLink, VoltageSource +from .VoltagePorts import VoltageLink, VoltageSource -class AnalogLink(CircuitLink): +class AnalogLink(Link): """Analog signal, a signal that carries information by varying voltage""" def __init__(self) -> None: @@ -34,6 +35,8 @@ def __init__(self) -> None: def contents(self) -> None: super().contents() + self.net = self.connect(self.source.net, self.sinks.map_extract(lambda sink: sink.net), flatten=True) + self.description = DescriptionString( "voltage: ", DescriptionString.FormatUnits(self.voltage, "V"), @@ -64,7 +67,7 @@ def contents(self) -> None: self.require(self.current_limits.contains(self.current_drawn), "overcurrent") -class AnalogBase(CircuitPort[AnalogLink]): +class AnalogBase(Port[AnalogLink]): link_type = AnalogLink # these are here (instead of in AnalogSource) since the port may be on the other side of a bridge @@ -72,7 +75,7 @@ def as_voltage_source(self) -> VoltageSource: return self._convert(AnalogSourceAdapterVoltageSource()) -class AnalogSinkBridge(CircuitPortBridge): +class AnalogSinkBridge(PortBridge): def __init__(self) -> None: super().__init__() @@ -94,6 +97,8 @@ def __init__(self) -> None: def contents(self) -> None: super().contents() + self.connect(self.outer_port.net, self.inner_link.net) + self.assign(self.outer_port.impedance, self.inner_link.link().sink_impedance) self.assign(self.outer_port.current_draw, self.inner_link.link().current_drawn) self.assign(self.outer_port.voltage_limits, self.inner_link.link().voltage_limits) @@ -103,7 +108,7 @@ def contents(self) -> None: self.assign(self.inner_link.signal_out, self.outer_port.link().signal) -class AnalogSourceBridge(CircuitPortBridge): # basic passthrough port, sources look the same inside and outside +class AnalogSourceBridge(PortBridge): # basic passthrough port, sources look the same inside and outside def __init__(self) -> None: super().__init__() @@ -130,6 +135,8 @@ def __init__(self) -> None: def contents(self) -> None: super().contents() + self.connect(self.outer_port.net, self.inner_link.net) + self.assign(self.outer_port.voltage_out, self.inner_link.link().voltage) self.assign(self.outer_port.signal_out, self.inner_link.link().signal) self.assign(self.outer_port.impedance, self.inner_link.link().source_impedance) @@ -141,7 +148,7 @@ def contents(self) -> None: self.assign(self.inner_link.impedance, self.outer_port.link().sink_impedance) -class AnalogSink(AnalogBase): +class AnalogSink(AnalogBase, HasPassivePort): bridge_type = AnalogSinkBridge @staticmethod @@ -195,26 +202,31 @@ def __init__( """voltage_limits are the maximum recommended voltage levels of the device (before device damage occurs), signal_limits are for proper device functionality (e.g. non-RRIO opamps)""" super().__init__() + self.voltage_limits = self.Parameter(RangeExpr(voltage_limits)) self.signal_limits = self.Parameter(RangeExpr(signal_limits)) self.current_draw = self.Parameter(RangeExpr(current_draw)) self.impedance = self.Parameter(RangeExpr(impedance)) -class AnalogSourceAdapterVoltageSource(CircuitPortAdapter[VoltageSource]): +class AnalogSourceAdapterVoltageSource(KicadImportablePortAdapter[VoltageSource]): def __init__(self) -> None: super().__init__() self.src = self.Port(AnalogSink(current_draw=RangeExpr())) # otherwise ideal - self.dst = self.Port( - VoltageSource( - voltage_out=(self.src.link().voltage.upper(), self.src.link().voltage.upper()), - current_limits=(-float("inf"), float("inf")), - ) - ) + self.dst = self.Port(VoltageSource.empty()) self.assign(self.src.current_draw, self.dst.link().current_drawn) + self.connect( + self.src.net.adapt_to( + VoltageSource( + voltage_out=(self.src.link().voltage.upper(), self.src.link().voltage.upper()), + current_limits=(-float("inf"), float("inf")), + ) + ), + self.dst, + ) -class AnalogSource(AnalogBase): +class AnalogSource(AnalogBase, HasPassivePort): bridge_type = AnalogSourceBridge @staticmethod @@ -256,6 +268,7 @@ def __init__( """voltage_out is the total voltage range the device can output (typically limited by power rails) regardless of controls and including transients, while signal_out is the intended operating range""" super().__init__() + self.voltage_out = self.Parameter(RangeExpr(voltage_out)) self.signal_out = self.Parameter(RangeExpr(signal_out)) self.current_limits = self.Parameter(RangeExpr(current_limits)) diff --git a/edg/electronics_model/CircuitBlock.py b/edg/electronics_model/CircuitBlock.py index f34c401a4..0d8333d6d 100644 --- a/edg/electronics_model/CircuitBlock.py +++ b/edg/electronics_model/CircuitBlock.py @@ -1,6 +1,6 @@ from __future__ import annotations -from typing import Generic, Any, Optional, List, Mapping, Dict +from typing import Generic, Any, Optional, List, Mapping, Dict, Union, TYPE_CHECKING from typing_extensions import TypeVar, override @@ -8,6 +8,9 @@ from ..core import * from ..core.HdlUserExceptions import EdgTypeError +if TYPE_CHECKING: + from .PassivePort import HasPassivePort + CircuitLinkType = TypeVar("CircuitLinkType", bound=Link, covariant=True, default=Link) @@ -57,7 +60,7 @@ def footprint( self, refdes: StringLike, footprint: StringLike, - pinning: Mapping[str, CircuitPort], + pinning: Mapping[str, Union[CircuitPort, "HasPassivePort"]], mfr: Optional[StringLike] = None, part: Optional[StringLike] = None, value: Optional[StringLike] = None, @@ -66,6 +69,7 @@ def footprint( """Creates a footprint in this circuit block. Value is a one-line description of the part, eg 680R, 0.01uF, LPC1549, to be used as a aid during layout or assembly""" + from .PassivePort import HasPassivePort from ..core.Blocks import BlockElaborationState, BlockDefinitionError from .VoltagePorts import CircuitPort @@ -84,6 +88,8 @@ def footprint( pinning_array = [] for pin_name, pin_port in pinning.items(): + if isinstance(pin_port, HasPassivePort): + pin_port = pin_port.net if not isinstance(pin_port, CircuitPort): raise EdgTypeError(f"Footprint(...) pin", pin_port, CircuitPort) pinning_array.append(f"{pin_name}={pin_port._name_from(self)}") @@ -137,22 +143,27 @@ def contents(self) -> None: self.net() -AdapterDstType = TypeVar("AdapterDstType", covariant=True, bound="CircuitPort", default="CircuitPort") +AdapterDstType = TypeVar("AdapterDstType", covariant=True, bound=Port, default=Port) -@abstract_block -class CircuitPortAdapter(KiCadImportableBlock, NetBaseBlock, PortAdapter[AdapterDstType], Generic[AdapterDstType]): +@non_library +class KicadImportablePortAdapter(KiCadImportableBlock, PortAdapter[AdapterDstType], Generic[AdapterDstType]): @override def symbol_pinning(self, symbol_name: str) -> Dict[str, BasePort]: assert symbol_name == "edg_importable:Adapter" return {"1": self.src, "2": self.dst} + +# TODO remove me once compositional passive refactoring complete, #114 +@abstract_block +class CircuitPortAdapter(KicadImportablePortAdapter[AdapterDstType], NetBaseBlock, Generic[AdapterDstType]): @override def contents(self) -> None: super().contents() self.net() +# TODO remove me once compositional passive refactoring complete, #114 @non_library # TODO make abstract instead? class CircuitLink(NetBaseBlock, Link): @override diff --git a/edg/electronics_model/GroundPort.py b/edg/electronics_model/GroundPort.py index bcfc05de5..8af144a28 100644 --- a/edg/electronics_model/GroundPort.py +++ b/edg/electronics_model/GroundPort.py @@ -5,7 +5,7 @@ from typing_extensions import override from ..core import * -from .CircuitBlock import CircuitPortBridge, CircuitPortAdapter, CircuitLink, CircuitPort +from .CircuitBlock import CircuitPortBridge, CircuitPortAdapter, CircuitLink, CircuitPort, KicadImportablePortAdapter from .Units import Volt, Ohm if TYPE_CHECKING: @@ -90,18 +90,19 @@ def __init__(self) -> None: ) -class GroundAdapterAnalogSource(CircuitPortAdapter["AnalogSource"]): +class GroundAdapterAnalogSource(KicadImportablePortAdapter["AnalogSource"]): def __init__(self) -> None: from .AnalogPort import AnalogSource super().__init__() - self.src = self.Port(Ground()) + self.src = self.Port(Ground.empty()) self.dst = self.Port( AnalogSource( voltage_out=self.src.link().voltage, signal_out=self.src.link().voltage, ) ) + self.connect(self.dst.net.adapt_to(Ground()), self.src) class Ground(CircuitPort[GroundLink]): diff --git a/edg/electronics_model/KiCadSchematicBlock.py b/edg/electronics_model/KiCadSchematicBlock.py index f60dbfc57..412d02f6f 100644 --- a/edg/electronics_model/KiCadSchematicBlock.py +++ b/edg/electronics_model/KiCadSchematicBlock.py @@ -1,14 +1,14 @@ import inspect import os from abc import abstractmethod -from typing import Type, Any, Optional, Mapping, Dict, List, Callable, Tuple, TypeVar, cast +from typing import Type, Any, Optional, Mapping, Dict, List, Callable, Tuple, TypeVar, cast, Union from typing_extensions import override from ..core import * from .CircuitBlock import FootprintBlock from .VoltagePorts import CircuitPort -from .PassivePort import Passive +from .PassivePort import Passive, HasPassivePort from .KiCadImportableBlock import KiCadInstantiableBlock, KiCadImportableBlock from .KiCadSchematicParser import ( KiCadSchematic, @@ -123,7 +123,7 @@ class KiCadSchematicBlock(Block): @staticmethod def _port_from_pin( - pin: KiCadPin, mapping: Mapping[str, BasePort], conversions: Mapping[str, CircuitPort] + pin: KiCadPin, mapping: Mapping[str, BasePort], conversions: Mapping[str, Union[CircuitPort, HasPassivePort]] ) -> BasePort: """Returns the Port from a symbol's pin, using the provided mapping and applying conversions as needed.""" from .PassivePort import Passive @@ -153,7 +153,7 @@ def _port_from_pin( f"mapping defined for both number ${pin.pin_number} and name ${pin.pin_name}" ) elif f"{pin.refdes}.{pin.pin_number}" in conversions: - conversion: Optional[CircuitPort] = conversions[f"{pin.refdes}.{pin.pin_number}"] + conversion: Optional[Union[CircuitPort, HasPassivePort]] = conversions[f"{pin.refdes}.{pin.pin_number}"] elif f"{pin.refdes}.{pin.pin_name}" in conversions: conversion = conversions[f"{pin.refdes}.{pin.pin_name}"] else: @@ -203,7 +203,7 @@ def import_kicad( locals: Mapping[str, Any] = {}, *, nodes: Mapping[str, Optional[BasePort]] = {}, - conversions: Mapping[str, CircuitPort] = {}, + conversions: Mapping[str, Union[CircuitPort, HasPassivePort]] = {}, auto_adapt: bool = False, ) -> None: # ideally SYMBOL_MAP would be a class variable, but this causes a import loop with Opamp, @@ -324,8 +324,16 @@ def import_kicad( and isinstance(boundary_port, CircuitPort) and not isinstance(boundary_port, Passive) ): + # TODO remove after full compositional passive refactor #114 adapted = cast(Passive, net_ports[0]).adapt_to(boundary_port.__class__()) self.connect(adapted, boundary_port) + elif ( + auto_adapt + and can_adapt + and isinstance(boundary_port, HasPassivePort) + and not isinstance(boundary_port, Passive) + ): + self.connect(net_ports[0], boundary_port.net) else: self.connect(connection, boundary_port) diff --git a/edg/electronics_model/NetlistGenerator.py b/edg/electronics_model/NetlistGenerator.py index c0c1037a9..c8cf93974 100644 --- a/edg/electronics_model/NetlistGenerator.py +++ b/edg/electronics_model/NetlistGenerator.py @@ -276,6 +276,17 @@ def name_net(net: Iterable[TransformUtil.Path], path_ordering: Dict[TransformUti ), # prefer earlier paths ] + def prune_net_component(path: TransformUtil.Path) -> TransformUtil.Path: + # prune out the net interior link, if it exists + if path.ports and len(path.ports) > 1 and path.ports[-1] == "net": + return path._replace(ports=path.ports[:-1]) + elif path.links and len(path.links) > 1 and path.links[-1] == "net": + return path._replace(links=path.links[:-1]) + else: + return path + + net = map(prune_net_component, net) + def pin_name_goodness(pin1: TransformUtil.Path, pin2: TransformUtil.Path) -> int: assert not pin1.params and not pin2.params for test in CRITERIA: diff --git a/edg/electronics_model/PassivePort.py b/edg/electronics_model/PassivePort.py index 4fbe5d528..25bc958bd 100644 --- a/edg/electronics_model/PassivePort.py +++ b/edg/electronics_model/PassivePort.py @@ -1,13 +1,17 @@ from __future__ import annotations -from typing import TypeVar, Type, Dict, Mapping +from typing import TypeVar, Type, Dict, Union + +from typing_extensions import TYPE_CHECKING from ..core import * -from .GroundPort import Ground -from .AnalogPort import AnalogSource, AnalogSink -from .CircuitBlock import CircuitLink, CircuitPortBridge, CircuitPortAdapter -from .DigitalPorts import DigitalSource, DigitalSink, DigitalBidir -from .VoltagePorts import CircuitPort, VoltageSource, VoltageSink +from .CircuitBlock import CircuitPort, CircuitLink, CircuitPortBridge, CircuitPortAdapter, KicadImportablePortAdapter + +if TYPE_CHECKING: + from .GroundPort import Ground + from .VoltagePorts import VoltageSource, VoltageSink + from .DigitalPorts import DigitalSource, DigitalSink, DigitalBidir + from .AnalogPort import AnalogSource, AnalogSink class PassiveLink(CircuitLink): @@ -18,14 +22,16 @@ def __init__(self) -> None: self.passives = self.Port(Vector(Passive())) -class PassiveAdapterGround(CircuitPortAdapter[Ground]): +class PassiveAdapterGround(CircuitPortAdapter["Ground"]): def __init__(self, voltage_limits: RangeLike = RangeExpr.ALL): + from .GroundPort import Ground + super().__init__() self.src = self.Port(Passive()) self.dst = self.Port(Ground(voltage_limits=voltage_limits)) -class PassiveAdapterVoltageSource(CircuitPortAdapter[VoltageSource]): +class PassiveAdapterVoltageSource(CircuitPortAdapter["VoltageSource"]): # TODO we can't use **kwargs b/c init_in_parent needs the initializer list def __init__( self, @@ -34,6 +40,8 @@ def __init__( reverse_voltage_limits: RangeLike = RangeExpr.EMPTY, reverse_current_draw: RangeLike = RangeExpr.EMPTY, ): + from .VoltagePorts import VoltageSource + super().__init__() self.src = self.Port(Passive()) self.dst = self.Port( @@ -46,7 +54,7 @@ def __init__( ) -class PassiveAdapterVoltageSink(CircuitPortAdapter[VoltageSink]): +class PassiveAdapterVoltageSink(CircuitPortAdapter["VoltageSink"]): # TODO we can't use **kwargs b/c the init hook needs an initializer list def __init__( self, @@ -55,6 +63,8 @@ def __init__( reverse_voltage_out: RangeLike = RangeExpr.EMPTY, reverse_current_limits: RangeLike = RangeExpr.EMPTY, ): + from .VoltagePorts import VoltageSink + super().__init__() self.src = self.Port(Passive()) self.dst = self.Port( @@ -67,7 +77,7 @@ def __init__( ) -class PassiveAdapterDigitalSource(CircuitPortAdapter[DigitalSource]): +class PassiveAdapterDigitalSource(CircuitPortAdapter["DigitalSource"]): # TODO we can't use **kwargs b/c the init hook needs an initializer list def __init__( self, @@ -80,6 +90,8 @@ def __init__( low_driver: BoolLike = True, _bridged_internal: BoolLike = False, ): + from .DigitalPorts import DigitalSource + super().__init__() self.src = self.Port(Passive()) self.dst = self.Port( @@ -96,7 +108,7 @@ def __init__( ) -class PassiveAdapterDigitalSink(CircuitPortAdapter[DigitalSink]): +class PassiveAdapterDigitalSink(CircuitPortAdapter["DigitalSink"]): # TODO we can't use **kwargs b/c the init hook needs an initializer list def __init__( self, @@ -107,6 +119,8 @@ def __init__( pulldown_capable: BoolLike = False, _bridged_internal: BoolLike = False, ): + from .DigitalPorts import DigitalSink + super().__init__() self.src = self.Port(Passive()) self.dst = self.Port( @@ -121,7 +135,7 @@ def __init__( ) -class PassiveAdapterDigitalBidir(CircuitPortAdapter[DigitalBidir]): +class PassiveAdapterDigitalBidir(CircuitPortAdapter["DigitalBidir"]): # TODO we can't use **kwargs b/c the init hook needs an initializer list def __init__( self, @@ -136,6 +150,8 @@ def __init__( pulldown_capable: BoolLike = False, _bridged_internal: BoolLike = False, ): + from .DigitalPorts import DigitalBidir + super().__init__() self.src = self.Port(Passive()) self.dst = self.Port( @@ -153,7 +169,7 @@ def __init__( ) -class PassiveAdapterAnalogSource(CircuitPortAdapter[AnalogSource]): +class PassiveAdapterAnalogSource(KicadImportablePortAdapter["AnalogSource"]): # TODO we can't use **kwargs b/c the init hook needs an initializer list def __init__( self, @@ -162,6 +178,8 @@ def __init__( current_limits: RangeLike = RangeExpr.ALL, impedance: RangeLike = RangeExpr.ZERO, ): + from .AnalogPort import AnalogSource + super().__init__() self.src = self.Port(Passive()) self.dst = self.Port( @@ -169,9 +187,10 @@ def __init__( voltage_out=voltage_out, signal_out=signal_out, current_limits=current_limits, impedance=impedance ) ) + self.connect(self.src, self.dst.net) -class PassiveAdapterAnalogSink(CircuitPortAdapter[AnalogSink]): +class PassiveAdapterAnalogSink(KicadImportablePortAdapter["AnalogSink"]): # TODO we can't use **kwargs b/c the init hook needs an initializer list def __init__( self, @@ -180,6 +199,8 @@ def __init__( current_draw: RangeLike = RangeExpr.ZERO, impedance: RangeLike = RangeExpr.INF, ): + from .AnalogPort import AnalogSink + super().__init__() self.src = self.Port(Passive()) self.dst = self.Port( @@ -190,6 +211,7 @@ def __init__( impedance=impedance, ) ) + self.connect(self.src, self.dst.net) class PassiveBridge(CircuitPortBridge): @@ -199,32 +221,48 @@ def __init__(self) -> None: self.inner_link = self.Port(Passive()) +class HasPassivePort(Port[Link]): + """A port that contains a single net as a passive port. + Some functionality may provide convenience functions on this to use the internal net.""" + + def __init__(self) -> None: + super().__init__() + self.net = self.Port(Passive()) + + +# TODO this should replace CircuitPort and should be the lowest level of abstraction port, #114 class Passive(CircuitPort[PassiveLink]): """Basic copper-only port, which can be adapted to a more strongly typed Voltage/Digital/Analog* port""" - adapter_type_map: Dict[Type[Port], Type[CircuitPortAdapter]] = { - Ground: PassiveAdapterGround, - VoltageSource: PassiveAdapterVoltageSource, - VoltageSink: PassiveAdapterVoltageSink, - DigitalSink: PassiveAdapterDigitalSink, - DigitalSource: PassiveAdapterDigitalSource, - DigitalBidir: PassiveAdapterDigitalBidir, - AnalogSink: PassiveAdapterAnalogSink, - AnalogSource: PassiveAdapterAnalogSource, - } link_type = PassiveLink bridge_type = PassiveBridge - AdaptTargetType = TypeVar("AdaptTargetType", bound=CircuitPort) + AdaptTargetType = TypeVar("AdaptTargetType", bound=Union[CircuitPort, HasPassivePort]) def adapt_to(self, that: AdaptTargetType) -> AdaptTargetType: + from .GroundPort import Ground + from .VoltagePorts import VoltageSource, VoltageSink + from .DigitalPorts import DigitalSource, DigitalSink, DigitalBidir + from .AnalogPort import AnalogSource, AnalogSink + + ADAPTER_TYPE_MAP: Dict[Type[Port], Type[PortAdapter]] = { + Ground: PassiveAdapterGround, + VoltageSource: PassiveAdapterVoltageSource, + VoltageSink: PassiveAdapterVoltageSink, + DigitalSink: PassiveAdapterDigitalSink, + DigitalSource: PassiveAdapterDigitalSource, + DigitalBidir: PassiveAdapterDigitalBidir, + AnalogSink: PassiveAdapterAnalogSink, + AnalogSource: PassiveAdapterAnalogSource, + } + # this is an experimental style that takes a port that has initializers but is not bound # and automatically creates an adapter from it, by matching the port parameter fields # with the adapter constructor argument fields by name assert isinstance(that, Port), "adapter target must be port" assert not that._is_bound(), "adapter target must be model only" - assert that.__class__ in self.adapter_type_map, f"no adapter to {that.__class__}" - adapter_cls = self.adapter_type_map[that.__class__] + assert that.__class__ in ADAPTER_TYPE_MAP, f"no adapter to {that.__class__}" + adapter_cls = ADAPTER_TYPE_MAP[that.__class__] # map initializers from that to constructor args adapter_init_kwargs = {} # make everything kwargs for simplicity diff --git a/edg/electronics_model/VoltagePorts.py b/edg/electronics_model/VoltagePorts.py index 5c6adeaac..081644db5 100644 --- a/edg/electronics_model/VoltagePorts.py +++ b/edg/electronics_model/VoltagePorts.py @@ -5,7 +5,7 @@ from typing_extensions import override from ..core import * -from .CircuitBlock import CircuitPort, CircuitPortBridge, CircuitLink, CircuitPortAdapter +from .CircuitBlock import CircuitPort, CircuitPortBridge, CircuitLink, CircuitPortAdapter, KicadImportablePortAdapter from .GroundPort import GroundLink, GroundReference from .Units import Volt, Ohm, Amp @@ -190,7 +190,7 @@ class VoltageBase(CircuitPort[VoltageLink]): # TODO: support isolation domains and offset grounds # these are here (instead of in VoltageSource) since the port may be on the other side of a bridge - def as_ground(self, current_draw: RangeLike) -> GroundReference: + def as_ground(self, current_draw: RangeLike = RangeExpr.ZERO) -> GroundReference: """Adapts this port to a ground. Current draw is the current drawn from this port, and is required since ground does not model current draw. """ @@ -255,12 +255,12 @@ def __init__(self) -> None: self.assign(self.src.current_draw, self.dst.link().current_drawn) # TODO might be an overestimate -class VoltageSinkAdapterAnalogSource(CircuitPortAdapter["AnalogSource"]): +class VoltageSinkAdapterAnalogSource(KicadImportablePortAdapter["AnalogSource"]): def __init__(self) -> None: from .AnalogPort import AnalogSource super().__init__() - self.src = self.Port(VoltageSink(current_draw=RangeExpr())) + self.src = self.Port(VoltageSink.empty()) self.dst = self.Port( AnalogSource( voltage_out=self.src.link().voltage, @@ -268,9 +268,7 @@ def __init__(self) -> None: impedance=(0, 0) * Ohm, # TODO not actually true, but pretty darn low? ) ) - - # TODO might be an overestimate - self.assign(self.src.current_draw, self.dst.link().current_drawn) + self.connect(self.dst.net.adapt_to(VoltageSink(current_draw=self.dst.link().current_drawn)), self.src) class VoltageSource(VoltageBase): diff --git a/edg/electronics_model/test_kicad_import_blackbox.py b/edg/electronics_model/test_kicad_import_blackbox.py index eafcbcafd..4b21f1200 100644 --- a/edg/electronics_model/test_kicad_import_blackbox.py +++ b/edg/electronics_model/test_kicad_import_blackbox.py @@ -122,8 +122,9 @@ def test_import_blackbox_autoadapt(self) -> None: expected_conn = edgir.ValueExpr() expected_conn.exported.exterior_port.ref.steps.add().name = "out" - expected_conn.exported.internal_block_port.ref.steps.add().name = "(adapter)res.b" - expected_conn.exported.internal_block_port.ref.steps.add().name = "dst" + expected_conn.exported.exterior_port.ref.steps.add().name = "net" + expected_conn.exported.internal_block_port.ref.steps.add().name = "res" + expected_conn.exported.internal_block_port.ref.steps.add().name = "b" self.assertIn(expected_conn, constraints) # blackbox definition not checked again diff --git a/edg/parts/BoostConverter_TexasInstruments.py b/edg/parts/BoostConverter_TexasInstruments.py index 1be48d352..704287c07 100644 --- a/edg/parts/BoostConverter_TexasInstruments.py +++ b/edg/parts/BoostConverter_TexasInstruments.py @@ -74,9 +74,9 @@ def contents(self) -> None: self.connect(self.fb.output, self.ic.fb) # TODO 10pF is the datasheet-suggested starting, point, but equation also available - self.cff = self.Block(Capacitor(10 * pFarad(tol=0.2), voltage=self.pwr_in.link().voltage)) - self.connect(self.cff.pos.adapt_to(VoltageSink()), self.pwr_out) - self.connect(self.cff.neg.adapt_to(AnalogSink()), self.ic.fb) + self.cff = self.Block(AnalogCapacitor(10 * pFarad(tol=0.2))).connected( + gnd=self.pwr_out.as_ground(), io=self.ic.fb + ) # power path calculation here - we don't use BoostConverterPowerPath since this IC operates in DCM # and has different component sizing guidelines @@ -261,13 +261,10 @@ def contents(self) -> None: self.connect(self.power_path.switch, self.ic.sw) self.cf = self.Block( - Capacitor( # arbitrary target tolerance for zero location for capacitance flexibility + AnalogCapacitor( # arbitrary target tolerance for zero location for capacitance flexibility capacitance=(1 / (8000 * Ohm(tol=0.35))).shrink_multiply(1 / (2 * math.pi * self.fb.actual_rtop)), - voltage=self.pwr_out.voltage_out, ) - ) - self.connect(self.cf.neg.adapt_to(AnalogSink()), self.ic.fb) - self.connect(self.cf.pos.adapt_to(VoltageSink()), self.pwr_out) + ).connected(gnd=self.pwr_out.as_ground(), io=self.ic.fb) self.rect = self.Block( Diode( diff --git a/edg/parts/DacI2c_Mcp4728.py b/edg/parts/DacI2c_Mcp4728.py index 21fa92956..d2c109b58 100644 --- a/edg/parts/DacI2c_Mcp4728.py +++ b/edg/parts/DacI2c_Mcp4728.py @@ -106,9 +106,9 @@ def generate(self) -> None: self.vdd_cap[1] = self.Block(DecouplingCapacitor(10 * uFarad(tol=0.2))).connected(self.gnd, self.pwr) if self.get(self.output_caps): - self.out_cap = ElementDict[Capacitor]() + self.out_cap = ElementDict[AnalogCapacitor]() for i, out_port in [(0, self.out0), (1, self.out1), (2, self.out2), (3, self.out3)]: if self.get(out_port.is_connected()): - self.out_cap[i] = out_cap = self.Block(Capacitor(0.1 * uFarad(tol=0.2), out_port.link().voltage)) - self.connect(out_cap.pos.adapt_to(AnalogSink()), out_port) - self.connect(out_cap.neg.adapt_to(Ground()), self.gnd) + self.out_cap[i] = self.Block(AnalogCapacitor(0.1 * uFarad(tol=0.2))).connected( + gnd=self.gnd, io=out_port + ) diff --git a/edg/parts/ResistiveSensor.py b/edg/parts/ResistiveSensor.py index a32234c1c..2bae0ebd8 100644 --- a/edg/parts/ResistiveSensor.py +++ b/edg/parts/ResistiveSensor.py @@ -15,7 +15,9 @@ def __init__(self, resistance_range: RangeLike, fixed_resistance: RangeLike) -> self.fixed_resistance = self.ArgParameter(fixed_resistance) self.input = self.Port(VoltageSink.empty(), [Power]) - self.output = self.Port(AnalogSource.empty(), [Output]) + self.output = self.Port( + AnalogSource(voltage_out=RangeExpr(), signal_out=RangeExpr(), impedance=RangeExpr()), [Output] + ) self.gnd = self.Port(Ground.empty(), [Common]) # TODO deduplicate with ResistiveDivider class @@ -31,13 +33,10 @@ def contents(self) -> None: output_voltage = ResistiveDivider.divider_output( self.input.link().voltage, self.gnd.link().voltage, self.actual_ratio ) - self.connect( - self.output, - self.top.b.adapt_to( - AnalogSource(voltage_out=output_voltage, signal_out=output_voltage, impedance=self.actual_impedance) - ), - self.bot.pins.request("1").adapt_to(AnalogSink()), - ) + self.assign(self.output.voltage_out, output_voltage) + self.assign(self.output.signal_out, output_voltage) + self.assign(self.output.impedance, self.actual_impedance) + self.connect(self.output.net, self.top.b, self.bot.pins.request("1")) self.connect(self.gnd, self.bot.pins.request("2").adapt_to(Ground())) self.assign(self.actual_impedance, 1 / (1 / self.top.actual_resistance + 1 / self.resistance_range)) diff --git a/edg/parts/SpeakerDriver_Analog.py b/edg/parts/SpeakerDriver_Analog.py index cfbdead4b..3cdf46886 100644 --- a/edg/parts/SpeakerDriver_Analog.py +++ b/edg/parts/SpeakerDriver_Analog.py @@ -21,9 +21,8 @@ def __init__(self) -> None: self.inp = self.Port(Passive()) # TODO these aren't actually documented w/ specs =( self.inm = self.Port(Passive()) - speaker_port = AnalogSource() - self.vo1 = self.Port(speaker_port) - self.vo2 = self.Port(speaker_port) + self.vo1 = self.Port(Passive()) + self.vo2 = self.Port(Passive()) self.byp = self.Port(Passive()) @@ -57,8 +56,8 @@ def __init__(self) -> None: self.pwr = self.Export(self.ic.pwr, [Power]) self.gnd = self.Export(self.ic.gnd, [Common]) - self.sig = self.Port(AnalogSink.empty(), [Input]) - self.spk = self.Port(SpeakerDriverPort(AnalogSource.empty()), [Output]) + self.sig = self.Port(AnalogSink(), [Input]) + self.spk = self.Port(SpeakerDriverPort(AnalogSource()), [Output]) @override def contents(self) -> None: @@ -86,11 +85,11 @@ def contents(self) -> None: ) self.sig_res = self.Block(Resistor(resistance=20 * kOhm(tol=0.2))) self.fb_res = self.Block(Resistor(resistance=20 * kOhm(tol=0.2))) - self.connect(self.sig, self.sig_cap.neg.adapt_to(AnalogSink())) + self.connect(self.sig.net, self.sig_cap.neg) self.connect(self.sig_cap.pos, self.sig_res.a) self.connect(self.sig_res.b, self.fb_res.a, self.ic.inm) - self.connect(self.spk.a, self.ic.vo1, self.fb_res.b.adapt_to(AnalogSink())) - self.connect(self.spk.b, self.ic.vo2) + self.connect(self.spk.a.net, self.ic.vo1, self.fb_res.b) + self.connect(self.spk.b.net, self.ic.vo2) self.connect(self.byp_cap.pos, self.ic.inp, self.ic.byp) @@ -118,11 +117,11 @@ def __init__(self) -> None: self.inp = self.Port(input_port) self.inn = self.Port(input_port) - speaker_port = AnalogSource( - impedance=RangeExpr.ZERO # TODO output impedance not given, but maximum Rl of 3.2-6.4ohm + self.vo = self.Port( + SpeakerDriverPort( + AnalogSource(impedance=RangeExpr.ZERO) # TODO output impedance not given, but maximum Rl of 3.2-6.4ohm + ) ) - self.vo1 = self.Port(speaker_port) - self.vo2 = self.Port(speaker_port) @override def contents(self) -> None: @@ -137,8 +136,8 @@ def contents(self) -> None: "1": self.pwr, # /SHDN "9": self.gnd, # exposed pad, "must be soldered to a grounded pad" "6": self.pwr, - "8": self.vo1, - "5": self.vo2, + "8": self.vo.a, # vo1 + "5": self.vo.b, # vo2 }, mfr="Texas Instruments", part="TPA2005D1", @@ -160,8 +159,8 @@ def __init__(self, gain: RangeLike = Range.from_tolerance(20, 0.2)): self.pwr = self.Export(self.ic.pwr, [Power]) self.gnd = self.Export(self.ic.gnd, [Common]) - self.sig = self.Port(AnalogSink.empty(), [Input]) - self.spk = self.Port(SpeakerDriverPort(AnalogSource.empty()), [Output]) + self.sig = self.Port(AnalogSink(), [Input]) + self.spk = self.Export(self.ic.vo, [Output]) self.gain = self.ArgParameter(gain) @@ -198,7 +197,7 @@ def contents(self) -> None: voltage=self.sig.link().voltage, ) ) - self.connect(self.sig, self.inp_cap.neg.adapt_to(AnalogSink())) + self.connect(self.sig.net, self.inp_cap.neg) self.connect(self.inp_cap.pos, self.inp_res.a) self.connect(self.inp_res.b.adapt_to(AnalogSource()), self.ic.inp) @@ -215,9 +214,6 @@ def contents(self) -> None: self.connect(self.inn_cap.pos, self.inn_res.a) self.connect(self.inn_res.b.adapt_to(AnalogSource()), self.ic.inn) - self.connect(self.spk.a, self.ic.vo1) - self.connect(self.spk.b, self.ic.vo2) - class Pam8302a_Device(InternalSubcircuit, JlcPart, FootprintBlock): def __init__(self) -> None: @@ -238,11 +234,11 @@ def __init__(self) -> None: self.inp = self.Port(input_port) self.inn = self.Port(input_port) - speaker_port = AnalogSource( - impedance=RangeExpr.ZERO # TODO output impedance not given, but maximum Rl of 3.2-6.4ohm + self.vo = self.Port( + SpeakerDriverPort( + AnalogSource(impedance=RangeExpr.ZERO) # TODO output impedance not given, but maximum Rl of 3.2-6.4ohm + ) ) - self.vop = self.Port(speaker_port) - self.von = self.Port(speaker_port) @override def contents(self) -> None: @@ -254,10 +250,10 @@ def contents(self) -> None: # pin 2 is NC "3": self.inp, "4": self.inn, - "5": self.vop, + "5": self.vo.a, # vop "6": self.pwr, "7": self.gnd, - "8": self.von, + "8": self.vo.b, # von }, mfr="Diodes Incorporated", part="PAM8302AASCR", @@ -278,7 +274,7 @@ def __init__(self) -> None: self.gnd = self.Export(self.ic.gnd, [Common]) self.sig = self.Port(AnalogSink.empty(), [Input]) - self.spk = self.Port(SpeakerDriverPort(AnalogSource.empty()), [Output]) + self.spk = self.Export(self.ic.vo, [Output]) @override def contents(self) -> None: @@ -302,6 +298,3 @@ def contents(self) -> None: self.inn_cap = self.Block(in_cap_model) self.connect(self.gnd, self.inn_cap.neg.adapt_to(Ground())) self.connect(self.inn_cap.pos.adapt_to(AnalogSource()), self.ic.inn) - - self.connect(self.spk.a, self.ic.vop) - self.connect(self.spk.b, self.ic.von) diff --git a/edg/parts/SpeakerDriver_Max98357a.py b/edg/parts/SpeakerDriver_Max98357a.py index 1990323ca..6abca4173 100644 --- a/edg/parts/SpeakerDriver_Max98357a.py +++ b/edg/parts/SpeakerDriver_Max98357a.py @@ -1,9 +1,10 @@ -from typing import Dict +from typing import Dict, Union from typing_extensions import override from ..abstract_parts import * from .JlcPart import JlcPart +from ..electronics_model.PassivePort import HasPassivePort class Max98357a_Device(InternalSubcircuit, JlcPart, SelectorFootprint, PartsTablePart, GeneratorBlock, FootprintBlock): @@ -38,7 +39,7 @@ def generate(self) -> None: or self.get(self.footprint_spec) == "Package_DFN_QFN:QFN-16-1EP_3x3mm_P0.5mm_EP1.45x1.45mm" ): footprint = "Package_DFN_QFN:QFN-16-1EP_3x3mm_P0.5mm_EP1.45x1.45mm" - pinning: Dict[str, CircuitPort] = { + pinning: Dict[str, Union[CircuitPort, HasPassivePort]] = { "4": self.vdd, # hard tied to left mode only TODO selectable SD_MODE "7": self.vdd, "8": self.vdd, diff --git a/edg/parts/Speakers.py b/edg/parts/Speakers.py index 5b27312bc..4416caebe 100644 --- a/edg/parts/Speakers.py +++ b/edg/parts/Speakers.py @@ -16,8 +16,9 @@ class ConnectorSpeaker(Speaker): def __init__(self, impedance: RangeLike = 8 * Ohm(tol=0)): super().__init__() + self.input.init_from(SpeakerPort(AnalogSink(impedance=impedance))) self.conn = self.Block(PassiveConnector()) - self.connect(self.input.a, self.conn.pins.request("1").adapt_to(AnalogSink(impedance=impedance))) - self.connect(self.input.b, self.conn.pins.request("2").adapt_to(AnalogSink(impedance=impedance))) + self.connect(self.input.a.net, self.conn.pins.request("1")) + self.connect(self.input.b.net, self.conn.pins.request("2")) diff --git a/examples/Multimeter/Multimeter.net b/examples/Multimeter/Multimeter.net index 9ada53b2f..0e89f83fc 100644 --- a/examples/Multimeter/Multimeter.net +++ b/examples/Multimeter/Multimeter.net @@ -1613,7 +1613,7 @@ (node (ref R17) (pin 2)) (node (ref R18) (pin 1)) (node (ref U8) (pin 3))) -(net (code 57) (name "inn_merge") +(net (code 57) (name "inn.port") (node (ref J5) (pin 1)) (node (ref U9) (pin 4)) (node (ref U12) (pin 4)) diff --git a/examples/Multimeter/Multimeter.svgpcb.js b/examples/Multimeter/Multimeter.svgpcb.js index 2c44e8d9d..74f0c1dfa 100644 --- a/examples/Multimeter/Multimeter.svgpcb.js +++ b/examples/Multimeter/Multimeter.svgpcb.js @@ -593,7 +593,7 @@ board.setNetlist([ {name: "spk_drv.inp_res.a", pads: [["R15", "1"], ["C13", "1"]]}, {name: "spk_drv.inn_res.a", pads: [["R16", "1"], ["C14", "1"]]}, {name: "ref_div.output", pads: [["R17", "2"], ["R18", "1"], ["U8", "3"]]}, - {name: "inn_merge", pads: [["J5", "1"], ["U9", "4"], ["U12", "4"], ["U14", "6"]]}, + {name: "inn.port", pads: [["J5", "1"], ["U9", "4"], ["U12", "4"], ["U14", "6"]]}, {name: "inp.port", pads: [["J6", "1"], ["R19", "1"], ["D7", "1"]]}, {name: "measure.range.switch.sw[0_0].com", pads: [["U10", "4"], ["U12", "3"]]}, {name: "measure.range.switch.sw[0_1].com", pads: [["U11", "4"], ["U12", "1"]]}, diff --git a/examples/RobotCrawler/RobotCrawler.net b/examples/RobotCrawler/RobotCrawler.net index f43d27f11..3a16ad653 100644 --- a/examples/RobotCrawler/RobotCrawler.net +++ b/examples/RobotCrawler/RobotCrawler.net @@ -365,7 +365,7 @@ (footprint "Capacitor_SMD:C_0603_1608Metric") (property (name "Sheetname") (value "reg_14v")) (property (name "Sheetfile") (value "edg.parts.BoostConverter_TexasInstruments.Tps61040")) - (property (name "edg_path") (value "reg_14v.cff")) + (property (name "edg_path") (value "reg_14v.cff.cap")) (property (name "edg_short_path") (value "reg_14v.cff")) (property (name "edg_refdes") (value "RC5")) (property (name "edg_part") (value "CL10C100JB8NNNC (Samsung Electro-Mechanics)")) @@ -1694,7 +1694,7 @@ (node (ref RR14) (pin 1))) (net (code 4) (name "Rv14") (node (ref RR1) (pin 1)) - (node (ref RC5) (pin 1)) + (node (ref RC5) (pin 2)) (node (ref RD1) (pin 1)) (node (ref RC7) (pin 1)) (node (ref RTP4) (pin 1)) @@ -1824,7 +1824,7 @@ (node (ref RU3) (pin 3)) (node (ref RR1) (pin 2)) (node (ref RR2) (pin 1)) - (node (ref RC5) (pin 2))) + (node (ref RC5) (pin 1))) (net (code 41) (name "Rmcu.program_uart_node.a_tx") (node (ref RU6) (pin 37)) (node (ref RJ16) (pin 3))) diff --git a/examples/RobotCrawler/RobotCrawler.svgpcb.js b/examples/RobotCrawler/RobotCrawler.svgpcb.js index fc541e07f..5b34657ed 100644 --- a/examples/RobotCrawler/RobotCrawler.svgpcb.js +++ b/examples/RobotCrawler/RobotCrawler.svgpcb.js @@ -150,7 +150,7 @@ const RR2 = board.add(R_0603_1608Metric, { translate: pt(2.604, 2.906), rotate: 0, id: 'RR2' }) -// reg_14v.cff +// reg_14v.cff.cap const RC5 = board.add(C_0603_1608Metric, { translate: pt(2.760, 2.906), rotate: 0, id: 'RC5' @@ -615,7 +615,7 @@ board.setNetlist([ {name: "Rvbatt", pads: [["RJ1", "2"], ["RJ2", "2"], ["RJ3", "2"], ["RJ4", "2"], ["RJ5", "2"], ["RJ6", "2"], ["RJ7", "2"], ["RJ8", "2"], ["RJ9", "2"], ["RJ10", "2"], ["RJ11", "2"], ["RJ12", "2"], ["RJ13", "2"], ["RJ14", "2"], ["RJ15", "2"], ["RTP1", "1"], ["RU2", "2"], ["RC3", "1"], ["RU3", "4"], ["RU3", "5"], ["RL1", "1"], ["RC6", "1"], ["RU4", "3"], ["RC8", "1"], ["RU5", "3"], ["RC10", "1"], ["RD10", "2"], ["RC40", "1"], ["RD11", "2"], ["RC41", "1"], ["RD12", "2"], ["RC42", "1"], ["RD13", "2"], ["RC43", "1"], ["RD14", "2"], ["RC44", "1"], ["RD15", "2"], ["RC45", "1"], ["RD16", "2"], ["RC46", "1"], ["RD17", "2"], ["RC47", "1"], ["RD18", "2"], ["RC48", "1"], ["RD19", "2"], ["RC49", "1"]]}, {name: "Rgnd", pads: [["RJ1", "1"], ["RJ2", "3"], ["RJ3", "3"], ["RJ4", "3"], ["RJ5", "3"], ["RJ6", "3"], ["RJ7", "3"], ["RJ8", "3"], ["RJ9", "3"], ["RJ10", "3"], ["RJ11", "3"], ["RJ12", "3"], ["RJ13", "3"], ["RU1", "1"], ["RU1", "2"], ["RU1", "3"], ["RU1", "6"], ["RU1", "7"], ["RC1", "2"], ["RC2", "2"], ["RJ14", "3"], ["RJ15", "3"], ["RTP2", "1"], ["RU2", "1"], ["RC3", "2"], ["RC4", "2"], ["RU3", "2"], ["RR2", "2"], ["RC6", "2"], ["RC7", "2"], ["RU4", "1"], ["RC8", "2"], ["RC9", "2"], ["RU5", "1"], ["RC10", "2"], ["RC11", "2"], ["RU6", "1"], ["RU6", "40"], ["RU6", "41"], ["RC12", "2"], ["RC13", "2"], ["RJ16", "5"], ["RC14", "2"], ["RJ17", "5"], ["RU7", "23"], ["RU7", "35"], ["RU7", "44"], ["RU7", "47"], ["RU7", "8"], ["RC15", "2"], ["RC16", "2"], ["RC17", "2"], ["RC18", "2"], ["RC19", "2"], ["RC20", "2"], ["RJ18", "5"], ["RU8", "19"], ["RU8", "57"], ["RC21", "2"], ["RC22", "2"], ["RC23", "2"], ["RC24", "2"], ["RC25", "2"], ["RC26", "2"], ["RC27", "2"], ["RC28", "2"], ["RU9", "4"], ["RC29", "2"], ["RC30", "2"], ["RC31", "2"], ["RC32", "2"], ["RR6", "2"], ["RR7", "2"], ["RR8", "2"], ["RR9", "2"], ["RR10", "2"], ["RR11", "2"], ["RJ19", "1"], ["RJ19", "10"], ["RJ19", "11"], ["RJ19", "12"], ["RJ19", "14"], ["RJ19", "15"], ["RJ19", "16"], ["RJ19", "21"], ["RJ19", "22"], ["RJ19", "23"], ["RJ19", "24"], ["RJ19", "25"], ["RJ19", "26"], ["RJ19", "31"], ["RJ19", "7"], ["RR12", "2"], ["RC33", "2"], ["RC34", "2"], ["RC35", "2"], ["RC36", "2"], ["RD9", "1"], ["RJ20", "10"], ["RJ20", "17"], ["RJ20", "23"], ["RC37", "2"], ["RC38", "2"], ["RC39", "2"], ["RD10", "4"], ["RC40", "2"], ["RD11", "4"], ["RC41", "2"], ["RD12", "4"], ["RC42", "2"], ["RD13", "4"], ["RC43", "2"], ["RD14", "4"], ["RC44", "2"], ["RD15", "4"], ["RC45", "2"], ["RD16", "4"], ["RC46", "2"], ["RD17", "4"], ["RC47", "2"], ["RD18", "4"], ["RC48", "2"], ["RD19", "4"], ["RC49", "2"]]}, {name: "Rv3v3", pads: [["RU1", "12"], ["RU1", "5"], ["RU1", "8"], ["RC1", "1"], ["RC2", "1"], ["RU2", "3"], ["RC4", "1"], ["RTP3", "1"], ["RU6", "2"], ["RC12", "1"], ["RC13", "1"], ["RJ16", "1"], ["RR3", "1"], ["RJ17", "1"], ["RU7", "1"], ["RU7", "24"], ["RU7", "36"], ["RU7", "48"], ["RU7", "9"], ["RC15", "1"], ["RC16", "1"], ["RC17", "1"], ["RC18", "1"], ["RC19", "1"], ["RC20", "1"], ["RJ18", "1"], ["RU8", "1"], ["RU8", "10"], ["RU8", "22"], ["RU8", "33"], ["RU8", "42"], ["RU8", "43"], ["RU8", "44"], ["RU8", "48"], ["RU8", "49"], ["RC21", "1"], ["RC22", "1"], ["RC23", "1"], ["RC24", "1"], ["RC25", "1"], ["RC26", "1"], ["RC27", "1"], ["RC28", "1"], ["RU9", "8"], ["RC29", "1"], ["RR4", "1"], ["RR5", "1"], ["RJ19", "13"], ["RJ19", "17"], ["RJ19", "8"], ["RC35", "1"], ["RJ20", "14"], ["RC37", "1"], ["RR14", "1"]]}, - {name: "Rv14", pads: [["RR1", "1"], ["RC5", "1"], ["RD1", "1"], ["RC7", "1"], ["RTP4", "1"], ["RJ19", "27"], ["RJ19", "5"], ["RC36", "1"]]}, + {name: "Rv14", pads: [["RR1", "1"], ["RC5", "2"], ["RD1", "1"], ["RC7", "1"], ["RTP4", "1"], ["RJ19", "27"], ["RJ19", "5"], ["RC36", "1"]]}, {name: "Rv2v5", pads: [["RU4", "2"], ["RC9", "1"], ["RJ20", "21"]]}, {name: "Rv1v2", pads: [["RU5", "2"], ["RC11", "1"], ["RJ20", "15"]]}, {name: "Ri2c_chain_0.scl", pads: [["RU1", "13"], ["RU6", "10"], ["RU7", "21"], ["RU8", "37"], ["RR4", "2"], ["RTP5", "1"], ["RJ19", "18"], ["RJ20", "20"]]}, @@ -651,7 +651,7 @@ board.setNetlist([ {name: "Rservos_cam[1].pwm", pads: [["RJ15", "1"], ["RU7", "29"]]}, {name: "Rservos_cam[1].fb", pads: [["RJ15", "4"], ["RU7", "16"]]}, {name: "Rreg_14v.ic.sw", pads: [["RU3", "1"], ["RL1", "2"], ["RD1", "2"]]}, - {name: "Rreg_14v.ic.fb", pads: [["RU3", "3"], ["RR1", "2"], ["RR2", "1"], ["RC5", "2"]]}, + {name: "Rreg_14v.ic.fb", pads: [["RU3", "3"], ["RR1", "2"], ["RR2", "1"], ["RC5", "1"]]}, {name: "Rmcu.program_uart_node.a_tx", pads: [["RU6", "37"], ["RJ16", "3"]]}, {name: "Rmcu.program_uart_node.b_tx", pads: [["RU6", "36"], ["RJ16", "4"]]}, {name: "Rmcu.program_en_node", pads: [["RU6", "3"], ["RJ16", "6"], ["RR3", "2"], ["RC14", "1"]]}, diff --git a/examples/UsbSourceMeasure/UsbSourceMeasure.net b/examples/UsbSourceMeasure/UsbSourceMeasure.net index d6849c3f2..0e948ee9a 100644 --- a/examples/UsbSourceMeasure/UsbSourceMeasure.net +++ b/examples/UsbSourceMeasure/UsbSourceMeasure.net @@ -569,7 +569,7 @@ (footprint "Capacitor_SMD:C_0603_1608Metric") (property (name "Sheetname") (value "reg_v12")) (property (name "Sheetfile") (value "edg.parts.BoostConverter_TexasInstruments.Lm2733")) - (property (name "edg_path") (value "reg_v12.cf")) + (property (name "edg_path") (value "reg_v12.cf.cap")) (property (name "edg_short_path") (value "reg_v12.cf")) (property (name "edg_refdes") (value "C16")) (property (name "edg_part") (value "CL10B221KB8NNNC (Samsung Electro-Mechanics)")) @@ -1241,7 +1241,7 @@ (footprint "Capacitor_SMD:C_0603_1608Metric") (property (name "Sheetname") (value "reg_vcontrol")) (property (name "Sheetfile") (value "edg.parts.BoostConverter_TexasInstruments.Lm2733")) - (property (name "edg_path") (value "reg_vcontrol.cf")) + (property (name "edg_path") (value "reg_vcontrol.cf.cap")) (property (name "edg_short_path") (value "reg_vcontrol.cf")) (property (name "edg_refdes") (value "C43")) (property (name "edg_part") (value "CL10C101JB8NNNC (Samsung Electro-Mechanics)")) @@ -3449,7 +3449,7 @@ (footprint "Capacitor_SMD:C_0603_1608Metric") (property (name "Sheetname") (value "dac")) (property (name "Sheetfile") (value "edg.parts.DacI2c_Mcp4728.Mcp4728")) - (property (name "edg_path") (value "dac.out_cap[0]")) + (property (name "edg_path") (value "dac.out_cap[0].cap")) (property (name "edg_short_path") (value "dac.out_cap[0]")) (property (name "edg_refdes") (value "C97")) (property (name "edg_part") (value "CC0603KRX7R9BB104 (YAGEO)")) @@ -3461,7 +3461,7 @@ (footprint "Capacitor_SMD:C_0603_1608Metric") (property (name "Sheetname") (value "dac")) (property (name "Sheetfile") (value "edg.parts.DacI2c_Mcp4728.Mcp4728")) - (property (name "edg_path") (value "dac.out_cap[1]")) + (property (name "edg_path") (value "dac.out_cap[1].cap")) (property (name "edg_short_path") (value "dac.out_cap[1]")) (property (name "edg_refdes") (value "C98")) (property (name "edg_part") (value "CC0603KRX7R9BB104 (YAGEO)")) @@ -3473,7 +3473,7 @@ (footprint "Capacitor_SMD:C_0603_1608Metric") (property (name "Sheetname") (value "dac")) (property (name "Sheetfile") (value "edg.parts.DacI2c_Mcp4728.Mcp4728")) - (property (name "edg_path") (value "dac.out_cap[2]")) + (property (name "edg_path") (value "dac.out_cap[2].cap")) (property (name "edg_short_path") (value "dac.out_cap[2]")) (property (name "edg_refdes") (value "C99")) (property (name "edg_part") (value "CC0603KRX7R9BB104 (YAGEO)")) @@ -3485,7 +3485,7 @@ (footprint "Capacitor_SMD:C_0603_1608Metric") (property (name "Sheetname") (value "dac")) (property (name "Sheetfile") (value "edg.parts.DacI2c_Mcp4728.Mcp4728")) - (property (name "edg_path") (value "dac.out_cap[3]")) + (property (name "edg_path") (value "dac.out_cap[3].cap")) (property (name "edg_short_path") (value "dac.out_cap[3]")) (property (name "edg_refdes") (value "C100")) (property (name "edg_part") (value "CC0603KRX7R9BB104 (YAGEO)")) @@ -4181,7 +4181,7 @@ (net (code 6) (name "v12") (node (ref R10) (pin 1)) (node (ref C15) (pin 1)) - (node (ref C16) (pin 1)) + (node (ref C16) (pin 2)) (node (ref D3) (pin 1)) (node (ref J5) (pin 2)) (node (ref C75) (pin 1)) @@ -4253,7 +4253,7 @@ (net (code 12) (name "vcontrol") (node (ref R20) (pin 1)) (node (ref C42) (pin 1)) - (node (ref C43) (pin 1)) + (node (ref C43) (pin 2)) (node (ref D7) (pin 1)) (node (ref TP8) (pin 1)) (node (ref U15) (pin 5)) @@ -4394,7 +4394,7 @@ (node (ref U4) (pin 3)) (node (ref R10) (pin 2)) (node (ref R11) (pin 1)) - (node (ref C16) (pin 2))) + (node (ref C16) (pin 1))) (net (code 36) (name "conv.reset") (node (ref U6) (pin 3)) (node (ref U7) (pin 3)) @@ -4473,7 +4473,7 @@ (node (ref U10) (pin 3)) (node (ref R20) (pin 2)) (node (ref R21) (pin 1)) - (node (ref C43) (pin 2))) + (node (ref C43) (pin 1))) (net (code 55) (name "filt_vcontroln.pwr_out") (node (ref FB2) (pin 2)) (node (ref U11) (pin 4)) diff --git a/examples/UsbSourceMeasure/UsbSourceMeasure.svgpcb.js b/examples/UsbSourceMeasure/UsbSourceMeasure.svgpcb.js index be7eb180d..6d8bc77b4 100644 --- a/examples/UsbSourceMeasure/UsbSourceMeasure.svgpcb.js +++ b/examples/UsbSourceMeasure/UsbSourceMeasure.svgpcb.js @@ -235,7 +235,7 @@ const C15 = board.add(C_0603_1608Metric, { translate: pt(6.213, 3.701), rotate: 0, id: 'C15' }) -// reg_v12.cf +// reg_v12.cf.cap const C16 = board.add(C_0603_1608Metric, { translate: pt(6.369, 3.701), rotate: 0, id: 'C16' @@ -515,7 +515,7 @@ const C42 = board.add(C_0805_2012Metric, { translate: pt(0.268, 4.033), rotate: 0, id: 'C42' }) -// reg_vcontrol.cf +// reg_vcontrol.cf.cap const C43 = board.add(C_0603_1608Metric, { translate: pt(0.370, 4.311), rotate: 0, id: 'C43' @@ -1435,22 +1435,22 @@ const C96 = board.add(C_0805_2012Metric, { translate: pt(1.539, 4.033), rotate: 0, id: 'C96' }) -// dac.out_cap[0] +// dac.out_cap[0].cap const C97 = board.add(C_0603_1608Metric, { translate: pt(1.396, 4.201), rotate: 0, id: 'C97' }) -// dac.out_cap[1] +// dac.out_cap[1].cap const C98 = board.add(C_0603_1608Metric, { translate: pt(1.552, 4.201), rotate: 0, id: 'C98' }) -// dac.out_cap[2] +// dac.out_cap[2].cap const C99 = board.add(C_0603_1608Metric, { translate: pt(1.240, 4.298), rotate: 0, id: 'C99' }) -// dac.out_cap[3] +// dac.out_cap[3].cap const C100 = board.add(C_0603_1608Metric, { translate: pt(1.396, 4.298), rotate: 0, id: 'C100' @@ -1607,13 +1607,13 @@ board.setNetlist([ {name: "vusb_ramp", pads: [["Q1", "5"], ["C2", "1"], ["C4", "1"], ["TP2", "1"], ["U2", "3"], ["C5", "1"], ["C7", "1"], ["R6", "1"], ["U5", "1"], ["R12", "1"]]}, {name: "v5", pads: [["R4", "1"], ["L1", "2"], ["C8", "1"], ["TP3", "1"], ["U4", "4"], ["U4", "5"], ["L3", "1"], ["C14", "1"], ["U6", "4"], ["C33", "1"], ["D4", "2"], ["U7", "4"], ["C35", "1"], ["D5", "2"], ["U8", "1"], ["U8", "3"], ["C37", "1"], ["U9", "1"], ["C39", "1"], ["U10", "4"], ["U10", "5"], ["L5", "1"], ["C41", "1"], ["D15", "4"], ["C86", "1"], ["D16", "4"], ["C87", "1"], ["D17", "4"], ["C88", "1"], ["D18", "4"], ["C89", "1"], ["D19", "4"], ["C90", "1"], ["D20", "4"], ["C91", "1"], ["C92", "1"], ["R87", "1"], ["Q14", "2"], ["U36", "4"], ["U36", "7"], ["U36", "8"], ["C93", "1"], ["C94", "1"]]}, {name: "v3v3", pads: [["U1", "4"], ["C1", "1"], ["R7", "1"], ["L2", "2"], ["C13", "1"], ["D2", "1"], ["TP4", "1"], ["U5", "4"], ["U5", "8"], ["C17", "1"], ["U25", "3"], ["U25", "4"], ["C67", "1"], ["C68", "1"], ["U26", "2"], ["C69", "1"], ["C70", "1"], ["J4", "1"], ["R66", "1"], ["D14", "2"], ["R68", "1"], ["R69", "1"], ["J5", "19"], ["J5", "20"], ["C73", "1"], ["C74", "1"], ["R71", "1"], ["U29", "16"], ["C78", "1"], ["U30", "5"], ["C81", "1"], ["R75", "1"], ["U31", "8"], ["C82", "1"], ["R80", "1"], ["U32", "5"], ["C83", "1"], ["U33", "4"], ["U33", "5"], ["C84", "1"], ["U34", "16"], ["U34", "2"], ["C85", "1"], ["R83", "1"], ["R84", "1"], ["J6", "2"], ["R89", "1"]]}, - {name: "v12", pads: [["R10", "1"], ["C15", "1"], ["C16", "1"], ["D3", "1"], ["J5", "2"], ["C75", "1"], ["C76", "1"]]}, + {name: "v12", pads: [["R10", "1"], ["C15", "1"], ["C16", "2"], ["D3", "1"], ["J5", "2"], ["C75", "1"], ["C76", "1"]]}, {name: "vconvin", pads: [["U5", "2"], ["R12", "2"], ["C18", "1"], ["C19", "1"], ["C20", "1"], ["C21", "1"], ["C22", "1"], ["C23", "1"], ["C24", "1"], ["Q4", "5"]]}, {name: "vconv", pads: [["C25", "1"], ["C26", "1"], ["C27", "1"], ["C28", "1"], ["C29", "1"], ["C30", "1"], ["C31", "1"], ["C32", "1"], ["Q6", "5"], ["D6", "1"], ["TP5", "1"], ["Q7", "2"], ["C56", "1"], ["C57", "1"], ["C58", "1"], ["R77", "1"], ["R81", "1"]]}, {name: "vanalog", pads: [["U8", "5"], ["C38", "1"], ["TP6", "1"], ["FB2", "1"], ["U12", "5"], ["C49", "1"], ["U13", "5"], ["C50", "1"], ["U14", "5"], ["C51", "1"], ["R88", "1"], ["U40", "8"], ["C110", "1"], ["U41", "8"], ["C111", "1"], ["U42", "8"], ["C112", "1"]]}, {name: "vref", pads: [["U9", "2"], ["TP7", "1"], ["R17", "1"], ["FB3", "1"], ["U38", "4"], ["C105", "1"]]}, {name: "vcenter", pads: [["R19", "2"], ["C40", "1"], ["R25", "1"], ["R38", "2"], ["U23", "6"], ["U24", "6"], ["J10", "1"], ["R90", "1"], ["U42", "3"]]}, - {name: "vcontrol", pads: [["R20", "1"], ["C42", "1"], ["C43", "1"], ["D7", "1"], ["TP8", "1"], ["U15", "5"], ["C54", "1"], ["U16", "5"], ["C55", "1"], ["U17", "5"], ["C60", "1"], ["U19", "5"], ["C61", "1"], ["U21", "5"], ["C62", "1"], ["U23", "8"], ["C64", "1"], ["U24", "8"], ["C65", "1"], ["U39", "8"], ["C109", "1"]]}, + {name: "vcontrol", pads: [["R20", "1"], ["C42", "1"], ["C43", "2"], ["D7", "1"], ["TP8", "1"], ["U15", "5"], ["C54", "1"], ["U16", "5"], ["C55", "1"], ["U17", "5"], ["C60", "1"], ["U19", "5"], ["C61", "1"], ["U21", "5"], ["C62", "1"], ["U23", "8"], ["C64", "1"], ["U24", "8"], ["C65", "1"], ["U39", "8"], ["C109", "1"]]}, {name: "vcontroln", pads: [["U11", "2"], ["C45", "1"], ["TP9", "1"], ["U15", "2"], ["C54", "2"], ["U16", "2"], ["C55", "2"], ["U23", "5"], ["C64", "2"], ["U24", "5"], ["C65", "2"], ["U39", "4"], ["C109", "2"]]}, {name: "usb_chain_0.d_P", pads: [["J1", "A6"], ["J1", "B6"], ["U26", "14"], ["U27", "2"]]}, {name: "usb_chain_0.d_N", pads: [["J1", "A7"], ["J1", "B7"], ["U26", "13"], ["U27", "1"]]}, @@ -1636,7 +1636,7 @@ board.setNetlist([ {name: "reg_3v3.ic.boot", pads: [["U3", "6"], ["C10", "1"]]}, {name: "reg_3v3.ic.en", pads: [["U3", "5"], ["R9", "2"]]}, {name: "reg_v12.ic.sw", pads: [["U4", "1"], ["L3", "2"], ["D3", "2"]]}, - {name: "reg_v12.ic.fb", pads: [["U4", "3"], ["R10", "2"], ["R11", "1"], ["C16", "2"]]}, + {name: "reg_v12.ic.fb", pads: [["U4", "3"], ["R10", "2"], ["R11", "1"], ["C16", "1"]]}, {name: "conv.reset", pads: [["U6", "3"], ["U7", "3"], ["U29", "7"], ["U31", "6"], ["U31", "7"]]}, {name: "conv.buck_pwm", pads: [["U6", "2"], ["R73", "2"], ["C79", "1"]]}, {name: "conv.boost_pwm", pads: [["U7", "2"], ["R74", "2"], ["C80", "1"]]}, @@ -1655,7 +1655,7 @@ board.setNetlist([ {name: "ref_div.output", pads: [["R17", "2"], ["R18", "1"], ["U40", "3"]]}, {name: "ref_buf.output", pads: [["R19", "1"], ["U40", "1"], ["U40", "2"]]}, {name: "reg_vcontrol.ic.sw", pads: [["U10", "1"], ["L5", "2"], ["D7", "2"]]}, - {name: "reg_vcontrol.ic.fb", pads: [["U10", "3"], ["R20", "2"], ["R21", "1"], ["C43", "2"]]}, + {name: "reg_vcontrol.ic.fb", pads: [["U10", "3"], ["R20", "2"], ["R21", "1"], ["C43", "1"]]}, {name: "filt_vcontroln.pwr_out", pads: [["FB2", "2"], ["U11", "4"], ["U11", "5"]]}, {name: "reg_vcontroln.ic.capn", pads: [["U11", "3"], ["C44", "2"]]}, {name: "reg_vcontroln.ic.capp", pads: [["U11", "6"], ["C44", "1"]]}, diff --git a/examples/test_bldc_controller.py b/examples/test_bldc_controller.py index 9254daf97..c0a86aa1f 100644 --- a/examples/test_bldc_controller.py +++ b/examples/test_bldc_controller.py @@ -38,9 +38,9 @@ def __init__(self) -> None: [Power], ) self.gnd = self.Export(self.conn.pins.request("3").adapt_to(Ground()), [Common]) - self.out = self.Export( - self.conn.pins.request("2").adapt_to(AnalogSource.from_supply(self.gnd, self.pwr)), [Output] - ) + self.out = self.Export(AnalogSource.from_supply(self.gnd, self.pwr), [Output]) + + self.connect(self.out.net, self.conn.pins.request("2")) class I2cConnector(Connector, Block): diff --git a/examples/test_iot_iron.py b/examples/test_iot_iron.py index eedb4b864..67c6b1a1e 100644 --- a/examples/test_iot_iron.py +++ b/examples/test_iot_iron.py @@ -17,25 +17,24 @@ def __init__( ): super().__init__() self.conn = self.Block(PinHeader254(3)) + self.isense_res = self.Block(CurrentSenseResistor(resistance=isense_resistance, sense_in_reqd=False)) self.gnd = self.Port(Ground.empty(), [Common]) self.pwr = self.Export(self.conn.pins.request("2").adapt_to(VoltageSink(current_draw=current_draw))) - self.thermocouple = self.Export( - self.conn.pins.request("3").adapt_to( - AnalogSource( - voltage_out=self.gnd.link().voltage + (0, 14.3) * mVolt, - signal_out=self.gnd.link().voltage + (0, 14.3) * mVolt, # up to ~350 C - ) + self.thermocouple = self.Port( + AnalogSource( + voltage_out=self.gnd.link().voltage + (0, 14.3) * mVolt, + signal_out=self.gnd.link().voltage + (0, 14.3) * mVolt, # up to ~350 C ), optional=True, ) - self.isense_res = self.Block(CurrentSenseResistor(resistance=isense_resistance, sense_in_reqd=False)) self.isense = self.Export(self.isense_res.sense_out) self.connect( self.conn.pins.request("1").adapt_to(VoltageSink(current_draw=current_draw)), self.isense_res.pwr_out ) self.connect(self.gnd.as_voltage_source(), self.isense_res.pwr_in) + self.connect(self.thermocouple.net, self.conn.pins.request("3")) class IotIron(JlcBoardTop): diff --git a/examples/test_robotcrawler.py b/examples/test_robotcrawler.py index 93196dd12..0321ceaca 100644 --- a/examples/test_robotcrawler.py +++ b/examples/test_robotcrawler.py @@ -23,15 +23,14 @@ def __init__(self) -> None: ) self.gnd = self.Export(self.conn.pins.request("3").adapt_to(Ground()), [Common]) - self.fb = self.Export( - self.conn.pins.request("4").adapt_to( - AnalogSource( # no specs given - voltage_out=(0.9, 2.1) - * Volt, # from https://www.pololu.com/blog/814/new-products-special-servos-with-position-feedback - signal_out=(0.9, 2.1) * Volt, - ) + self.fb = self.Port( + AnalogSource( # no specs given + voltage_out=(0.9, 2.1) + * Volt, # from https://www.pololu.com/blog/814/new-products-special-servos-with-position-feedback + signal_out=(0.9, 2.1) * Volt, ) ) + self.connect(self.fb.net, self.conn.pins.request("4")) @abstract_block diff --git a/examples/test_usb_source_measure.py b/examples/test_usb_source_measure.py index a3e2062c1..20231bbf6 100644 --- a/examples/test_usb_source_measure.py +++ b/examples/test_usb_source_measure.py @@ -1032,7 +1032,7 @@ def refinements(self) -> Refinements: (["conv", "power_path", "out_cap", "cap", "require_basic_part"], False), (["control", "driver", "cap_in2", "cap", "voltage_rating_derating"], 0.9), (["control", "driver", "cap_in3", "cap", "voltage_rating_derating"], 0.9), - (["reg_vcontrol", "cf", "voltage_rating_derating"], 0.85), + (["reg_vcontrol", "cf", "cap", "voltage_rating_derating"], 0.85), (["reg_vcontrol", "power_path", "out_cap", "cap", "exact_capacitance"], False), (["reg_vcontrol", "power_path", "out_cap", "cap", "voltage_rating_derating"], 0.85), (