Skip to content

SMU v3.1 #397

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 75 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
75 commits
Select commit Hold shift + click to select a range
59d2812
wip new ranging cell
ducky64 Dec 30, 2024
f86e959
Update SourceMeasureRangingCell.kicad_sch
ducky64 Dec 30, 2024
830a677
prob wont compile but the new circuit
ducky64 Dec 30, 2024
ec4c524
Update EmitterFollower.kicad_sch
ducky64 Jan 1, 2025
f263e82
emitter follower builds
ducky64 Jan 1, 2025
33bb0e5
to erc almost clean
ducky64 Jan 2, 2025
06cf2b2
precharge skeleton
ducky64 Jan 4, 2025
0763190
wip precharge circuit
ducky64 Jan 4, 2025
30b85f5
merge
ducky64 Feb 3, 2025
5e171f9
fixes
ducky64 Feb 4, 2025
2679f60
Update test_usb_source_measure.py
ducky64 Feb 12, 2025
89c60a9
wip additional device symbols
ducky64 Feb 12, 2025
4c59e7c
test skeleton
ducky64 Feb 17, 2025
3997cdf
basic equals test
ducky64 Feb 17, 2025
64ef223
fix ratio corners
ducky64 Feb 17, 2025
947cb86
rebaseline netlist
ducky64 Feb 18, 2025
6d8108d
gated summing amp + fine voltage control
ducky64 Feb 18, 2025
d6e3e65
nano2 fuseholder
ducky64 Feb 18, 2025
ac9e848
ilim sense and high speed mclk
ducky64 Feb 19, 2025
fb62d76
ffffffuses
ducky64 Feb 19, 2025
3bcad3a
rebaseline netlists
ducky64 Feb 19, 2025
b3b72ae
INA219 not working bus conflict + some bugfixes
ducky64 Feb 19, 2025
2490e12
ina219 addr
ducky64 Feb 20, 2025
22ebb4b
Create JfetProtect.asc
ducky64 Feb 20, 2025
06c0371
divider + diff-rc importables
ducky64 Feb 22, 2025
9111c4e
Merge branch 'master' into smuv3.2
ducky64 Feb 22, 2025
d722922
new baseline netlist
ducky64 Feb 24, 2025
da1804e
ina826
ducky64 Feb 24, 2025
95ce681
ina826 w/ tolerancing
ducky64 Feb 24, 2025
ba70104
use stock divider symbol
ducky64 Feb 28, 2025
f1d2da0
updated control schematic w/o netlist diff
ducky64 Mar 1, 2025
21842c2
wip control stage
ducky64 Mar 3, 2025
db8ec6f
WIP smu control stage
ducky64 Mar 4, 2025
b95d939
cleaning
ducky64 Mar 4, 2025
31a72d9
chipping away at errors
ducky64 Mar 5, 2025
8c3c970
update netlist
ducky64 Mar 5, 2025
02d3f6e
Update UsbSourceMeasure.kicad_pro
ducky64 Mar 5, 2025
7a5976d
use ratio type
ducky64 Mar 5, 2025
19f9397
architecturally almost there!
ducky64 Mar 5, 2025
a0b7b18
proper negative rails
ducky64 Mar 5, 2025
43258ce
3 bugs left, 1 real
ducky64 Mar 5, 2025
29f7625
lol?
ducky64 Mar 5, 2025
a9c22ce
Update SourceMeasureControl.kicad_sch
ducky64 Mar 5, 2025
47bf22e
Update SourceMeasureControl.kicad_sch
ducky64 Mar 5, 2025
82ce5aa
netlisting
ducky64 Mar 6, 2025
93e7328
rebaseline schematic
ducky64 Mar 6, 2025
533a707
Update SourceMeasureControl.kicad_sch
ducky64 Mar 6, 2025
69cf43a
basically erc clean
ducky64 Mar 6, 2025
88477ff
add i2s speaker driver and repin
ducky64 Mar 6, 2025
7395bdd
latest
ducky64 Mar 7, 2025
00b66db
cleaning
ducky64 Mar 10, 2025
6b67558
cap spam
ducky64 Mar 10, 2025
ed90c44
model clamp pdis
ducky64 Mar 10, 2025
1b7ff22
add voltage comparator utility block
ducky64 Mar 14, 2025
96e34c7
low range cheaper SSR
ducky64 Mar 14, 2025
300f9b8
Update test_usb_source_measure.py
ducky64 Mar 15, 2025
137acd8
Update test_usb_source_measure.py
ducky64 Mar 15, 2025
50565f0
Merge branch 'master' into smuv3.2
ducky64 Mar 16, 2025
7b7a233
sr latch with set priority
ducky64 Mar 17, 2025
8a7af80
Update test_usb_source_measure.py
ducky64 Mar 17, 2025
bd59774
series resistor wip
ducky64 Mar 17, 2025
bca8bbe
cleaning
ducky64 Mar 17, 2025
58fe807
Improved int support
ducky64 Mar 17, 2025
025cb41
Merge branch 'master' into smuv3.2
ducky64 Mar 17, 2025
0405ce5
tolerance stackup on series resistors
ducky64 Mar 17, 2025
7246482
cleaning
ducky64 Mar 22, 2025
e83c164
Merge branch 'master' into smuv3.2
ducky64 Mar 23, 2025
e56a754
Update Logic_74Lvc.py
ducky64 Mar 23, 2025
630f8ee
fix voltage comp port in type
ducky64 Mar 23, 2025
651c1f9
Add RC snubber
ducky64 Mar 23, 2025
7c868d3
add RC and TVS, resolve all ERCs
ducky64 Mar 23, 2025
788c655
regenerate netlists
ducky64 Mar 23, 2025
23c58ce
layout beginnings
ducky64 Mar 23, 2025
39019a3
Update UsbSourceMeasure.kicad_pro
ducky64 Mar 23, 2025
be179d1
Merge branch 'master' into smuv3.2
ducky64 Apr 13, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions edg/BoardTop.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ def refinements(self) -> Refinements:
(Fpc050Bottom, HiroseFh12sh),
(UsbEsdDiode, Tpd2e009),
(CanEsdDiode, Pesd1can),
(Fuse, Nano2Fuseholder),
(TestPoint, TeRc),

(SwdCortexTargetConnector, SwdCortexTargetHeader),
Expand Down
27 changes: 27 additions & 0 deletions edg/abstract_parts/AbstractCapacitor.py
Original file line number Diff line number Diff line change
Expand Up @@ -336,6 +336,33 @@ def connected(self, gnd: Optional[Port[GroundLink]] = None, pwr: Optional[Port[V
return self


class AnalogCapacitor(DiscreteApplication, KiCadImportableBlock):
"""Capacitor attached to an analog line, that presents as an open model-wise.
"""
def symbol_pinning(self, symbol_name: str) -> Dict[str, BasePort]:
assert symbol_name in ('Device:C', 'Device:C_Small', 'Device:C_Polarized', 'Device:C_Polarized_Small')
return {'1': self.io, '2': self.gnd}

@init_in_parent
def __init__(self, capacitance: RangeLike, *, exact_capacitance: BoolLike = False) -> None:
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.assign(self.cap.voltage, self.io.link().voltage - self.gnd.link().voltage)

def connected(self, gnd: Optional[Port[GroundLink]] = None, io: Optional[Port[AnalogLink]] = None) -> \
'AnalogCapacitor':
"""Convenience function to connect both ports, returning this object so it can still be given a name."""
if gnd is not None:
cast(Block, builder.get_enclosing_block()).connect(gnd, self.gnd)
if io is not None:
cast(Block, builder.get_enclosing_block()).connect(io, self.io)
return self


class CombinedCapacitorElement(Capacitor): # to avoid an abstract part error
def contents(self):
super().contents()
Expand Down
65 changes: 65 additions & 0 deletions edg/abstract_parts/AbstractComparator.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
from typing import Mapping

from .ResistiveDivider import FeedbackVoltageDivider, VoltageDivider
from ..electronics_model import *


Expand All @@ -22,3 +23,67 @@ def __init__(self) -> None:
self.inn = self.Port(AnalogSink.empty())
self.inp = self.Port(AnalogSink.empty())
self.out = self.Port(DigitalSource.empty())


class VoltageComparator(GeneratorBlock):
"""A comparator subcircuit that compares an input voltage rail against some reference, either
internally generated from the power lines or an external analog signals.
Accounts for tolerance stackup on the reference input - so make sure the trip
tolerance is specified wide enough.
The output is logic high when the input exceeds the trip voltage by default,
this can be inverted with the invert parameter.
Optionally this can take a reference voltage input, otherwise this generates a 1:1
divider by default.

TODO: maybe a version that takes an input analog signal?
"""
@init_in_parent
def __init__(self, trip_voltage: RangeLike, *, invert: BoolLike = False,
input_impedance: RangeLike=(4.7, 47)*kOhm,
trip_ref: RangeLike=1.65*Volt(tol=0.10)):
super().__init__()
self.comp = self.Block(Comparator())
self.gnd = self.Export(self.comp.gnd, [Common])
self.pwr = self.Export(self.comp.pwr, [Power])
self.input = self.Port(AnalogSink.empty(), [Input])
self.output = self.Export(self.comp.out, [Output])
self.ref = self.Port(AnalogSink.empty(), optional=True)

self.trip_voltage = self.ArgParameter(trip_voltage)
self.invert = self.ArgParameter(invert)
self.trip_ref = self.ArgParameter(trip_ref) # only used if self.ref disconnected
self.input_impedance = self.ArgParameter(input_impedance)
self.generator_param(self.ref.is_connected(), self.invert)

self.actual_trip_voltage = self.Parameter(RangeExpr())

def generate(self):
super().generate()

if self.get(self.ref.is_connected()):
ref_pin: Port[AnalogLink] = self.ref
ref_voltage = self.ref.link().signal
else:
self.ref_div = self.Block(VoltageDivider(
output_voltage=self.trip_ref,
impedance=self.input_impedance,
))
self.connect(self.ref_div.input, self.pwr)
self.connect(self.ref_div.gnd, self.gnd)
ref_pin = self.ref_div.output
ref_voltage = self.ref_div.output.link().signal

self.comp_div = self.Block(FeedbackVoltageDivider(
impedance=self.input_impedance,
output_voltage=ref_voltage,
assumed_input_voltage=self.trip_voltage
))
self.assign(self.actual_trip_voltage, self.comp_div.actual_input_voltage)
self.connect(self.comp_div.input, self.input.as_voltage_source())
self.connect(self.comp_div.gnd, self.gnd)
if not self.get(self.invert): # positive connection
self.connect(self.comp.inp, self.comp_div.output)
self.connect(self.comp.inn, ref_pin)
else: # negative connection
self.connect(self.comp.inn, self.comp_div.output)
self.connect(self.comp.inp, ref_pin)
68 changes: 37 additions & 31 deletions edg/abstract_parts/AbstractFuse.py
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,41 @@ def contents(self):
"operating voltage not within rating")


class SeriesPowerFuse(Protection):
"""Series fuse for power applications"""
FUSE_TYPE = Fuse

@init_in_parent
def __init__(self, trip_current: RangeLike) -> None:
super().__init__()

self.pwr_out = self.Port(VoltageSource.empty(), [Output]) # forward declaration
self.pwr_in = self.Port(VoltageSink.empty(), [Power, Input]) # forward declaration

self.fuse = self.Block(self.FUSE_TYPE(
trip_current=trip_current,
hold_current=(self.pwr_out.link().current_drawn.upper(), float('inf')),
voltage=self.pwr_in.link().voltage
))
self.connect(self.pwr_in, self.fuse.a.adapt_to(VoltageSink(
voltage_limits=self.fuse.actual_voltage_rating, # TODO: eventually needs a ground ref
current_draw=self.pwr_out.link().current_drawn
)))
self.connect(self.pwr_out, self.fuse.b.adapt_to(VoltageSource(
voltage_out=self.pwr_in.link().voltage, # ignore voltage drop
current_limits=(0, self.fuse.actual_hold_current.lower())
)))

def connected(self, pwr_in: Optional[Port[VoltageLink]] = None, pwr_out: Optional[Port[VoltageLink]] = None) -> \
'SeriesPowerFuse':
"""Convenience function to connect both ports, returning this object so it can still be given a name."""
if pwr_in is not None:
cast(Block, builder.get_enclosing_block()).connect(pwr_in, self.pwr_in)
if pwr_out is not None:
cast(Block, builder.get_enclosing_block()).connect(pwr_out, self.pwr_out)
return self


@abstract_block
class PptcFuse(Fuse):
"""PPTC self-resetting fuse"""
Expand Down Expand Up @@ -97,34 +132,5 @@ def _row_generate(self, row: PartsTableRow) -> None:
self.assign(self.actual_voltage_rating, row[self.VOLTAGE_RATING])


class SeriesPowerPptcFuse(Protection):
"""Series fuse for power applications"""
@init_in_parent
def __init__(self, trip_current: RangeLike) -> None:
super().__init__()

self.pwr_out = self.Port(VoltageSource.empty(), [Output]) # forward declaration
self.pwr_in = self.Port(VoltageSink.empty(), [Power, Input]) # forward declaration

self.fuse = self.Block(PptcFuse(
trip_current=trip_current,
hold_current=(self.pwr_out.link().current_drawn.upper(), float('inf')),
voltage=self.pwr_in.link().voltage
))
self.connect(self.pwr_in, self.fuse.a.adapt_to(VoltageSink(
voltage_limits=self.fuse.actual_voltage_rating, # TODO: eventually needs a ground ref
current_draw=self.pwr_out.link().current_drawn
)))
self.connect(self.pwr_out, self.fuse.b.adapt_to(VoltageSource(
voltage_out=self.pwr_in.link().voltage, # ignore voltage drop
current_limits=(0, self.fuse.actual_hold_current.lower())
)))

def connected(self, pwr_in: Optional[Port[VoltageLink]] = None, pwr_out: Optional[Port[VoltageLink]] = None) -> \
'SeriesPowerPptcFuse':
"""Convenience function to connect both ports, returning this object so it can still be given a name."""
if pwr_in is not None:
cast(Block, builder.get_enclosing_block()).connect(pwr_in, self.pwr_in)
if pwr_out is not None:
cast(Block, builder.get_enclosing_block()).connect(pwr_out, self.pwr_out)
return self
class SeriesPowerPptcFuse(SeriesPowerFuse):
FUSE_TYPE = PptcFuse
55 changes: 54 additions & 1 deletion edg/abstract_parts/AbstractResistor.py
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,54 @@ def _row_generate(self, row: PartsTableRow) -> None:
self.assign(self.actual_voltage_rating, row[self.VOLTAGE_RATING])


class SeriesResistor(Resistor, GeneratorBlock):
"""Splits a resistor into equal resistors in series. Improves power and voltage ratings
by distributing the load across multiple devices.

Generally used as a refinement to break up a single (logical) resistor that is dissipating too much power
or has an excessive voltage across it. Accounts for tolerance stackup for power and voltage distribution
using specified (not actual) resistor tolerance - is a pessimistic calculation."""
@init_in_parent
def __init__(self, *args, count: IntLike = 2, **kwargs):
super().__init__(*args, **kwargs)
self.count = self.ArgParameter(count)
self.generator_param(self.count, self.resistance)

def generate(self):
super().generate()
count = self.get(self.count)
last_port = self.a
cumu_resistance: RangeLike = Range.exact(0)
cumu_power_rating: RangeLike = Range.exact(0)
cumu_voltage_rating: RangeLike = Range.exact(0)
self.res = ElementDict[Resistor]()

# calculate tolerance stackup effects on R for worst-case power and voltage
resistance_range = self.get(self.resistance)
resistance_tol = (resistance_range.upper - resistance_range.lower) / 2 / resistance_range.center()
resistance_tol = min(0.05, resistance_tol) # in practice there should be no >5% resistors
resistance_ratio_range = Range((1 - resistance_tol) / (count + resistance_tol * (count - 2)),
(1 + resistance_tol) / (count - resistance_tol * (count - 2)))

elt_resistance = self.resistance / self.count
elt_power = self.power * resistance_ratio_range
elt_voltage = self.voltage * resistance_ratio_range

for i in range(count):
self.res[i] = res = self.Block(Resistor(resistance=elt_resistance,
power=elt_power,
voltage=elt_voltage))
self.connect(last_port, res.a)
cumu_resistance = cumu_resistance + res.actual_resistance
cumu_power_rating = cumu_power_rating + res.actual_power_rating
cumu_voltage_rating = cumu_voltage_rating + res.actual_voltage_rating
last_port = res.b
self.connect(last_port, self.b)
self.assign(self.actual_resistance, cumu_resistance)
self.assign(self.actual_power_rating, cumu_power_rating)
self.assign(self.actual_voltage_rating, cumu_voltage_rating)


class PullupResistor(DiscreteApplication):
"""Pull-up resistor with an VoltageSink for automatic implicit connect to a Power line."""
@init_in_parent
Expand Down Expand Up @@ -205,8 +253,13 @@ def generate(self):
self.connect(self.io.append_elt(DigitalSource.empty(), requested), res.io)


class SeriesPowerResistor(DiscreteApplication):
class SeriesPowerResistor(DiscreteApplication, KiCadInstantiableBlock):
"""Series resistor for power applications"""
def symbol_pinning(self, symbol_name: str) -> Mapping[str, BasePort]:
assert symbol_name in ('Device:R', 'Device:R_Small')
return {'1': self.pwr_in, '2': self.pwr_out}


@init_in_parent
def __init__(self, resistance: RangeLike) -> None:
super().__init__()
Expand Down
6 changes: 3 additions & 3 deletions edg/abstract_parts/DigitalAmplifiers.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,16 +15,16 @@ class HighSideSwitch(PowerSwitch, KiCadSchematicBlock, GeneratorBlock):
TODO: clamp_voltage should be compared against the actual voltage so the clamp is automatically generated,
but generators don't support link terms (yet?)"""
@init_in_parent
def __init__(self, pull_resistance: RangeLike = 10000*Ohm(tol=0.05), max_rds: FloatLike = 1*Ohm,
def __init__(self, pull_resistance: RangeLike = 10*kOhm(tol=0.05), max_rds: FloatLike = 1*Ohm,
frequency: RangeLike = RangeExpr.ZERO, *,
clamp_voltage: RangeLike = RangeExpr.ZERO, clamp_resistance_ratio: FloatLike = 10) -> None:
super().__init__()

self.pwr = self.Port(VoltageSink.empty(), [Power]) # amplifier voltage
self.gnd = self.Port(Ground.empty(), [Common])

self.control = self.Port(DigitalSink.empty(), [Input])
self.output = self.Port(VoltageSource.empty(), [Output])
self.control = self.Port(DigitalSink.empty())
self.output = self.Port(VoltageSource.empty())

self.pull_resistance = self.ArgParameter(pull_resistance)
self.max_rds = self.ArgParameter(max_rds)
Expand Down
23 changes: 23 additions & 0 deletions edg/abstract_parts/OpampCircuits.py
Original file line number Diff line number Diff line change
Expand Up @@ -381,3 +381,26 @@ def contents(self) -> None:
})

self.assign(self.actual_factor, 1 / self.r.actual_resistance / self.c.actual_capacitance)


class SummingAmplifier(OpampApplication):
@classmethod
def calculate_ratio(cls, resistances: List[Range]) -> List[Range]:
"""Calculates each input's contribution to the output, for 1x gain.
Non-inverting summing amplifier topology.
Based on https://www.electronicshub.org/summing-amplifier/, which calculates the voltage of each input
and uses superposition to combine them."""
output = []
for i, resistance in enumerate(resistances):
# compute the two tolerance corners
others = resistances[:i] + resistances[i+1:]
other_lowest_parallel = 1 / sum([1 / other.lower for other in others])
other_highest_parallel = 1 / sum([1 / other.upper for other in others])
# ratio is lowest when this resistance is highest and other is lowest
ratio_lowest = other_lowest_parallel / (resistance.upper + other_lowest_parallel)
# ratio is highest when this resistance is lowest and other is highest
ratio_highest = other_highest_parallel / (resistance.lower + other_highest_parallel)

output.append(Range(ratio_lowest, ratio_highest))

return output
56 changes: 53 additions & 3 deletions edg/abstract_parts/PassiveFilters.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
from math import pi
from typing import Optional, cast
from typing import Optional, cast, Mapping

from ..electronics_model import *
from .AbstractResistor import Resistor
Expand Down Expand Up @@ -43,10 +43,9 @@ def __init__(self, impedance: RangeLike, time_constant: RangeLike):

self.rc = self.Block(LowPassRc(impedance=impedance, cutoff_freq=1/(2 * pi * self.time_constant),
voltage=self.pwr.link().voltage))

self.gnd = self.Export(self.rc.gnd.adapt_to(Ground()), [Common])
self.connect(self.pwr, self.rc.input.adapt_to(VoltageSink()))
self.io = self.Export(self.rc.output.adapt_to(DigitalSource.pullup_from_supply(self.pwr)), [Output])
self.gnd = self.Export(self.rc.gnd.adapt_to(Ground()), [Common])

def connected(self, *, gnd: Optional[Port[GroundLink]] = None, pwr: Optional[Port[VoltageLink]] = None,
io: Optional[Port[DigitalLink]] = None) -> 'PullupDelayRc':
Expand Down Expand Up @@ -158,3 +157,54 @@ def __init__(self, impedance: RangeLike, cutoff_freq: RangeLike):
)))

self.gnd = self.Export(self.rc.gnd.adapt_to(Ground()), [Common])


class LowPassAnalogDifferentialRc(AnalogFilter, KiCadImportableBlock, GeneratorBlock):
"""Analog-typed low-pass differential RC filter, with cutoff frequency specified at the -3dB (~70%) point.
Impedance is the single-ended resistor value."""
def symbol_pinning(self, symbol_name: str) -> Mapping[str, BasePort]:
assert symbol_name == 'edg_importable:DifferentialRC'
return {
'1': self.inp, '2': self.inn, '3': self.outp, '4': self.outn
}

@init_in_parent
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.impedance = self.ArgParameter(impedance)
self.cutoff_freq = self.ArgParameter(cutoff_freq)

self.generator_param(self.impedance, self.cutoff_freq)

def generate(self) -> None:
super().generate()

self.rp = self.Block(Resistor(resistance=self.impedance))
self.rn = self.Block(Resistor(resistance=self.impedance))
capacitance = Range.cancel_multiply(1 / (2 * pi * self.get(self.impedance)), 1 / self.get(self.cutoff_freq))
# capacitance is single-ended, halve it for differential
self.c = self.Block(Capacitor(capacitance=0.5*capacitance*Farad,
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()))
Loading