diff --git a/edg/abstract_parts/Diode.py b/edg/abstract_parts/Diode.py index e6c88cf10..53aea04ab 100644 --- a/edg/abstract_parts/Diode.py +++ b/edg/abstract_parts/Diode.py @@ -1,6 +1,5 @@ from typing import Any, Dict from typing_extensions import override -from deprecated import deprecated from ..electronics_interfaces import * from .PartsTable import PartsTableColumn, PartsTableRow @@ -144,113 +143,3 @@ def _row_generate(self, row: PartsTableRow) -> None: self.assign(self.actual_current_rating, row[self.CURRENT_RATING]) self.assign(self.actual_voltage_drop, row[self.FORWARD_VOLTAGE]) self.assign(self.actual_reverse_recovery_time, row[self.REVERSE_RECOVERY]) - - -@abstract_block -class ZenerDiode(KiCadImportableBlock, BaseDiode, DiscreteSemiconductor): - """Base class for untyped zeners - - TODO power? capacitance? leakage current? - """ - - @override - def symbol_pinning(self, symbol_name: str) -> Dict[str, BasePort]: - assert symbol_name in ("Device:D_Zener", "Device:D_Zener_Small") - return {"A": self.anode, "K": self.cathode} - - def __init__(self, zener_voltage: RangeLike) -> None: - super().__init__() - - self.zener_voltage = self.ArgParameter(zener_voltage) - - self.actual_zener_voltage = self.Parameter(RangeExpr()) - self.actual_power_rating = self.Parameter(RangeExpr()) - - @override - def contents(self) -> None: - super().contents() - - self.description = DescriptionString( - "zener voltage=", - DescriptionString.FormatUnits(self.actual_zener_voltage, "V"), - " of spec:", - DescriptionString.FormatUnits(self.zener_voltage, "V"), - "\n", - "power=", - DescriptionString.FormatUnits(self.actual_power_rating, "W"), - ) - - -@non_library -class TableZenerDiode(PartsTableSelector, ZenerDiode): - ZENER_VOLTAGE = PartsTableColumn(Range) - POWER_RATING = PartsTableColumn(Range) # tolerable power - - def __init__(self, *args: Any, **kwargs: Any) -> None: - super().__init__(*args, **kwargs) - self.generator_param(self.zener_voltage) - - @override - def _row_filter(self, row: PartsTableRow) -> bool: - return super()._row_filter(row) and row[self.ZENER_VOLTAGE].fuzzy_in(self.get(self.zener_voltage)) - - @override - def _row_generate(self, row: PartsTableRow) -> None: - super()._row_generate(row) - self.assign(self.actual_zener_voltage, row[self.ZENER_VOLTAGE]) - self.assign(self.actual_power_rating, row[self.POWER_RATING]) - - -class ProtectionZenerDiode(Protection): - """Zener diode reversed across a power rail to provide transient overvoltage protection (and become an incandescent - indicator on a reverse voltage)""" - - def __init__(self, voltage: RangeLike): - super().__init__() - - self.pwr = self.Port( - VoltageSink(voltage_limits=RangeExpr()), - [Power, InOut], - ) - self.gnd = self.Port(Ground(), [Common]) - - self.voltage = self.ArgParameter(voltage) - - @override - def contents(self) -> None: - super().contents() - self.diode = self.Block(ZenerDiode(zener_voltage=self.voltage)) - self.connect(self.pwr.net, self.diode.cathode) - self.connect(self.gnd.net, self.diode.anode) - self.assign(self.pwr.voltage_limits, (0, self.diode.actual_zener_voltage.lower())) - - -@deprecated("Use AnalogClampResistor, which should be cheaper and cause less signal distortion") -class AnalogClampZenerDiode(Protection, KiCadImportableBlock): - """Analog overvoltage protection diode to clamp the input voltage""" - - def __init__(self, voltage: RangeLike): - super().__init__() - - self.diode = self.Block(ZenerDiode(zener_voltage=voltage)) - - self.gnd = self.Port(Ground(), [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.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.gnd.net, self.diode.anode) - - @override - def symbol_pinning(self, symbol_name: str) -> Dict[str, Port]: - assert symbol_name == "edg_importable:AnalogClampZenerDiode" - return {"IN": self.signal_in, "OUT": self.signal_out, "GND": self.gnd} diff --git a/edg/abstract_parts/LedDriver.py b/edg/abstract_parts/LedDriver.py index 2bf1a9691..c18fefec8 100644 --- a/edg/abstract_parts/LedDriver.py +++ b/edg/abstract_parts/LedDriver.py @@ -4,6 +4,7 @@ from deprecated import deprecated +@deprecated("LED API is not stabilized") @abstract_block class LedDriver(PowerConditioner, Interface): """Abstract current-regulated high-power LED driver. @@ -30,6 +31,7 @@ def __init__(self, *args: Any, ripple_limit: FloatLike = float("inf"), **kwargs: self.ripple_limit = self.ArgParameter(ripple_limit) +@deprecated("LED API is not stabilized") class LedDriverPwm(BlockInterfaceMixin[LedDriver]): """LED driver mixin with PWM input for dimming control.""" diff --git a/edg/abstract_parts/LinearRegulator.py b/edg/abstract_parts/LinearRegulator.py new file mode 100644 index 000000000..94581515d --- /dev/null +++ b/edg/abstract_parts/LinearRegulator.py @@ -0,0 +1,63 @@ +from typing_extensions import override + +from ..electronics_interfaces import * +from .Resettable import Resettable +from .VoltageRegulator import VoltageRegulator + + +@abstract_block_default(lambda: IdealLinearRegulator) +class LinearRegulator(VoltageRegulator): + """Structural abstract base class for linear regulators, a voltage regulator that can produce some + output voltage lower than its input voltage (minus some dropout) by 'burning' the excess voltage as heat. + + Compared to switching converters like buck and boost converters, linear regulators usually have lower + complexity, lower parts count, and higher stability. However, depending on the application, they are + typically less efficient, and at higher loads may require thermal design considerations.""" + + +@abstract_block +class VoltageReference(LinearRegulator): + """Voltage reference, generally provides high accuracy but limited current""" + + +class IdealLinearRegulator(Resettable, LinearRegulator, IdealModel): + """Ideal linear regulator, draws the output current and produces spec output voltage limited by input voltage""" + + @override + def contents(self) -> None: + super().contents() + effective_output_voltage = self.output_voltage.intersect((0, self.pwr_in.link().voltage.upper())) + self.gnd.init_from(Ground()) + self.pwr_in.init_from(VoltageSink(current_draw=self.pwr_out.link().current_drawn)) + self.pwr_out.init_from(VoltageSource(voltage_out=effective_output_voltage)) + self.reset.init_from(DigitalSink()) + + +@non_library +class LinearRegulatorDevice(Block): + """Abstract base class that provides a default model with common functionality for a linear regulator chip. + Does not include supporting components like capacitors. + """ + + def __init__(self) -> None: + super().__init__() + + # these device model parameters must be provided by subtypes + self.actual_dropout = self.Parameter(RangeExpr()) + self.actual_quiescent_current = self.Parameter(RangeExpr()) + + self.gnd = self.Port(Ground(), [Common]) + self.pwr_in = self.Port( + VoltageSink(voltage_limits=RangeExpr(), current_draw=RangeExpr()), # parameters set by subtype + [Power, Input], + ) + self.pwr_out = self.Port( + VoltageSource(voltage_out=self.RangeExpr(), current_limits=RangeExpr()), # parameters set by subtype + [Output], + ) + self.assign(self.pwr_in.current_draw, self.pwr_out.link().current_drawn + self.actual_quiescent_current) + + self.require( + self.pwr_out.voltage_out.lower() + self.actual_dropout.upper() <= self.pwr_in.link().voltage.lower(), + "excessive dropout", + ) diff --git a/edg/abstract_parts/PowerConverters.py b/edg/abstract_parts/PowerConverters.py deleted file mode 100644 index 688f39b68..000000000 --- a/edg/abstract_parts/PowerConverters.py +++ /dev/null @@ -1,983 +0,0 @@ -from abc import abstractmethod -from typing import Any, Optional, NamedTuple, Callable -from typing_extensions import override - -from deprecated import deprecated - -from ..electronics_interfaces import * -from .Capacitor import DecouplingCapacitor, Capacitor -from .Inductor import Inductor, TableInductor -from .PartsTable import PartsTableRow, ExperimentalUserFnPartsTable -from .Resettable import Resettable - - -@abstract_block_default(lambda: IdealVoltageRegulator) -class VoltageRegulator(PowerConditioner): - """Structural abstract base class for DC-DC voltage regulators with shared ground (non-isolated). - This takes some input voltage and produces a stable voltage at output_voltage on its output. - - While this abstract class does not define any limitations on the output voltage, subclasses and concrete - implementations commonly have restrictions, for example linear regulators can only produce voltages lower - than the input voltage. - """ - - def __init__(self, output_voltage: RangeLike) -> None: - super().__init__() - - self.output_voltage = self.ArgParameter(output_voltage) - - self.pwr_in = self.Port(VoltageSink.empty(), [Power, Input]) - self.pwr_out = self.Port(VoltageSource.empty(), [Output]) - self.gnd = self.Port(Ground.empty(), [Common]) - - @override - def contents(self) -> None: - super().contents() - - self.description = DescriptionString( - "output voltage: ", - DescriptionString.FormatUnits(self.pwr_out.voltage_out, "V"), - " of spec: ", - DescriptionString.FormatUnits(self.output_voltage, "V"), - "\n", - "input voltage: ", - DescriptionString.FormatUnits(self.pwr_in.link().voltage, "V"), - ) - - self.require(self.pwr_out.voltage_out.within(self.output_voltage), "Output voltage must be within spec") - - -@non_library -class VoltageRegulatorEnableWrapper(Resettable, VoltageRegulator, GeneratorBlock): - """Implementation mixin for a voltage regulator wrapper block where the inner device has a reset/enable pin - (active-high enable / active-low shutdown) that is automatically tied high if not externally connected. - Mix this into a VoltageRegulator to automatically handle the reset pin.""" - - @abstractmethod - def _generator_inner_reset_pin(self) -> Port[DigitalLink]: - """Returns the inner device's reset pin, to be connected in the generator. - Only called within a generator.""" - - @override - def contents(self) -> None: - super().contents() - self.generator_param(self.reset.is_connected()) - - @override - def generate(self) -> None: - super().generate() - if self.get(self.reset.is_connected()): - self.connect(self.reset, self._generator_inner_reset_pin()) - else: # by default tie high to enable regulator - self.connect(self.pwr_in.as_digital_source(), self._generator_inner_reset_pin()) - - -@abstract_block_default(lambda: IdealLinearRegulator) -class LinearRegulator(VoltageRegulator): - """Structural abstract base class for linear regulators, a voltage regulator that can produce some - output voltage lower than its input voltage (minus some dropout) by 'burning' the excess voltage as heat. - - Compared to switching converters like buck and boost converters, linear regulators usually have lower - complexity, lower parts count, and higher stability. However, depending on the application, they are - typically less efficient, and at higher loads may require thermal design considerations.""" - - -@abstract_block -class VoltageReference(LinearRegulator): - """Voltage reference, generally provides high accuracy but limited current""" - - -class IdealLinearRegulator(Resettable, LinearRegulator, IdealModel): - """Ideal linear regulator, draws the output current and produces spec output voltage limited by input voltage""" - - @override - def contents(self) -> None: - super().contents() - effective_output_voltage = self.output_voltage.intersect((0, self.pwr_in.link().voltage.upper())) - self.gnd.init_from(Ground()) - self.pwr_in.init_from(VoltageSink(current_draw=self.pwr_out.link().current_drawn)) - self.pwr_out.init_from(VoltageSource(voltage_out=effective_output_voltage)) - self.reset.init_from(DigitalSink()) - - -@non_library -class LinearRegulatorDevice(Block): - """Abstract base class that provides a default model with common functionality for a linear regulator chip. - Does not include supporting components like capacitors. - """ - - def __init__(self) -> None: - super().__init__() - - # these device model parameters must be provided by subtypes - self.actual_dropout = self.Parameter(RangeExpr()) - self.actual_quiescent_current = self.Parameter(RangeExpr()) - - self.gnd = self.Port(Ground(), [Common]) - self.pwr_in = self.Port( - VoltageSink(voltage_limits=RangeExpr(), current_draw=RangeExpr()), # parameters set by subtype - [Power, Input], - ) - self.pwr_out = self.Port( - VoltageSource(voltage_out=self.RangeExpr(), current_limits=RangeExpr()), # parameters set by subtype - [Output], - ) - self.assign(self.pwr_in.current_draw, self.pwr_out.link().current_drawn + self.actual_quiescent_current) - - self.require( - self.pwr_out.voltage_out.lower() + self.actual_dropout.upper() <= self.pwr_in.link().voltage.lower(), - "excessive dropout", - ) - - -@abstract_block -class SwitchingVoltageRegulator(VoltageRegulator): - @staticmethod - @deprecated("ripple calculation moved into the power-path block itself") - def _calculate_ripple( - output_current: RangeLike, ripple_ratio: RangeLike, *, rated_current: Optional[FloatLike] = None - ) -> RangeExpr: - """ - Calculates the target inductor ripple current (with parameters - concrete values not necessary) - given the output current draw, and optionally a non-default ripple ratio and rated current. - - In general, ripple current largely trades off inductor maximum current and inductance. - - The default ripple ratio is an expansion of the heuristic 0.3-0.4 to account for tolerancing. - the rated current is used to set a reasonable ceiling for ripple current, when the actual current - is very low. Per the LMR33630 datasheet, the device's rated current should be used in these cases. - """ - output_current_range = RangeExpr._to_expr_type(output_current) - ripple_ratio_range = RangeExpr._to_expr_type(ripple_ratio) - upper_ripple_limit = ripple_ratio_range.upper() * output_current_range.upper() - if rated_current is not None: # if rated current is specified, extend the upper limit for small current draws - # this fallback limit is an arbitrary and low 0.2, not tied to specified ripple ratio since - # it leads to unintuitive behavior where as the low bound increases (range shrinks) the inductance - # spec actually becomes larger - upper_ripple_limit = upper_ripple_limit.max(0.2 * rated_current) - return RangeExpr._to_expr_type((ripple_ratio_range.lower() * output_current_range.upper(), upper_ripple_limit)) - - def __init__( - self, - *args: Any, - input_ripple_limit: FloatLike = 75 * mVolt, - output_ripple_limit: FloatLike = 25 * mVolt, - **kwargs: Any, - ) -> None: - """https://www.ti.com/lit/an/slta055/slta055.pdf: recommends 75mV for maximum peak-peak ripple voltage""" - super().__init__(*args, **kwargs) - - self.input_ripple_limit = self.ArgParameter(input_ripple_limit) - self.output_ripple_limit = self.ArgParameter(output_ripple_limit) - - self.actual_frequency = self.Parameter(RangeExpr()) - - -@abstract_block_default(lambda: IdealBuckConverter) -class BuckConverter(SwitchingVoltageRegulator): - """Step-down switching converter""" - - def __init__(self, *args: Any, **kwargs: Any) -> None: - super().__init__(*args, **kwargs) - self.require(self.pwr_out.voltage_out.upper() <= self.pwr_in.voltage_limits.upper()) - - -@abstract_block_default(lambda: IdealBuckConverter) -class DiscreteBuckConverter(BuckConverter): - """Category for discrete buck converter subcircuits (as opposed to integrated components)""" - - -class IdealBuckConverter(Resettable, DiscreteBuckConverter, IdealModel): - """Ideal buck converter producing the spec output voltage (buck-boost) limited by input voltage - and drawing input current from conversation of power""" - - @override - def contents(self) -> None: - super().contents() - effective_output_voltage = self.output_voltage.intersect((0, self.pwr_in.link().voltage.upper())) - self.gnd.init_from(Ground()) - self.pwr_in.init_from( - VoltageSink( - current_draw=effective_output_voltage / self.pwr_in.link().voltage * self.pwr_out.link().current_drawn - ) - ) - self.pwr_out.init_from(VoltageSource(voltage_out=effective_output_voltage)) - self.reset.init_from(DigitalSink()) - - -class BootstrapCapacitor(Block): - """A Capacitor wrapper for bootstrap capacitors, with a negative VoltageSink and a positive VoltageSource. - This is meant to be used only with bootstrap pins on power conversion chips, that source some voltage and sink the - boosted voltage. This is not meant to be general-purpose and will not function standalone. - The negative node is a pure VoltageSink, where the source must model the entire switching voltage range. - The positive node is a VoltageSource, where the source voltage models the boosted voltage, and the - reverse voltage models the charging voltage. - """ - - def __init__(self, capacitance: RangeLike): - super().__init__() - - self.neg = self.Port(VoltageSink()) - self.pos = self.Port( - VoltageSource( - voltage_out=RangeExpr(), reverse_voltage_limits=RangeExpr.ALL, reverse_current_draw=(0, 0) * Amp - ) - ) - boost_voltage = self.pos.link().reverse_voltage - self.neg.link().voltage.lower() - - self.cap = self.Block(Capacitor(capacitance=capacitance, voltage=boost_voltage)) - self.assign(self.pos.voltage_out, self.neg.link().voltage + boost_voltage) - self.connect(self.pos.net, self.cap.pos) - self.connect(self.neg.net, self.cap.neg) - - def connected( - self, neg: Optional[Port[VoltageLink]] = None, pos: Optional[Port[VoltageLink]] = None - ) -> "BootstrapCapacitor": - """Convenience function to connect both ports, returning this object so it can still be given a name.""" - if neg is not None: - builder.block().connect(neg, self.neg) - if pos is not None: - builder.block().connect(pos, self.pos) - return self - - -class BuckConverterPowerPath(InternalSubcircuit, GeneratorBlock): - """A helper block to generate the power path (inductors, capacitors) for a switching buck converter. - - Useful resources: - https://www.ti.com/lit/an/slva477b/slva477b.pdf - Component sizing in continuous mode - http://www.onmyphd.com/?p=voltage.regulators.buck.step.down.converter - Very detailed analysis including component sizing, operating modes, calculating losses - """ - - @staticmethod - def _d_inverse_d(d_range: Range) -> Range: - """Some power calculations require the maximum of D*(1-D), which has a maximum at D=0.5""" - # can't use range ops since they will double-count the tolerance of D, so calculate endpoints separately - range_endpoints = [d_range.lower * (1 - d_range.lower), d_range.upper * (1 - d_range.upper)] - raw_range = Range(min(range_endpoints), max(range_endpoints)) - if 0.5 in d_range: # the function has a maximum at 0.5 - return raw_range.hull(Range.exact(0.5 * (1 - 0.5))) - else: - return raw_range - - @staticmethod - def _ripple_current_from_sw_current(sw_current: float, ripple_ratio: Range) -> Range: - """Calculates the ripple current from a total switch current and ripple ratio.""" - return Range( # separate range parts to avoid double-counting tolerances - sw_current / (1 + ripple_ratio.lower) * ripple_ratio.lower, - sw_current / (1 + ripple_ratio.upper) * ripple_ratio.upper, - ) - - class Values(NamedTuple): - dutycycle: Range - inductance: Range - input_capacitance: Range - output_capacitance: Range - - inductor_avg_current: Range - ripple_scale: float # divide this by inductance to get the inductor ripple current - min_ripple: float # fallback minimum ripple current for component sizing for light-load, may be 0 - output_capacitance_scale: float # multiply inductor ripple by this to get required output capacitance - - inductor_peak_currents: Range # based on the worst case input spec, for unit testing - effective_dutycycle: Range # duty cycle adjusted for tracking behavior - - @classmethod - def _calculate_parameters( - cls, - input_voltage: Range, - output_voltage: Range, - frequency: Range, - output_current: Range, - sw_current_limits: Range, - ripple_ratio: Range, - input_voltage_ripple: float, - output_voltage_ripple: float, - efficiency: Range = Range(0.9, 1.0), - dutycycle_limit: Range = Range(0.1, 0.9), - limit_ripple_ratio: Range = Range(0.1, 0.5), - ) -> "BuckConverterPowerPath.Values": - """Calculates parameters for the buck converter power path. - - This uses the continuous conduction mode (CCM) equations to calculate component sizes. - DCM is not explicitly calculated since it requires additional parameters like minimum on-time. - The limit_ripple_ratio provides some broadly sane values for light-load / DCM operation. - This also ignores higher-order component behavior like capacitor ESR. - - The ripple_ratio is optional and may be set to Range.all(), allowing the inductor selector - to optimize the inductor by trading off inductance and max current. - - Values for component selections are bounded by: - - the ripple_ratio at output_current (if ripple_ratio < inf), and - - the limit_ripple_ratio at sw_current_limits (if sw_current_limits is not zero), as a fallback - for light-load conditions (where otherwise current goes to zero and inductance goes to the moon) - """ - dutycycle = output_voltage / input_voltage / efficiency - effective_dutycycle = dutycycle.bound_to(dutycycle_limit) # account for tracking behavior - - # calculate minimum inductance based on worst case values (operating range corners producing maximum inductance) - # worst-case input/output voltages and frequency is used to avoid double-counting tolerances as ranges - # note, for buck converter, L = (Vin - Vout) * D / (f * Iripple) = Vout (Vin - Vout) / (Iripple * f * Vin) - # this is at a maximum at Vin,max, and on that curve with a critical point at Vout = Vin,max / 2 - # note, the same formula calculates ripple-from-inductance and inductance-from-ripple - inductance_scale_candidates = [ - output_voltage.lower * (input_voltage.upper - output_voltage.lower) / input_voltage.upper, - output_voltage.upper * (input_voltage.upper - output_voltage.upper) / input_voltage.upper, - ] - if input_voltage.upper / 2 in output_voltage: - inductance_scale_candidates.append( - input_voltage.upper / 2 * (input_voltage.upper - input_voltage.upper / 2) / input_voltage.upper - ) - inductance_scale = max(inductance_scale_candidates) / frequency.lower - - inductance = Range.all() - min_ripple = 0.0 - if sw_current_limits.upper > 0: # fallback for light-load - ripple_current = cls._ripple_current_from_sw_current(sw_current_limits.upper, limit_ripple_ratio) - inductance = inductance.intersect(inductance_scale / ripple_current) - min_ripple = ripple_current.lower - if ripple_ratio.upper < float("inf"): - assert ripple_ratio.lower > 0, f"invalid non-inf ripple ratio {ripple_ratio}" - - inductance = inductance.intersect(inductance_scale / (output_current.upper * ripple_ratio)) - assert inductance.upper < float("inf"), "neither ripple_ratio nor fallback sw_current_limits given" - - input_capacitance = Range.from_lower( - output_current.upper - * cls._d_inverse_d(effective_dutycycle).upper - / (frequency.lower * input_voltage_ripple) - ) - output_capacitance_scale = 1 / (8 * frequency.lower * output_voltage_ripple) - - # these are static worst-case estimates for the range of specified ripple currents - # mainly used for unit testing - inductor_current_ripple = output_current * ripple_ratio.intersect(limit_ripple_ratio) - inductor_peak_currents = Range( - max(0, output_current.lower - inductor_current_ripple.upper / 2), - max(output_current.upper + inductor_current_ripple.upper / 2, inductor_current_ripple.upper), - ) - output_capacitance = Range.from_lower(output_capacitance_scale * inductor_current_ripple.upper) - - return cls.Values( - dutycycle=dutycycle, - inductance=inductance, - input_capacitance=input_capacitance, - output_capacitance=output_capacitance, - inductor_avg_current=output_current / efficiency, - ripple_scale=inductance_scale, - min_ripple=min_ripple, - output_capacitance_scale=output_capacitance_scale, - inductor_peak_currents=inductor_peak_currents, - effective_dutycycle=effective_dutycycle, - ) - - @staticmethod - @ExperimentalUserFnPartsTable.user_fn([float, float, float]) - def _buck_inductor_filter( - max_avg_current: float, ripple_scale: float, min_ripple: float - ) -> Callable[[PartsTableRow], bool]: - """Applies further filtering to inductors using the trade-off between inductance and peak-peak current. - max_avg_current is the maximum average current (not accounting for ripple) seen by the inductor - ripple_scale is the scaling factor from 1/L to ripple - This structure also works for boost converters, which would have its ripple_scale calculated differently.""" - - def filter_fn(row: PartsTableRow) -> bool: - ripple_current = max(ripple_scale / row[TableInductor.INDUCTANCE].lower, min_ripple) - max_current_pp = max_avg_current + ripple_current / 2 - return max_current_pp in row[TableInductor.CURRENT_RATING] - - return filter_fn - - @staticmethod - def _ilim_expr(inductor_ilim: RangeExpr, sw_ilim: RangeExpr, inductor_iripple: RangeExpr) -> RangeExpr: - """Returns the average current limit, as an expression, derived from the inductor and switch (instantaneous) - current limits.""" - iout_limit_inductor = inductor_ilim - (inductor_iripple.upper() / 2) - iout_limit_sw = (sw_ilim.upper() > 0).then_else(sw_ilim - (inductor_iripple.upper() / 2), Range.all()) - return iout_limit_inductor.intersect(iout_limit_sw).intersect(Range.from_lower(0)) - - def __init__( - self, - input_voltage: RangeLike, - output_voltage: RangeLike, - frequency: RangeLike, - output_current: RangeLike, - sw_current_limits: RangeLike, - *, - input_voltage_ripple: FloatLike, - output_voltage_ripple: FloatLike, - efficiency: RangeLike = (0.9, 1.0), # from TI reference - dutycycle_limit: RangeLike = (0.1, 0.9), - ripple_ratio: RangeLike = Range.all(), - ): - super().__init__() - - self.pwr_in = self.Port(VoltageSink.empty(), [Power]) # no modeling, input cap only - self.pwr_out = self.Port(VoltageSource.empty()) # models max output avg. current - # technically VoltageSink is the wrong model, but this is used to pass the current draw to the chip - # (and its input pin) without need the top-level to explicitly pass a parameter to the chip - self.switch = self.Port(VoltageSink.empty()) # models input / inductor avg. current draw - self.gnd = self.Port(Ground.empty(), [Common]) - - self.input_voltage = self.ArgParameter(input_voltage) - self.output_voltage = self.ArgParameter(output_voltage) - self.frequency = self.ArgParameter(frequency) - self.output_current = self.ArgParameter(output_current) - self.sw_current_limits = self.ArgParameter(sw_current_limits) - - self.efficiency = self.ArgParameter(efficiency) - self.input_voltage_ripple = self.ArgParameter(input_voltage_ripple) - self.output_voltage_ripple = self.ArgParameter(output_voltage_ripple) - self.dutycycle_limit = self.ArgParameter(dutycycle_limit) - self.ripple_ratio = self.ArgParameter(ripple_ratio) # only used to force a ripple ratio at the actual currents - - self.generator_param( - self.input_voltage, - self.output_voltage, - self.frequency, - self.output_current, - self.sw_current_limits, - self.input_voltage_ripple, - self.output_voltage_ripple, - self.efficiency, - self.dutycycle_limit, - self.ripple_ratio, - ) - - self.actual_dutycycle = self.Parameter(RangeExpr()) - self.actual_inductor_current_ripple = self.Parameter(RangeExpr()) - self.actual_inductor_current_peak = self.Parameter(RangeExpr()) - - @override - def contents(self) -> None: - super().contents() - - self.description = DescriptionString( - "duty cycle: ", - DescriptionString.FormatUnits(self.actual_dutycycle, ""), - " of limits: ", - DescriptionString.FormatUnits(self.dutycycle_limit, ""), - "\n", - "output current avg: ", - DescriptionString.FormatUnits(self.output_current, "A"), - ", ripple: ", - DescriptionString.FormatUnits(self.actual_inductor_current_ripple, "A"), - ) - - @override - def generate(self) -> None: - super().generate() - values = self._calculate_parameters( - self.get(self.input_voltage), - self.get(self.output_voltage), - self.get(self.frequency), - self.get(self.output_current), - self.get(self.sw_current_limits), - self.get(self.ripple_ratio), - self.get(self.input_voltage_ripple), - self.get(self.output_voltage_ripple), - efficiency=self.get(self.efficiency), - dutycycle_limit=self.get(self.dutycycle_limit), - ) - self.assign(self.actual_dutycycle, values.dutycycle) - self.require(values.dutycycle == values.effective_dutycycle, "dutycycle outside limit") - - self.inductor = self.Block( - Inductor( - inductance=values.inductance * Henry, - current=values.inductor_avg_current, # min-bound only, the real filter happens in the filter_fn - frequency=self.frequency, - experimental_filter_fn=ExperimentalUserFnPartsTable.serialize_fn( - self._buck_inductor_filter, - values.inductor_avg_current.upper, - values.ripple_scale, - values.min_ripple, - ), - ) - ) - self.assign(self.actual_inductor_current_ripple, values.ripple_scale / self.inductor.actual_inductance) - self.assign( - self.actual_inductor_current_peak, values.inductor_avg_current + self.actual_inductor_current_ripple / 2 - ) - - self.connect( - self.switch, - self.inductor.a.adapt_to(VoltageSink(current_draw=self.output_current * values.effective_dutycycle)), - ) - self.connect( - self.pwr_out, - self.inductor.b.adapt_to( - VoltageSource( - voltage_out=self.output_voltage, - current_limits=self._ilim_expr( - self.inductor.actual_current_rating, self.sw_current_limits, self.actual_inductor_current_ripple - ) - * self.efficiency, - ) - ), - ) - - self.in_cap = self.Block( - DecouplingCapacitor(capacitance=values.input_capacitance * Farad, exact_capacitance=True) - ).connected(self.gnd, self.pwr_in) - self.out_cap = self.Block( - DecouplingCapacitor( - capacitance=(Range.exact(float("inf")) * Farad).hull( - ( - values.output_capacitance_scale - * self.actual_inductor_current_ripple.upper().max(values.min_ripple) - ) - ), - exact_capacitance=True, - ) - ).connected(self.gnd, self.pwr_out) - - -@abstract_block_default(lambda: IdealBoostConverter) -class BoostConverter(SwitchingVoltageRegulator): - """Step-up switching converter""" - - def __init__(self, *args: Any, **kwargs: Any) -> None: - super().__init__(*args, **kwargs) - self.require(self.pwr_out.voltage_out.lower() >= self.pwr_in.voltage_limits.lower()) - - -@abstract_block_default(lambda: IdealBoostConverter) -class DiscreteBoostConverter(BoostConverter): - """Category for discrete boost converter subcircuits (as opposed to integrated components)""" - - -class IdealBoostConverter(Resettable, DiscreteBoostConverter, IdealModel): - """Ideal boost converter producing the spec output voltage (buck-boost) limited by input voltage - and drawing input current from conversation of power""" - - @override - def contents(self) -> None: - super().contents() - effective_output_voltage = self.output_voltage.intersect((self.pwr_in.link().voltage.lower(), float("inf"))) - self.gnd.init_from(Ground()) - self.pwr_in.init_from( - VoltageSink( - current_draw=effective_output_voltage / self.pwr_in.link().voltage * self.pwr_out.link().current_drawn - ) - ) - self.pwr_out.init_from(VoltageSource(voltage_out=effective_output_voltage)) - self.reset.init_from(DigitalSink()) - - -class BoostConverterPowerPath(InternalSubcircuit, GeneratorBlock): - """A helper block to generate the power path (inductors, capacitors) for a synchronous boost converter. - - Useful resources: - https://www.ti.com/lit/an/slva372c/slva372c.pdf - Component sizing in continuous mode - http://www.simonbramble.co.uk/dc_dc_converter_design/boost_converter/boost_converter_design.htm - Detailed analysis of converter with discrete FET and diode - """ - - class Values(NamedTuple): - dutycycle: Range - inductance: Range - input_capacitance: Range - output_capacitance: Range - - inductor_avg_current: Range - ripple_scale: float # divide this by inductance to get the inductor ripple current - min_ripple: float # fallback minimum ripple current for component sizing for light-load, may be 0 - - inductor_peak_currents: Range # based on the worst case input spec, for unit testing - effective_dutycycle: Range - - @classmethod - def _calculate_parameters( - cls, - input_voltage: Range, - output_voltage: Range, - frequency: Range, - output_current: Range, - sw_current_limits: Range, - ripple_ratio: Range, - input_voltage_ripple: float, - output_voltage_ripple: float, - efficiency: Range = Range(0.8, 1.0), - dutycycle_limit: Range = Range(0.1, 0.9), - limit_ripple_ratio: Range = Range(0.1, 0.5), - ) -> "BoostConverterPowerPath.Values": - """See BuckConverterPowerPath._calculate_parameters, this performs a similar function.""" - dutycycle = 1 - input_voltage / output_voltage * efficiency - effective_dutycycle = dutycycle.bound_to(dutycycle_limit) # account for tracking behavior - inductor_avg_current = output_current / (1 - effective_dutycycle) - - # calculate minimum inductance based on worst case values (operating range corners producing maximum inductance) - # worst-case input/output voltages and frequency is used to avoid double-counting tolerances as ranges - # note, for boost converter, L = Vin * D / (f * Iripple) = Vin (Vout - Vin) / (Iripple * f * Vout) - # this is at a maximum at Vout,max, and on that curve with a critical point at Vin = Vout,max / 2 - inductance_scale_candidates = [ - input_voltage.lower * (output_voltage.upper - input_voltage.lower) / output_voltage.upper, - input_voltage.upper * (output_voltage.upper - input_voltage.upper) / output_voltage.upper, - ] - if output_voltage.upper / 2 in input_voltage: - inductance_scale_candidates.append( - output_voltage.upper / 2 * (output_voltage.upper - output_voltage.upper / 2) / output_voltage.upper - ) - inductance_scale = max(inductance_scale_candidates) / frequency.lower - - inductance = Range.all() - min_ripple = 0.0 - if sw_current_limits.upper > 0: # fallback for light-load - ripple_current = BuckConverterPowerPath._ripple_current_from_sw_current( - sw_current_limits.upper, limit_ripple_ratio - ) - inductance = inductance.intersect(inductance_scale / ripple_current) - min_ripple = ripple_current.lower - if ripple_ratio.upper < float("inf"): - assert ripple_ratio.lower > 0, f"invalid non-inf ripple ratio {ripple_ratio}" - inductance = inductance.intersect(inductance_scale / (inductor_avg_current.upper * ripple_ratio)) - assert inductance.upper < float("inf"), "neither ripple_ratio nor fallback sw_current_limits given" - - inductor_current_ripple = inductor_avg_current * ripple_ratio.intersect(limit_ripple_ratio) - inductor_peak_currents = Range( - max(0, inductor_current_ripple.lower - inductor_current_ripple.upper / 2), - max(inductor_avg_current.upper + inductor_current_ripple.upper / 2, inductor_current_ripple.upper), - ) - - # Capacitor equation Q = CV => i = C dv/dt => for constant current, i * t = C dV => dV = i * t / C - # C = i * t / dV => C = i / (f * dV) - # Boost converter draws current from input throughout the entire cycle, and by conversation of power - # the average input current is Iin = Vout/Vin * Iout = 1/(1-D) * Iout - # Boost converter current should be much less spikey than buck converter current and probably - # less filtering than this is acceptable - input_capacitance = Range.from_lower( - (output_current.upper / (1 - effective_dutycycle.upper)) / (frequency.lower * input_voltage_ripple) - ) - output_capacitance = Range.from_lower( - output_current.upper * effective_dutycycle.upper / (frequency.lower * output_voltage_ripple) - ) - - return cls.Values( - dutycycle=dutycycle, - inductance=inductance, - input_capacitance=input_capacitance, - output_capacitance=output_capacitance, - inductor_avg_current=inductor_avg_current, - ripple_scale=inductance_scale, - min_ripple=min_ripple, - inductor_peak_currents=inductor_peak_currents, - effective_dutycycle=effective_dutycycle, - ) - - def __init__( - self, - input_voltage: RangeLike, - output_voltage: RangeLike, - frequency: RangeLike, - output_current: RangeLike, - sw_current_limits: RangeLike, - *, - input_voltage_ripple: FloatLike, - output_voltage_ripple: FloatLike, - efficiency: RangeLike = (0.8, 1.0), # from TI reference - dutycycle_limit: RangeLike = (0.1, 0.9), # arbitrary - ripple_ratio: RangeLike = Range.all(), - ): - super().__init__() - - self.pwr_in = self.Port(VoltageSink.empty(), [Power]) # models input / inductor avg. current draw - self.pwr_out = self.Port(VoltageSink.empty()) # no modeling, output cap only - self.switch = self.Port(VoltageSource.empty()) # models maximum output avg. current - self.gnd = self.Port(Ground.empty(), [Common]) - - self.input_voltage = self.ArgParameter(input_voltage) - self.output_voltage = self.ArgParameter(output_voltage) - self.frequency = self.ArgParameter(frequency) - self.output_current = self.ArgParameter(output_current) - self.sw_current_limits = self.ArgParameter(sw_current_limits) - - self.efficiency = self.ArgParameter(efficiency) - self.input_voltage_ripple = self.ArgParameter(input_voltage_ripple) - self.output_voltage_ripple = self.ArgParameter(output_voltage_ripple) - self.dutycycle_limit = self.ArgParameter(dutycycle_limit) - self.ripple_ratio = self.ArgParameter(ripple_ratio) # only used to force a ripple ratio at the actual currents - - self.generator_param( - self.input_voltage, - self.output_voltage, - self.frequency, - self.output_current, - self.sw_current_limits, - self.input_voltage_ripple, - self.output_voltage_ripple, - self.efficiency, - self.dutycycle_limit, - self.ripple_ratio, - ) - - self.actual_dutycycle = self.Parameter(RangeExpr()) - self.actual_inductor_current_ripple = self.Parameter(RangeExpr()) - self.actual_inductor_current_peak = self.Parameter(RangeExpr()) - - @override - def contents(self) -> None: - super().contents() - - self.description = DescriptionString( - "duty cycle: ", - DescriptionString.FormatUnits(self.actual_dutycycle, ""), - " of limits: ", - DescriptionString.FormatUnits(self.dutycycle_limit, ""), - "\n", - "output current avg: ", - DescriptionString.FormatUnits(self.output_current, "A"), - ", ripple: ", - DescriptionString.FormatUnits(self.actual_inductor_current_ripple, "A"), - ) - - @override - def generate(self) -> None: - super().generate() - values = self._calculate_parameters( - self.get(self.input_voltage), - self.get(self.output_voltage), - self.get(self.frequency), - self.get(self.output_current), - self.get(self.sw_current_limits), - self.get(self.ripple_ratio), - self.get(self.input_voltage_ripple), - self.get(self.output_voltage_ripple), - efficiency=self.get(self.efficiency), - dutycycle_limit=self.get(self.dutycycle_limit), - ) - self.assign(self.actual_dutycycle, values.dutycycle) - self.require(values.dutycycle == values.effective_dutycycle, "dutycycle outside limit") - - self.inductor = self.Block( - Inductor( - inductance=values.inductance * Henry, - current=values.inductor_avg_current, # min-bound only, the real filter happens in the filter_fn - frequency=self.frequency, - experimental_filter_fn=ExperimentalUserFnPartsTable.serialize_fn( - BuckConverterPowerPath._buck_inductor_filter, - values.inductor_avg_current.upper, - values.ripple_scale, - values.min_ripple, - ), - ) - ) - self.assign(self.actual_inductor_current_ripple, values.ripple_scale / self.inductor.actual_inductance) - self.assign( - self.actual_inductor_current_peak, values.inductor_avg_current + self.actual_inductor_current_ripple / 2 - ) - - self.connect(self.pwr_in, self.inductor.a.adapt_to(VoltageSink(current_draw=values.inductor_avg_current))) - self.connect( - self.switch, - self.inductor.b.adapt_to( - VoltageSource( - voltage_out=self.output_voltage, - current_limits=BuckConverterPowerPath._ilim_expr( - self.inductor.actual_current_rating, self.sw_current_limits, self.actual_inductor_current_ripple - ) - * (1 - values.effective_dutycycle.upper), - ) - ), - ) - - self.in_cap = self.Block( - DecouplingCapacitor(capacitance=values.input_capacitance * Farad, exact_capacitance=True) - ).connected(self.gnd, self.pwr_in) - - self.out_cap = self.Block( - DecouplingCapacitor(capacitance=values.output_capacitance * Farad, exact_capacitance=True) - ).connected(self.gnd, self.pwr_out) - - -@abstract_block_default(lambda: IdealVoltageRegulator) -class BuckBoostConverter(SwitchingVoltageRegulator): - """Step-up or switch-down switching converter""" - - -@abstract_block_default(lambda: IdealVoltageRegulator) -class DiscreteBuckBoostConverter(BuckBoostConverter): - """Category for discrete buck-boost converter subcircuits (as opposed to integrated components)""" - - -class IdealVoltageRegulator(Resettable, DiscreteBuckBoostConverter, IdealModel): - """Ideal buck-boost / general DC-DC converter producing the spec output voltage - and drawing input current from conversation of power""" - - @override - def contents(self) -> None: - super().contents() - self.gnd.init_from(Ground()) - self.pwr_in.init_from( - VoltageSink( - current_draw=self.output_voltage / self.pwr_in.link().voltage * self.pwr_out.link().current_drawn - ) - ) - self.pwr_out.init_from(VoltageSource(voltage_out=self.output_voltage)) - self.reset.init_from(DigitalSink()) - - -class BuckBoostConverterPowerPath(InternalSubcircuit, GeneratorBlock): - """A helper block to generate the power path (inductors, capacitors) for a 4-switch buck-boost converter. - - Main assumptions in component sizing - - Operating only in continuous mode, TODO: also consider boundary and discontinuous mode - - TODO: account for capacitor ESR? - - Useful resources: - https://www.ti.com/lit/an/slva535b/slva535b.pdf - Largely based on this document, the tl;dr of which is combine the buck and boost equations - """ - - def __init__( - self, - input_voltage: RangeLike, - output_voltage: RangeLike, - frequency: RangeLike, - output_current: RangeLike, - sw_current_limits: RangeLike, - *, - efficiency: RangeLike = (0.8, 1.0), # from TI reference - input_voltage_ripple: FloatLike = 75 * mVolt, - output_voltage_ripple: FloatLike = 25 * mVolt, # arbitrary - ripple_ratio: RangeLike = Range.all(), - ): - super().__init__() - - self.pwr_in = self.Port(VoltageSink.empty(), [Power]) # no modeling, input cap only - self.switch_in = self.Port(VoltageSink.empty()) # models input / inductor avg. current draw - self.switch_out = self.Port(VoltageSource.empty()) # models maximum output avg. current - self.pwr_out = self.Port(VoltageSink.empty()) # no modeling, output cap only - self.gnd = self.Port(Ground.empty(), [Common]) - - self.input_voltage = self.ArgParameter(input_voltage) - self.output_voltage = self.ArgParameter(output_voltage) - self.frequency = self.ArgParameter(frequency) - self.output_current = self.ArgParameter(output_current) - self.sw_current_limits = self.ArgParameter(sw_current_limits) - self.efficiency = self.ArgParameter(efficiency) - self.input_voltage_ripple = self.ArgParameter(input_voltage_ripple) - self.output_voltage_ripple = self.ArgParameter(output_voltage_ripple) - self.ripple_ratio = self.ArgParameter(ripple_ratio) # only used to force a ripple ratio at the actual currents - - # duty cycle limits not supported, since the crossover point has a dutycycle of 0 (boost) and 1 (buck) - self.generator_param( - self.input_voltage, - self.output_voltage, - self.frequency, - self.output_current, - self.sw_current_limits, - self.input_voltage_ripple, - self.output_voltage_ripple, - self.efficiency, - self.ripple_ratio, - ) - - self.actual_buck_dutycycle = self.Parameter(RangeExpr()) # possible actual duty cycle in buck mode - self.actual_boost_dutycycle = self.Parameter(RangeExpr()) # possible actual duty cycle in boost mode - self.actual_inductor_current_ripple = self.Parameter(RangeExpr()) - self.actual_inductor_current_peak = self.Parameter( - RangeExpr() - ) # inductor current accounting for ripple (upper is peak) - - @override - def contents(self) -> None: - super().contents() - - self.description = DescriptionString( - "duty cycle: ", - DescriptionString.FormatUnits(self.actual_buck_dutycycle, ""), - " (buck)", - ", ", - DescriptionString.FormatUnits(self.actual_boost_dutycycle, ""), - " (boost)\n", - "output current avg: ", - DescriptionString.FormatUnits(self.output_current, "A"), - ", ripple: ", - DescriptionString.FormatUnits(self.actual_inductor_current_ripple, "A"), - ) - - @override - def generate(self) -> None: - super().generate() - buck_values = BuckConverterPowerPath._calculate_parameters( - self.get(self.input_voltage), - self.get(self.output_voltage), - self.get(self.frequency), - self.get(self.output_current), - self.get(self.sw_current_limits), - self.get(self.ripple_ratio), - self.get(self.input_voltage_ripple), - self.get(self.output_voltage_ripple), - efficiency=self.get(self.efficiency), - dutycycle_limit=Range(0, 1), - ) - boost_values = BoostConverterPowerPath._calculate_parameters( - self.get(self.input_voltage), - self.get(self.output_voltage), - self.get(self.frequency), - self.get(self.output_current), - self.get(self.sw_current_limits), - self.get(self.ripple_ratio), - self.get(self.input_voltage_ripple), - self.get(self.output_voltage_ripple), - efficiency=self.get(self.efficiency), - dutycycle_limit=Range(0, 1), - ) - self.assign(self.actual_buck_dutycycle, buck_values.effective_dutycycle) - self.assign(self.actual_boost_dutycycle, boost_values.effective_dutycycle) - - combined_ripple_scale = max(buck_values.ripple_scale, boost_values.ripple_scale) - combined_inductor_avg_current = boost_values.inductor_avg_current.hull(boost_values.inductor_avg_current) - combined_min_ripple = max(buck_values.min_ripple, boost_values.min_ripple) - - self.inductor = self.Block( - Inductor( - inductance=buck_values.inductance.intersect(boost_values.inductance) * Henry, - current=buck_values.inductor_avg_current.hull(boost_values.inductor_avg_current), - frequency=self.frequency, - experimental_filter_fn=ExperimentalUserFnPartsTable.serialize_fn( - BuckConverterPowerPath._buck_inductor_filter, - combined_inductor_avg_current.upper, - combined_ripple_scale, - combined_min_ripple, - ), - ) - ) - self.connect(self.switch_in, self.inductor.a.adapt_to(VoltageSink(current_draw=combined_inductor_avg_current))) - self.connect( - self.switch_out, - self.inductor.b.adapt_to( - VoltageSource( - voltage_out=self.output_voltage, - current_limits=BuckConverterPowerPath._ilim_expr( - self.inductor.actual_current_rating, self.sw_current_limits, self.actual_inductor_current_ripple - ) - * (1 - boost_values.effective_dutycycle.upper), - ) - ), - ) - self.assign(self.actual_inductor_current_ripple, combined_ripple_scale / self.inductor.actual_inductance) - self.assign( - self.actual_inductor_current_peak, combined_inductor_avg_current + self.actual_inductor_current_ripple / 2 - ) - - self.in_cap = self.Block( - DecouplingCapacitor( - capacitance=buck_values.input_capacitance.intersect(boost_values.input_capacitance) * Farad, - exact_capacitance=True, - ) - ).connected(self.gnd, self.pwr_in) - self.out_cap = self.Block( - DecouplingCapacitor( - capacitance=(Range.exact(float("inf")) * Farad).hull( - (buck_values.output_capacitance_scale * self.actual_inductor_current_ripple.upper()).max( - boost_values.output_capacitance.lower - ) - ), - exact_capacitance=True, - ) - ).connected(self.gnd, self.pwr_out) diff --git a/edg/abstract_parts/Resistor.py b/edg/abstract_parts/Resistor.py index 01be6fdb7..596fc3cd1 100644 --- a/edg/abstract_parts/Resistor.py +++ b/edg/abstract_parts/Resistor.py @@ -408,7 +408,7 @@ def connected( class AnalogSeriesResistor(InternalSubcircuit, KiCadImportableBlock): """Analog passthrough series resistor. - Generally an utility component in subcircuits and not used at the top level.""" + Generally a utility component in subcircuits and not used at the top level.""" @override def symbol_pinning(self, symbol_name: str) -> Mapping[str, BasePort]: @@ -450,69 +450,9 @@ def connected( return self -class AnalogClampResistor(Protection, KiCadImportableBlock): - """Inline resistor that limits the current (to a parameterized amount) which works in concert - with ESD diodes in the downstream device to clamp the signal voltage to allowable levels. - - The protection voltage can be extended beyond the modeled range from the input signal, - and can also be specified to allow zero output voltage (for when the downstream device - is powered down) - - TODO: clamp_target should be inferred from the target voltage_limits, - but voltage_limits doesn't always get propagated""" - - def __init__( - self, - clamp_target: RangeLike = (0, 3) * Volt, - clamp_current: RangeLike = (0.25, 2.5) * mAmp, - protection_voltage: RangeLike = (0, 0) * Volt, - zero_out: BoolLike = False, - ): - super().__init__() - - 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() - - # TODO bidirectional clamping calcs? - self.res = self.Block( - Resistor( - resistance=1 - / self.clamp_current - * self.zero_out.then_else( - self.signal_in.link().voltage.hull(self.protection_voltage).upper(), - self.signal_in.link().voltage.hull(self.protection_voltage).upper() - self.clamp_target.upper(), - ) - ) - ) - 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]: - assert symbol_name == "Device:R" - return {"1": self.signal_in, "2": self.signal_out} - - class DigitalSeriesResistor(InternalSubcircuit, KiCadImportableBlock): """Digital passthrough series resistor, with source / sink (directioned) ports. - Generally an utility component in subcircuits and not used at the top level.""" + Generally a utility component in subcircuits and not used at the top level.""" @override def symbol_pinning(self, symbol_name: str) -> Mapping[str, BasePort]: @@ -626,78 +566,3 @@ def connected( if exterior is not None: builder.block().connect(exterior, self.exterior) return self - - -class DigitalClampResistor(Protection, KiCadImportableBlock): - """Inline resistor that limits the current (to a parameterized amount) which works in concert - with ESD diodes in the downstream device to clamp the signal voltage to allowable levels. - - The protection voltage can be extended beyond the modeled range from the input signal, - and can also be specified to allow zero output voltage (for when the downstream device - is powered down) - - TODO: clamp_target should be inferred from the target voltage_limits, - but voltage_limits doesn't always get propagated.""" - - def __init__( - self, - clamp_target: RangeLike = (0, 3) * Volt, - clamp_current: RangeLike = (1.0, 10) * mAmp, - protection_voltage: RangeLike = (0, 0) * Volt, - zero_out: BoolLike = False, - ): - super().__init__() - - 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(DigitalSink(current_draw=RangeExpr()), [Input]) - self.signal_out = self.Port( - DigitalSource( - voltage_out=self.signal_in.link().voltage.intersect(self.clamp_target), - output_thresholds=self.signal_in.link().output_thresholds, - ), - [Output], - ) - - @override - def contents(self) -> None: - super().contents() - - # TODO bidirectional clamping calcs? - self.assign(self.signal_in.current_draw, self.signal_out.link().current_drawn) - self.res = self.Block( - Resistor( - resistance=1 - / self.clamp_current - * self.zero_out.then_else( - self.signal_in.link().voltage.hull(self.protection_voltage).upper(), - self.signal_in.link().voltage.hull(self.protection_voltage).upper() - self.clamp_target.upper(), - ) - ) - ) - self.connect(self.res.a, self.signal_in.net) - self.connect(self.res.b, self.signal_out.net) - - @override - def symbol_pinning(self, symbol_name: str) -> Dict[str, Port]: - assert symbol_name == "Device:R" - return {"1": self.signal_in, "2": self.signal_out} - - -class UsbSeriesResistor(InternalSubcircuit, Block): - """Inline resistor on DM and DP lines, sometimes needed by microcontrollers.""" - - def __init__(self, resistance: RangeLike) -> None: - super().__init__() - self.resistance = self.ArgParameter(resistance) - self.interior = self.Port(UsbHostPort.empty(), [Input]) - self.exterior = self.Port(UsbDevicePort.empty(), [Output]) - - @override - def contents(self) -> None: - super().contents() - self.dp = self.Block(DigitalBidirSeriesResistor(self.resistance)).connected(self.interior.dp, self.exterior.dp) - self.dm = self.Block(DigitalBidirSeriesResistor(self.resistance)).connected(self.interior.dm, self.exterior.dm) diff --git a/edg/abstract_parts/SwitchingVoltageRegulator.py b/edg/abstract_parts/SwitchingVoltageRegulator.py new file mode 100644 index 000000000..31d52ed77 --- /dev/null +++ b/edg/abstract_parts/SwitchingVoltageRegulator.py @@ -0,0 +1,128 @@ +from typing import Any, Optional + +from deprecated import deprecated +from typing_extensions import override + +from ..electronics_interfaces import * +from .VoltageRegulator import VoltageRegulator, IdealVoltageRegulator +from .Resettable import Resettable + + +@abstract_block +class SwitchingVoltageRegulator(VoltageRegulator): + @staticmethod + @deprecated("ripple calculation moved into the power-path block itself") + def _calculate_ripple( + output_current: RangeLike, ripple_ratio: RangeLike, *, rated_current: Optional[FloatLike] = None + ) -> RangeExpr: + """ + Calculates the target inductor ripple current (with parameters - concrete values not necessary) + given the output current draw, and optionally a non-default ripple ratio and rated current. + + In general, ripple current largely trades off inductor maximum current and inductance. + + The default ripple ratio is an expansion of the heuristic 0.3-0.4 to account for tolerancing. + the rated current is used to set a reasonable ceiling for ripple current, when the actual current + is very low. Per the LMR33630 datasheet, the device's rated current should be used in these cases. + """ + output_current_range = RangeExpr._to_expr_type(output_current) + ripple_ratio_range = RangeExpr._to_expr_type(ripple_ratio) + upper_ripple_limit = ripple_ratio_range.upper() * output_current_range.upper() + if rated_current is not None: # if rated current is specified, extend the upper limit for small current draws + # this fallback limit is an arbitrary and low 0.2, not tied to specified ripple ratio since + # it leads to unintuitive behavior where as the low bound increases (range shrinks) the inductance + # spec actually becomes larger + upper_ripple_limit = upper_ripple_limit.max(0.2 * rated_current) + return RangeExpr._to_expr_type((ripple_ratio_range.lower() * output_current_range.upper(), upper_ripple_limit)) + + def __init__( + self, + *args: Any, + input_ripple_limit: FloatLike = 75 * mVolt, + output_ripple_limit: FloatLike = 25 * mVolt, + **kwargs: Any, + ) -> None: + """https://www.ti.com/lit/an/slta055/slta055.pdf: recommends 75mV for maximum peak-peak ripple voltage""" + super().__init__(*args, **kwargs) + + self.input_ripple_limit = self.ArgParameter(input_ripple_limit) + self.output_ripple_limit = self.ArgParameter(output_ripple_limit) + + self.actual_frequency = self.Parameter(RangeExpr()) + + +@abstract_block_default(lambda: IdealBuckConverter) +class BuckConverter(SwitchingVoltageRegulator): + """Step-down switching converter""" + + def __init__(self, *args: Any, **kwargs: Any) -> None: + super().__init__(*args, **kwargs) + self.require(self.pwr_out.voltage_out.upper() <= self.pwr_in.voltage_limits.upper()) + + +@abstract_block_default(lambda: IdealBuckConverter) +class DiscreteBuckConverter(BuckConverter): + """Category for discrete buck converter subcircuits (as opposed to integrated components)""" + + +class IdealBuckConverter(Resettable, DiscreteBuckConverter, IdealModel): + """Ideal buck converter producing the spec output voltage (buck-boost) limited by input voltage + and drawing input current from conversation of power""" + + @override + def contents(self) -> None: + super().contents() + effective_output_voltage = self.output_voltage.intersect((0, self.pwr_in.link().voltage.upper())) + self.gnd.init_from(Ground()) + self.pwr_in.init_from( + VoltageSink( + current_draw=effective_output_voltage / self.pwr_in.link().voltage * self.pwr_out.link().current_drawn + ) + ) + self.pwr_out.init_from(VoltageSource(voltage_out=effective_output_voltage)) + self.reset.init_from(DigitalSink()) + + +@abstract_block_default(lambda: IdealBoostConverter) +class BoostConverter(SwitchingVoltageRegulator): + """Step-up switching converter""" + + def __init__(self, *args: Any, **kwargs: Any) -> None: + super().__init__(*args, **kwargs) + self.require(self.pwr_out.voltage_out.lower() >= self.pwr_in.voltage_limits.lower()) + + +@abstract_block_default(lambda: IdealBoostConverter) +class DiscreteBoostConverter(BoostConverter): + """Category for discrete boost converter subcircuits (as opposed to integrated components)""" + + +class IdealBoostConverter(Resettable, DiscreteBoostConverter, IdealModel): + """Ideal boost converter producing the spec output voltage (buck-boost) limited by input voltage + and drawing input current from conversation of power""" + + @override + def contents(self) -> None: + super().contents() + effective_output_voltage = self.output_voltage.intersect((self.pwr_in.link().voltage.lower(), float("inf"))) + self.gnd.init_from(Ground()) + self.pwr_in.init_from( + VoltageSink( + current_draw=effective_output_voltage / self.pwr_in.link().voltage * self.pwr_out.link().current_drawn + ) + ) + self.pwr_out.init_from(VoltageSource(voltage_out=effective_output_voltage)) + self.reset.init_from(DigitalSink()) + + +@abstract_block_default(lambda: BuckBoostConverter) +class BuckBoostConverter(SwitchingVoltageRegulator): + """Step-up or switch-down switching converter""" + + +class IdealBuckBoostConverter(IdealVoltageRegulator, BuckBoostConverter): + pass + + +class DiscreteBuckBoostConverter(BuckBoostConverter): + """Category for discrete buck-boost converter subcircuits (as opposed to integrated components)""" diff --git a/edg/abstract_parts/VoltageRegulator.py b/edg/abstract_parts/VoltageRegulator.py new file mode 100644 index 000000000..aab739e5f --- /dev/null +++ b/edg/abstract_parts/VoltageRegulator.py @@ -0,0 +1,86 @@ +from abc import abstractmethod +from typing import Any, Optional + +from deprecated import deprecated +from typing_extensions import override + +from .Resettable import Resettable +from ..electronics_interfaces import * + + +@abstract_block_default(lambda: IdealVoltageRegulator) +class VoltageRegulator(PowerConditioner): + """Structural abstract base class for DC-DC voltage regulators with shared ground (non-isolated). + This takes some input voltage and produces a stable voltage at output_voltage on its output. + + While this abstract class does not define any limitations on the output voltage, subclasses and concrete + implementations commonly have restrictions, for example linear regulators can only produce voltages lower + than the input voltage. + """ + + def __init__(self, output_voltage: RangeLike) -> None: + super().__init__() + + self.output_voltage = self.ArgParameter(output_voltage) + + self.pwr_in = self.Port(VoltageSink.empty(), [Power, Input]) + self.pwr_out = self.Port(VoltageSource.empty(), [Output]) + self.gnd = self.Port(Ground.empty(), [Common]) + + @override + def contents(self) -> None: + super().contents() + + self.description = DescriptionString( + "output voltage: ", + DescriptionString.FormatUnits(self.pwr_out.voltage_out, "V"), + " of spec: ", + DescriptionString.FormatUnits(self.output_voltage, "V"), + "\n", + "input voltage: ", + DescriptionString.FormatUnits(self.pwr_in.link().voltage, "V"), + ) + + self.require(self.pwr_out.voltage_out.within(self.output_voltage), "Output voltage must be within spec") + + +@non_library +class VoltageRegulatorEnableWrapper(Resettable, VoltageRegulator, GeneratorBlock): + """Implementation mixin for a voltage regulator wrapper block where the inner device has a reset/enable pin + (active-high enable / active-low shutdown) that is automatically tied high if not externally connected. + Mix this into a VoltageRegulator to automatically handle the reset pin.""" + + @abstractmethod + def _generator_inner_reset_pin(self) -> Port[DigitalLink]: + """Returns the inner device's reset pin, to be connected in the generator. + Only called within a generator.""" + + @override + def contents(self) -> None: + super().contents() + self.generator_param(self.reset.is_connected()) + + @override + def generate(self) -> None: + super().generate() + if self.get(self.reset.is_connected()): + self.connect(self.reset, self._generator_inner_reset_pin()) + else: # by default tie high to enable regulator + self.connect(self.pwr_in.as_digital_source(), self._generator_inner_reset_pin()) + + +class IdealVoltageRegulator(Resettable, VoltageRegulator, IdealModel): + """Ideal buck-boost / general DC-DC converter producing the spec output voltage + and drawing input current from conversation of power""" + + @override + def contents(self) -> None: + super().contents() + self.gnd.init_from(Ground()) + self.pwr_in.init_from( + VoltageSink( + current_draw=self.output_voltage / self.pwr_in.link().voltage * self.pwr_out.link().current_drawn + ) + ) + self.pwr_out.init_from(VoltageSource(voltage_out=self.output_voltage)) + self.reset.init_from(DigitalSink()) diff --git a/edg/abstract_parts/ZenerDiode.py b/edg/abstract_parts/ZenerDiode.py new file mode 100644 index 000000000..581397304 --- /dev/null +++ b/edg/abstract_parts/ZenerDiode.py @@ -0,0 +1,118 @@ +from typing import Any, Dict +from typing_extensions import override +from deprecated import deprecated + +from ..electronics_interfaces import * +from .Diode import BaseDiode +from .PartsTable import PartsTableColumn, PartsTableRow +from .PartsTablePart import PartsTableSelector + + +@abstract_block +class ZenerDiode(KiCadImportableBlock, BaseDiode, DiscreteSemiconductor): + """Base class for untyped zeners + + TODO power? capacitance? leakage current? + """ + + @override + def symbol_pinning(self, symbol_name: str) -> Dict[str, BasePort]: + assert symbol_name in ("Device:D_Zener", "Device:D_Zener_Small") + return {"A": self.anode, "K": self.cathode} + + def __init__(self, zener_voltage: RangeLike) -> None: + super().__init__() + + self.zener_voltage = self.ArgParameter(zener_voltage) + + self.actual_zener_voltage = self.Parameter(RangeExpr()) + self.actual_power_rating = self.Parameter(RangeExpr()) + + @override + def contents(self) -> None: + super().contents() + + self.description = DescriptionString( + "zener voltage=", + DescriptionString.FormatUnits(self.actual_zener_voltage, "V"), + " of spec:", + DescriptionString.FormatUnits(self.zener_voltage, "V"), + "\n", + "power=", + DescriptionString.FormatUnits(self.actual_power_rating, "W"), + ) + + +@non_library +class TableZenerDiode(PartsTableSelector, ZenerDiode): + ZENER_VOLTAGE = PartsTableColumn(Range) + POWER_RATING = PartsTableColumn(Range) # tolerable power + + def __init__(self, *args: Any, **kwargs: Any) -> None: + super().__init__(*args, **kwargs) + self.generator_param(self.zener_voltage) + + @override + def _row_filter(self, row: PartsTableRow) -> bool: + return super()._row_filter(row) and row[self.ZENER_VOLTAGE].fuzzy_in(self.get(self.zener_voltage)) + + @override + def _row_generate(self, row: PartsTableRow) -> None: + super()._row_generate(row) + self.assign(self.actual_zener_voltage, row[self.ZENER_VOLTAGE]) + self.assign(self.actual_power_rating, row[self.POWER_RATING]) + + +class ProtectionZenerDiode(Protection): + """Zener diode reversed across a power rail to provide transient overvoltage protection (and become an incandescent + indicator on a reverse voltage)""" + + def __init__(self, voltage: RangeLike): + super().__init__() + + self.pwr = self.Port( + VoltageSink(voltage_limits=RangeExpr()), + [Power, InOut], + ) + self.gnd = self.Port(Ground(), [Common]) + + self.voltage = self.ArgParameter(voltage) + + @override + def contents(self) -> None: + super().contents() + self.diode = self.Block(ZenerDiode(zener_voltage=self.voltage)) + self.connect(self.pwr.net, self.diode.cathode) + self.connect(self.gnd.net, self.diode.anode) + self.assign(self.pwr.voltage_limits, (0, self.diode.actual_zener_voltage.lower())) + + +@deprecated("Use AnalogClampResistor, which should be cheaper and cause less signal distortion") +class AnalogClampZenerDiode(Protection, KiCadImportableBlock): + """Analog overvoltage protection diode to clamp the input voltage""" + + def __init__(self, voltage: RangeLike): + super().__init__() + + self.diode = self.Block(ZenerDiode(zener_voltage=voltage)) + + self.gnd = self.Port(Ground(), [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.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.gnd.net, self.diode.anode) + + @override + def symbol_pinning(self, symbol_name: str) -> Dict[str, Port]: + assert symbol_name == "edg_importable:AnalogClampZenerDiode" + return {"IN": self.signal_in, "OUT": self.signal_out, "GND": self.gnd} diff --git a/edg/abstract_parts/__init__.py b/edg/abstract_parts/__init__.py index b7992de37..da0c160ac 100644 --- a/edg/abstract_parts/__init__.py +++ b/edg/abstract_parts/__init__.py @@ -35,12 +35,9 @@ from .Resistor import ( SeriesPowerResistor, CurrentSenseResistor, - AnalogClampResistor, DigitalSeriesResistor, DigitalBidirSeriesResistor, - DigitalClampResistor, AnalogSetpointResistor, - UsbSeriesResistor, ) from .ResistorArray import ResistorArray, ResistorArrayStandardFootprint, TableResistorArray from .Capacitor import ( @@ -65,7 +62,7 @@ from .Resettable import Resettable from .Diode import BaseDiode, Diode, DiodeStandardFootprint, TableDiode -from .Diode import ZenerDiode, TableZenerDiode, ProtectionZenerDiode, AnalogClampZenerDiode +from .ZenerDiode import ZenerDiode, TableZenerDiode, ProtectionZenerDiode, AnalogClampZenerDiode from .TvsDiode import TvsDiode, ProtectionTvsDiode, DigitalTvsDiode from .Led import Led, LedStandardFootprint, TableLed, RgbLedCommonAnode, LedColor, LedColorLike from .Led import ( @@ -90,11 +87,15 @@ from .Comparator import Comparator from .Opamp import Opamp, OpampElement, MultipackOpamp, MultipackOpampGenerator from .SpiMemory import SpiMemory, SpiMemoryQspi -from .PowerConverters import VoltageRegulator, VoltageRegulatorEnableWrapper -from .PowerConverters import LinearRegulator, VoltageReference, LinearRegulatorDevice, SwitchingVoltageRegulator -from .PowerConverters import BootstrapCapacitor -from .PowerConverters import BuckConverter, DiscreteBuckConverter, BoostConverter, DiscreteBoostConverter -from .PowerConverters import BuckConverterPowerPath, BoostConverterPowerPath, BuckBoostConverterPowerPath +from .VoltageRegulator import VoltageRegulator, VoltageRegulatorEnableWrapper +from .LinearRegulator import LinearRegulator, VoltageReference, LinearRegulatorDevice +from .SwitchingVoltageRegulator import ( + SwitchingVoltageRegulator, + BuckConverter, + DiscreteBuckConverter, + BoostConverter, + DiscreteBoostConverter, +) from .LedDriver import LedDriver, LedDriverPwm, LedDriverSwitchingConverter from .Fuse import Fuse, SeriesPowerFuse, PptcFuse, FuseStandardFootprint, TableFuse, SeriesPowerPptcFuse from .Crystal import Crystal, TableCrystal, OscillatorReference, CeramicResonator diff --git a/edg/abstract_parts/test_ideal_circuit.py b/edg/abstract_parts/test_ideal_circuit.py index 353d1422a..ccffb1688 100644 --- a/edg/abstract_parts/test_ideal_circuit.py +++ b/edg/abstract_parts/test_ideal_circuit.py @@ -2,7 +2,8 @@ from ..electronics_interfaces import * from .IoController import IoController -from .PowerConverters import LinearRegulator, BoostConverter +from .LinearRegulator import LinearRegulator +from .SwitchingVoltageRegulator import BoostConverter class IdealCircuitTestTop(Block): diff --git a/edg/circuits/BoostConverterPowerPath.py b/edg/circuits/BoostConverterPowerPath.py new file mode 100644 index 000000000..f353b718d --- /dev/null +++ b/edg/circuits/BoostConverterPowerPath.py @@ -0,0 +1,232 @@ +from typing import NamedTuple +from typing_extensions import override + +from ..abstract_parts import * +from ..abstract_parts.PartsTable import ExperimentalUserFnPartsTable +from .BuckConverterPowerPath import BuckConverterPowerPath + + +class BoostConverterPowerPath(InternalSubcircuit, GeneratorBlock): + """A helper block to generate the power path (inductors, capacitors) for a synchronous boost converter. + + Useful resources: + https://www.ti.com/lit/an/slva372c/slva372c.pdf + Component sizing in continuous mode + http://www.simonbramble.co.uk/dc_dc_converter_design/boost_converter/boost_converter_design.htm + Detailed analysis of converter with discrete FET and diode + """ + + class Values(NamedTuple): + dutycycle: Range + inductance: Range + input_capacitance: Range + output_capacitance: Range + + inductor_avg_current: Range + ripple_scale: float # divide this by inductance to get the inductor ripple current + min_ripple: float # fallback minimum ripple current for component sizing for light-load, may be 0 + + inductor_peak_currents: Range # based on the worst case input spec, for unit testing + effective_dutycycle: Range + + @classmethod + def _calculate_parameters( + cls, + input_voltage: Range, + output_voltage: Range, + frequency: Range, + output_current: Range, + sw_current_limits: Range, + ripple_ratio: Range, + input_voltage_ripple: float, + output_voltage_ripple: float, + efficiency: Range = Range(0.8, 1.0), + dutycycle_limit: Range = Range(0.1, 0.9), + limit_ripple_ratio: Range = Range(0.1, 0.5), + ) -> "BoostConverterPowerPath.Values": + """See BuckConverterPowerPath._calculate_parameters, this performs a similar function.""" + dutycycle = 1 - input_voltage / output_voltage * efficiency + effective_dutycycle = dutycycle.bound_to(dutycycle_limit) # account for tracking behavior + inductor_avg_current = output_current / (1 - effective_dutycycle) + + # calculate minimum inductance based on worst case values (operating range corners producing maximum inductance) + # worst-case input/output voltages and frequency is used to avoid double-counting tolerances as ranges + # note, for boost converter, L = Vin * D / (f * Iripple) = Vin (Vout - Vin) / (Iripple * f * Vout) + # this is at a maximum at Vout,max, and on that curve with a critical point at Vin = Vout,max / 2 + inductance_scale_candidates = [ + input_voltage.lower * (output_voltage.upper - input_voltage.lower) / output_voltage.upper, + input_voltage.upper * (output_voltage.upper - input_voltage.upper) / output_voltage.upper, + ] + if output_voltage.upper / 2 in input_voltage: + inductance_scale_candidates.append( + output_voltage.upper / 2 * (output_voltage.upper - output_voltage.upper / 2) / output_voltage.upper + ) + inductance_scale = max(inductance_scale_candidates) / frequency.lower + + inductance = Range.all() + min_ripple = 0.0 + if sw_current_limits.upper > 0: # fallback for light-load + ripple_current = BuckConverterPowerPath._ripple_current_from_sw_current( + sw_current_limits.upper, limit_ripple_ratio + ) + inductance = inductance.intersect(inductance_scale / ripple_current) + min_ripple = ripple_current.lower + if ripple_ratio.upper < float("inf"): + assert ripple_ratio.lower > 0, f"invalid non-inf ripple ratio {ripple_ratio}" + inductance = inductance.intersect(inductance_scale / (inductor_avg_current.upper * ripple_ratio)) + assert inductance.upper < float("inf"), "neither ripple_ratio nor fallback sw_current_limits given" + + inductor_current_ripple = inductor_avg_current * ripple_ratio.intersect(limit_ripple_ratio) + inductor_peak_currents = Range( + max(0, inductor_current_ripple.lower - inductor_current_ripple.upper / 2), + max(inductor_avg_current.upper + inductor_current_ripple.upper / 2, inductor_current_ripple.upper), + ) + + # Capacitor equation Q = CV => i = C dv/dt => for constant current, i * t = C dV => dV = i * t / C + # C = i * t / dV => C = i / (f * dV) + # Boost converter draws current from input throughout the entire cycle, and by conversation of power + # the average input current is Iin = Vout/Vin * Iout = 1/(1-D) * Iout + # Boost converter current should be much less spikey than buck converter current and probably + # less filtering than this is acceptable + input_capacitance = Range.from_lower( + (output_current.upper / (1 - effective_dutycycle.upper)) / (frequency.lower * input_voltage_ripple) + ) + output_capacitance = Range.from_lower( + output_current.upper * effective_dutycycle.upper / (frequency.lower * output_voltage_ripple) + ) + + return cls.Values( + dutycycle=dutycycle, + inductance=inductance, + input_capacitance=input_capacitance, + output_capacitance=output_capacitance, + inductor_avg_current=inductor_avg_current, + ripple_scale=inductance_scale, + min_ripple=min_ripple, + inductor_peak_currents=inductor_peak_currents, + effective_dutycycle=effective_dutycycle, + ) + + def __init__( + self, + input_voltage: RangeLike, + output_voltage: RangeLike, + frequency: RangeLike, + output_current: RangeLike, + sw_current_limits: RangeLike, + *, + input_voltage_ripple: FloatLike, + output_voltage_ripple: FloatLike, + efficiency: RangeLike = (0.8, 1.0), # from TI reference + dutycycle_limit: RangeLike = (0.1, 0.9), # arbitrary + ripple_ratio: RangeLike = Range.all(), + ): + super().__init__() + + self.pwr_in = self.Port(VoltageSink.empty(), [Power]) # models input / inductor avg. current draw + self.pwr_out = self.Port(VoltageSink.empty()) # no modeling, output cap only + self.switch = self.Port(VoltageSource.empty()) # models maximum output avg. current + self.gnd = self.Port(Ground.empty(), [Common]) + + self.input_voltage = self.ArgParameter(input_voltage) + self.output_voltage = self.ArgParameter(output_voltage) + self.frequency = self.ArgParameter(frequency) + self.output_current = self.ArgParameter(output_current) + self.sw_current_limits = self.ArgParameter(sw_current_limits) + + self.efficiency = self.ArgParameter(efficiency) + self.input_voltage_ripple = self.ArgParameter(input_voltage_ripple) + self.output_voltage_ripple = self.ArgParameter(output_voltage_ripple) + self.dutycycle_limit = self.ArgParameter(dutycycle_limit) + self.ripple_ratio = self.ArgParameter(ripple_ratio) # only used to force a ripple ratio at the actual currents + + self.generator_param( + self.input_voltage, + self.output_voltage, + self.frequency, + self.output_current, + self.sw_current_limits, + self.input_voltage_ripple, + self.output_voltage_ripple, + self.efficiency, + self.dutycycle_limit, + self.ripple_ratio, + ) + + self.actual_dutycycle = self.Parameter(RangeExpr()) + self.actual_inductor_current_ripple = self.Parameter(RangeExpr()) + self.actual_inductor_current_peak = self.Parameter(RangeExpr()) + + @override + def contents(self) -> None: + super().contents() + + self.description = DescriptionString( + "duty cycle: ", + DescriptionString.FormatUnits(self.actual_dutycycle, ""), + " of limits: ", + DescriptionString.FormatUnits(self.dutycycle_limit, ""), + "\n", + "output current avg: ", + DescriptionString.FormatUnits(self.output_current, "A"), + ", ripple: ", + DescriptionString.FormatUnits(self.actual_inductor_current_ripple, "A"), + ) + + @override + def generate(self) -> None: + super().generate() + values = self._calculate_parameters( + self.get(self.input_voltage), + self.get(self.output_voltage), + self.get(self.frequency), + self.get(self.output_current), + self.get(self.sw_current_limits), + self.get(self.ripple_ratio), + self.get(self.input_voltage_ripple), + self.get(self.output_voltage_ripple), + efficiency=self.get(self.efficiency), + dutycycle_limit=self.get(self.dutycycle_limit), + ) + self.assign(self.actual_dutycycle, values.dutycycle) + self.require(values.dutycycle == values.effective_dutycycle, "dutycycle outside limit") + + self.inductor = self.Block( + Inductor( + inductance=values.inductance * Henry, + current=values.inductor_avg_current, # min-bound only, the real filter happens in the filter_fn + frequency=self.frequency, + experimental_filter_fn=ExperimentalUserFnPartsTable.serialize_fn( + BuckConverterPowerPath._buck_inductor_filter, + values.inductor_avg_current.upper, + values.ripple_scale, + values.min_ripple, + ), + ) + ) + self.assign(self.actual_inductor_current_ripple, values.ripple_scale / self.inductor.actual_inductance) + self.assign( + self.actual_inductor_current_peak, values.inductor_avg_current + self.actual_inductor_current_ripple / 2 + ) + + self.connect(self.pwr_in, self.inductor.a.adapt_to(VoltageSink(current_draw=values.inductor_avg_current))) + self.connect( + self.switch, + self.inductor.b.adapt_to( + VoltageSource( + voltage_out=self.output_voltage, + current_limits=BuckConverterPowerPath._ilim_expr( + self.inductor.actual_current_rating, self.sw_current_limits, self.actual_inductor_current_ripple + ) + * (1 - values.effective_dutycycle.upper), + ) + ), + ) + + self.in_cap = self.Block( + DecouplingCapacitor(capacitance=values.input_capacitance * Farad, exact_capacitance=True) + ).connected(self.gnd, self.pwr_in) + + self.out_cap = self.Block( + DecouplingCapacitor(capacitance=values.output_capacitance * Farad, exact_capacitance=True) + ).connected(self.gnd, self.pwr_out) diff --git a/edg/circuits/BootstrapCapacitor.py b/edg/circuits/BootstrapCapacitor.py new file mode 100644 index 000000000..c2f2a00b0 --- /dev/null +++ b/edg/circuits/BootstrapCapacitor.py @@ -0,0 +1,38 @@ +from typing import Optional +from ..abstract_parts import * + + +class BootstrapCapacitor(Block): + """A Capacitor wrapper for bootstrap capacitors, with a negative VoltageSink and a positive VoltageSource. + This is meant to be used only with bootstrap pins on power conversion chips, that source some voltage and sink the + boosted voltage. This is not meant to be general-purpose and will not function standalone. + The negative node is a pure VoltageSink, where the source must model the entire switching voltage range. + The positive node is a VoltageSource, where the source voltage models the boosted voltage, and the + reverse voltage models the charging voltage. + """ + + def __init__(self, capacitance: RangeLike): + super().__init__() + + self.neg = self.Port(VoltageSink()) + self.pos = self.Port( + VoltageSource( + voltage_out=RangeExpr(), reverse_voltage_limits=RangeExpr.ALL, reverse_current_draw=(0, 0) * Amp + ) + ) + boost_voltage = self.pos.link().reverse_voltage - self.neg.link().voltage.lower() + + self.cap = self.Block(Capacitor(capacitance=capacitance, voltage=boost_voltage)) + self.assign(self.pos.voltage_out, self.neg.link().voltage + boost_voltage) + self.connect(self.pos.net, self.cap.pos) + self.connect(self.neg.net, self.cap.neg) + + def connected( + self, neg: Optional[Port[VoltageLink]] = None, pos: Optional[Port[VoltageLink]] = None + ) -> "BootstrapCapacitor": + """Convenience function to connect both ports, returning this object so it can still be given a name.""" + if neg is not None: + builder.block().connect(neg, self.neg) + if pos is not None: + builder.block().connect(pos, self.pos) + return self diff --git a/edg/circuits/BuckBoostConverterPowerPath.py b/edg/circuits/BuckBoostConverterPowerPath.py new file mode 100644 index 000000000..71a7d64aa --- /dev/null +++ b/edg/circuits/BuckBoostConverterPowerPath.py @@ -0,0 +1,169 @@ +from typing_extensions import override + +from ..abstract_parts import * +from ..abstract_parts.PartsTable import ExperimentalUserFnPartsTable +from .BuckConverterPowerPath import BuckConverterPowerPath +from .BoostConverterPowerPath import BoostConverterPowerPath + + +class BuckBoostConverterPowerPath(InternalSubcircuit, GeneratorBlock): + """A helper block to generate the power path (inductors, capacitors) for a 4-switch buck-boost converter. + + Main assumptions in component sizing + - Operating only in continuous mode, TODO: also consider boundary and discontinuous mode + - TODO: account for capacitor ESR? + + Useful resources: + https://www.ti.com/lit/an/slva535b/slva535b.pdf + Largely based on this document, the tl;dr of which is combine the buck and boost equations + """ + + def __init__( + self, + input_voltage: RangeLike, + output_voltage: RangeLike, + frequency: RangeLike, + output_current: RangeLike, + sw_current_limits: RangeLike, + *, + efficiency: RangeLike = (0.8, 1.0), # from TI reference + input_voltage_ripple: FloatLike = 75 * mVolt, + output_voltage_ripple: FloatLike = 25 * mVolt, # arbitrary + ripple_ratio: RangeLike = Range.all(), + ): + super().__init__() + + self.pwr_in = self.Port(VoltageSink.empty(), [Power]) # no modeling, input cap only + self.switch_in = self.Port(VoltageSink.empty()) # models input / inductor avg. current draw + self.switch_out = self.Port(VoltageSource.empty()) # models maximum output avg. current + self.pwr_out = self.Port(VoltageSink.empty()) # no modeling, output cap only + self.gnd = self.Port(Ground.empty(), [Common]) + + self.input_voltage = self.ArgParameter(input_voltage) + self.output_voltage = self.ArgParameter(output_voltage) + self.frequency = self.ArgParameter(frequency) + self.output_current = self.ArgParameter(output_current) + self.sw_current_limits = self.ArgParameter(sw_current_limits) + self.efficiency = self.ArgParameter(efficiency) + self.input_voltage_ripple = self.ArgParameter(input_voltage_ripple) + self.output_voltage_ripple = self.ArgParameter(output_voltage_ripple) + self.ripple_ratio = self.ArgParameter(ripple_ratio) # only used to force a ripple ratio at the actual currents + + # duty cycle limits not supported, since the crossover point has a dutycycle of 0 (boost) and 1 (buck) + self.generator_param( + self.input_voltage, + self.output_voltage, + self.frequency, + self.output_current, + self.sw_current_limits, + self.input_voltage_ripple, + self.output_voltage_ripple, + self.efficiency, + self.ripple_ratio, + ) + + self.actual_buck_dutycycle = self.Parameter(RangeExpr()) # possible actual duty cycle in buck mode + self.actual_boost_dutycycle = self.Parameter(RangeExpr()) # possible actual duty cycle in boost mode + self.actual_inductor_current_ripple = self.Parameter(RangeExpr()) + self.actual_inductor_current_peak = self.Parameter( + RangeExpr() + ) # inductor current accounting for ripple (upper is peak) + + @override + def contents(self) -> None: + super().contents() + + self.description = DescriptionString( + "duty cycle: ", + DescriptionString.FormatUnits(self.actual_buck_dutycycle, ""), + " (buck)", + ", ", + DescriptionString.FormatUnits(self.actual_boost_dutycycle, ""), + " (boost)\n", + "output current avg: ", + DescriptionString.FormatUnits(self.output_current, "A"), + ", ripple: ", + DescriptionString.FormatUnits(self.actual_inductor_current_ripple, "A"), + ) + + @override + def generate(self) -> None: + super().generate() + buck_values = BuckConverterPowerPath._calculate_parameters( + self.get(self.input_voltage), + self.get(self.output_voltage), + self.get(self.frequency), + self.get(self.output_current), + self.get(self.sw_current_limits), + self.get(self.ripple_ratio), + self.get(self.input_voltage_ripple), + self.get(self.output_voltage_ripple), + efficiency=self.get(self.efficiency), + dutycycle_limit=Range(0, 1), + ) + boost_values = BoostConverterPowerPath._calculate_parameters( + self.get(self.input_voltage), + self.get(self.output_voltage), + self.get(self.frequency), + self.get(self.output_current), + self.get(self.sw_current_limits), + self.get(self.ripple_ratio), + self.get(self.input_voltage_ripple), + self.get(self.output_voltage_ripple), + efficiency=self.get(self.efficiency), + dutycycle_limit=Range(0, 1), + ) + self.assign(self.actual_buck_dutycycle, buck_values.effective_dutycycle) + self.assign(self.actual_boost_dutycycle, boost_values.effective_dutycycle) + + combined_ripple_scale = max(buck_values.ripple_scale, boost_values.ripple_scale) + combined_inductor_avg_current = buck_values.inductor_avg_current.hull(boost_values.inductor_avg_current) + combined_min_ripple = max(buck_values.min_ripple, boost_values.min_ripple) + + self.inductor = self.Block( + Inductor( + inductance=buck_values.inductance.intersect(boost_values.inductance) * Henry, + current=buck_values.inductor_avg_current.hull(boost_values.inductor_avg_current), + frequency=self.frequency, + experimental_filter_fn=ExperimentalUserFnPartsTable.serialize_fn( + BuckConverterPowerPath._buck_inductor_filter, + combined_inductor_avg_current.upper, + combined_ripple_scale, + combined_min_ripple, + ), + ) + ) + self.connect(self.switch_in, self.inductor.a.adapt_to(VoltageSink(current_draw=combined_inductor_avg_current))) + self.connect( + self.switch_out, + self.inductor.b.adapt_to( + VoltageSource( + voltage_out=self.output_voltage, + current_limits=BuckConverterPowerPath._ilim_expr( + self.inductor.actual_current_rating, self.sw_current_limits, self.actual_inductor_current_ripple + ) + * (1 - boost_values.effective_dutycycle.upper), + ) + ), + ) + self.assign(self.actual_inductor_current_ripple, combined_ripple_scale / self.inductor.actual_inductance) + self.assign( + self.actual_inductor_current_peak, combined_inductor_avg_current + self.actual_inductor_current_ripple / 2 + ) + + self.in_cap = self.Block( + DecouplingCapacitor( + capacitance=buck_values.input_capacitance.intersect(boost_values.input_capacitance) * Farad, + exact_capacitance=True, + ) + ).connected(self.gnd, self.pwr_in) + self.out_cap = self.Block( + DecouplingCapacitor( + capacitance=(Range.exact(float("inf")) * Farad).hull( + (buck_values.output_capacitance_scale * self.actual_inductor_current_ripple.upper()).max( + boost_values.output_capacitance.lower + ) + ), + exact_capacitance=True, + ) + ).connected(self.gnd, self.pwr_out) diff --git a/edg/circuits/BuckConverterPowerPath.py b/edg/circuits/BuckConverterPowerPath.py new file mode 100644 index 000000000..112f45539 --- /dev/null +++ b/edg/circuits/BuckConverterPowerPath.py @@ -0,0 +1,299 @@ +from typing import NamedTuple, Callable +from typing_extensions import override + +from ..abstract_parts import * +from ..abstract_parts.PartsTable import PartsTableRow, ExperimentalUserFnPartsTable + + +class BuckConverterPowerPath(InternalSubcircuit, GeneratorBlock): + """A helper block to generate the power path (inductors, capacitors) for a switching buck converter. + + Useful resources: + https://www.ti.com/lit/an/slva477b/slva477b.pdf + Component sizing in continuous mode + http://www.onmyphd.com/?p=voltage.regulators.buck.step.down.converter + Very detailed analysis including component sizing, operating modes, calculating losses + """ + + @staticmethod + def _d_inverse_d(d_range: Range) -> Range: + """Some power calculations require the maximum of D*(1-D), which has a maximum at D=0.5""" + # can't use range ops since they will double-count the tolerance of D, so calculate endpoints separately + range_endpoints = [d_range.lower * (1 - d_range.lower), d_range.upper * (1 - d_range.upper)] + raw_range = Range(min(range_endpoints), max(range_endpoints)) + if 0.5 in d_range: # the function has a maximum at 0.5 + return raw_range.hull(Range.exact(0.5 * (1 - 0.5))) + else: + return raw_range + + @staticmethod + def _ripple_current_from_sw_current(sw_current: float, ripple_ratio: Range) -> Range: + """Calculates the ripple current from a total switch current and ripple ratio.""" + return Range( # separate range parts to avoid double-counting tolerances + sw_current / (1 + ripple_ratio.lower) * ripple_ratio.lower, + sw_current / (1 + ripple_ratio.upper) * ripple_ratio.upper, + ) + + class Values(NamedTuple): + dutycycle: Range + inductance: Range + input_capacitance: Range + output_capacitance: Range + + inductor_avg_current: Range + ripple_scale: float # divide this by inductance to get the inductor ripple current + min_ripple: float # fallback minimum ripple current for component sizing for light-load, may be 0 + output_capacitance_scale: float # multiply inductor ripple by this to get required output capacitance + + inductor_peak_currents: Range # based on the worst case input spec, for unit testing + effective_dutycycle: Range # duty cycle adjusted for tracking behavior + + @classmethod + def _calculate_parameters( + cls, + input_voltage: Range, + output_voltage: Range, + frequency: Range, + output_current: Range, + sw_current_limits: Range, + ripple_ratio: Range, + input_voltage_ripple: float, + output_voltage_ripple: float, + efficiency: Range = Range(0.9, 1.0), + dutycycle_limit: Range = Range(0.1, 0.9), + limit_ripple_ratio: Range = Range(0.1, 0.5), + ) -> "BuckConverterPowerPath.Values": + """Calculates parameters for the buck converter power path. + + This uses the continuous conduction mode (CCM) equations to calculate component sizes. + DCM is not explicitly calculated since it requires additional parameters like minimum on-time. + The limit_ripple_ratio provides some broadly sane values for light-load / DCM operation. + This also ignores higher-order component behavior like capacitor ESR. + + The ripple_ratio is optional and may be set to Range.all(), allowing the inductor selector + to optimize the inductor by trading off inductance and max current. + + Values for component selections are bounded by: + - the ripple_ratio at output_current (if ripple_ratio < inf), and + - the limit_ripple_ratio at sw_current_limits (if sw_current_limits is not zero), as a fallback + for light-load conditions (where otherwise current goes to zero and inductance goes to the moon) + """ + dutycycle = output_voltage / input_voltage / efficiency + effective_dutycycle = dutycycle.bound_to(dutycycle_limit) # account for tracking behavior + + # calculate minimum inductance based on worst case values (operating range corners producing maximum inductance) + # worst-case input/output voltages and frequency is used to avoid double-counting tolerances as ranges + # note, for buck converter, L = (Vin - Vout) * D / (f * Iripple) = Vout (Vin - Vout) / (Iripple * f * Vin) + # this is at a maximum at Vin,max, and on that curve with a critical point at Vout = Vin,max / 2 + # note, the same formula calculates ripple-from-inductance and inductance-from-ripple + inductance_scale_candidates = [ + output_voltage.lower * (input_voltage.upper - output_voltage.lower) / input_voltage.upper, + output_voltage.upper * (input_voltage.upper - output_voltage.upper) / input_voltage.upper, + ] + if input_voltage.upper / 2 in output_voltage: + inductance_scale_candidates.append( + input_voltage.upper / 2 * (input_voltage.upper - input_voltage.upper / 2) / input_voltage.upper + ) + inductance_scale = max(inductance_scale_candidates) / frequency.lower + + inductance = Range.all() + min_ripple = 0.0 + if sw_current_limits.upper > 0: # fallback for light-load + ripple_current = cls._ripple_current_from_sw_current(sw_current_limits.upper, limit_ripple_ratio) + inductance = inductance.intersect(inductance_scale / ripple_current) + min_ripple = ripple_current.lower + if ripple_ratio.upper < float("inf"): + assert ripple_ratio.lower > 0, f"invalid non-inf ripple ratio {ripple_ratio}" + + inductance = inductance.intersect(inductance_scale / (output_current.upper * ripple_ratio)) + assert inductance.upper < float("inf"), "neither ripple_ratio nor fallback sw_current_limits given" + + input_capacitance = Range.from_lower( + output_current.upper + * cls._d_inverse_d(effective_dutycycle).upper + / (frequency.lower * input_voltage_ripple) + ) + output_capacitance_scale = 1 / (8 * frequency.lower * output_voltage_ripple) + + # these are static worst-case estimates for the range of specified ripple currents + # mainly used for unit testing + inductor_current_ripple = output_current * ripple_ratio.intersect(limit_ripple_ratio) + inductor_peak_currents = Range( + max(0, output_current.lower - inductor_current_ripple.upper / 2), + max(output_current.upper + inductor_current_ripple.upper / 2, inductor_current_ripple.upper), + ) + output_capacitance = Range.from_lower(output_capacitance_scale * inductor_current_ripple.upper) + + return cls.Values( + dutycycle=dutycycle, + inductance=inductance, + input_capacitance=input_capacitance, + output_capacitance=output_capacitance, + inductor_avg_current=output_current / efficiency, + ripple_scale=inductance_scale, + min_ripple=min_ripple, + output_capacitance_scale=output_capacitance_scale, + inductor_peak_currents=inductor_peak_currents, + effective_dutycycle=effective_dutycycle, + ) + + @staticmethod + @ExperimentalUserFnPartsTable.user_fn([float, float, float]) + def _buck_inductor_filter( + max_avg_current: float, ripple_scale: float, min_ripple: float + ) -> Callable[[PartsTableRow], bool]: + """Applies further filtering to inductors using the trade-off between inductance and peak-peak current. + max_avg_current is the maximum average current (not accounting for ripple) seen by the inductor + ripple_scale is the scaling factor from 1/L to ripple + This structure also works for boost converters, which would have its ripple_scale calculated differently.""" + + def filter_fn(row: PartsTableRow) -> bool: + ripple_current = max(ripple_scale / row[TableInductor.INDUCTANCE].lower, min_ripple) + max_current_pp = max_avg_current + ripple_current / 2 + return max_current_pp in row[TableInductor.CURRENT_RATING] + + return filter_fn + + @staticmethod + def _ilim_expr(inductor_ilim: RangeExpr, sw_ilim: RangeExpr, inductor_iripple: RangeExpr) -> RangeExpr: + """Returns the average current limit, as an expression, derived from the inductor and switch (instantaneous) + current limits.""" + iout_limit_inductor = inductor_ilim - (inductor_iripple.upper() / 2) + iout_limit_sw = (sw_ilim.upper() > 0).then_else(sw_ilim - (inductor_iripple.upper() / 2), Range.all()) + return iout_limit_inductor.intersect(iout_limit_sw).intersect(Range.from_lower(0)) + + def __init__( + self, + input_voltage: RangeLike, + output_voltage: RangeLike, + frequency: RangeLike, + output_current: RangeLike, + sw_current_limits: RangeLike, + *, + input_voltage_ripple: FloatLike, + output_voltage_ripple: FloatLike, + efficiency: RangeLike = (0.9, 1.0), # from TI reference + dutycycle_limit: RangeLike = (0.1, 0.9), + ripple_ratio: RangeLike = Range.all(), + ): + super().__init__() + + self.pwr_in = self.Port(VoltageSink.empty(), [Power]) # no modeling, input cap only + self.pwr_out = self.Port(VoltageSource.empty()) # models max output avg. current + # technically VoltageSink is the wrong model, but this is used to pass the current draw to the chip + # (and its input pin) without need the top-level to explicitly pass a parameter to the chip + self.switch = self.Port(VoltageSink.empty()) # models input / inductor avg. current draw + self.gnd = self.Port(Ground.empty(), [Common]) + + self.input_voltage = self.ArgParameter(input_voltage) + self.output_voltage = self.ArgParameter(output_voltage) + self.frequency = self.ArgParameter(frequency) + self.output_current = self.ArgParameter(output_current) + self.sw_current_limits = self.ArgParameter(sw_current_limits) + + self.efficiency = self.ArgParameter(efficiency) + self.input_voltage_ripple = self.ArgParameter(input_voltage_ripple) + self.output_voltage_ripple = self.ArgParameter(output_voltage_ripple) + self.dutycycle_limit = self.ArgParameter(dutycycle_limit) + self.ripple_ratio = self.ArgParameter(ripple_ratio) # only used to force a ripple ratio at the actual currents + + self.generator_param( + self.input_voltage, + self.output_voltage, + self.frequency, + self.output_current, + self.sw_current_limits, + self.input_voltage_ripple, + self.output_voltage_ripple, + self.efficiency, + self.dutycycle_limit, + self.ripple_ratio, + ) + + self.actual_dutycycle = self.Parameter(RangeExpr()) + self.actual_inductor_current_ripple = self.Parameter(RangeExpr()) + self.actual_inductor_current_peak = self.Parameter(RangeExpr()) + + @override + def contents(self) -> None: + super().contents() + + self.description = DescriptionString( + "duty cycle: ", + DescriptionString.FormatUnits(self.actual_dutycycle, ""), + " of limits: ", + DescriptionString.FormatUnits(self.dutycycle_limit, ""), + "\n", + "output current avg: ", + DescriptionString.FormatUnits(self.output_current, "A"), + ", ripple: ", + DescriptionString.FormatUnits(self.actual_inductor_current_ripple, "A"), + ) + + @override + def generate(self) -> None: + super().generate() + values = self._calculate_parameters( + self.get(self.input_voltage), + self.get(self.output_voltage), + self.get(self.frequency), + self.get(self.output_current), + self.get(self.sw_current_limits), + self.get(self.ripple_ratio), + self.get(self.input_voltage_ripple), + self.get(self.output_voltage_ripple), + efficiency=self.get(self.efficiency), + dutycycle_limit=self.get(self.dutycycle_limit), + ) + self.assign(self.actual_dutycycle, values.dutycycle) + self.require(values.dutycycle == values.effective_dutycycle, "dutycycle outside limit") + + self.inductor = self.Block( + Inductor( + inductance=values.inductance * Henry, + current=values.inductor_avg_current, # min-bound only, the real filter happens in the filter_fn + frequency=self.frequency, + experimental_filter_fn=ExperimentalUserFnPartsTable.serialize_fn( + self._buck_inductor_filter, + values.inductor_avg_current.upper, + values.ripple_scale, + values.min_ripple, + ), + ) + ) + self.assign(self.actual_inductor_current_ripple, values.ripple_scale / self.inductor.actual_inductance) + self.assign( + self.actual_inductor_current_peak, values.inductor_avg_current + self.actual_inductor_current_ripple / 2 + ) + + self.connect( + self.switch, + self.inductor.a.adapt_to(VoltageSink(current_draw=self.output_current * values.effective_dutycycle)), + ) + self.connect( + self.pwr_out, + self.inductor.b.adapt_to( + VoltageSource( + voltage_out=self.output_voltage, + current_limits=self._ilim_expr( + self.inductor.actual_current_rating, self.sw_current_limits, self.actual_inductor_current_ripple + ) + * self.efficiency, + ) + ), + ) + + self.in_cap = self.Block( + DecouplingCapacitor(capacitance=values.input_capacitance * Farad, exact_capacitance=True) + ).connected(self.gnd, self.pwr_in) + self.out_cap = self.Block( + DecouplingCapacitor( + capacitance=(Range.exact(float("inf")) * Farad).hull( + ( + values.output_capacitance_scale + * self.actual_inductor_current_ripple.upper().max(values.min_ripple) + ) + ), + exact_capacitance=True, + ) + ).connected(self.gnd, self.pwr_out) diff --git a/edg/circuits/UsbSeriesResistor.py b/edg/circuits/UsbSeriesResistor.py new file mode 100644 index 000000000..655c95bba --- /dev/null +++ b/edg/circuits/UsbSeriesResistor.py @@ -0,0 +1,19 @@ +from typing_extensions import override + +from ..abstract_parts import * + + +class UsbSeriesResistor(InternalSubcircuit, Block): + """Inline resistor on DM and DP lines, sometimes needed by microcontrollers.""" + + def __init__(self, resistance: RangeLike) -> None: + super().__init__() + self.resistance = self.ArgParameter(resistance) + self.interior = self.Port(UsbHostPort.empty(), [Input]) + self.exterior = self.Port(UsbDevicePort.empty(), [Output]) + + @override + def contents(self) -> None: + super().contents() + self.dp = self.Block(DigitalBidirSeriesResistor(self.resistance)).connected(self.interior.dp, self.exterior.dp) + self.dm = self.Block(DigitalBidirSeriesResistor(self.resistance)).connected(self.interior.dm, self.exterior.dm) diff --git a/edg/circuits/VoltageClamping.py b/edg/circuits/VoltageClamping.py new file mode 100644 index 000000000..c8565a738 --- /dev/null +++ b/edg/circuits/VoltageClamping.py @@ -0,0 +1,123 @@ +from typing import Dict +from typing_extensions import override + +from ..abstract_parts import * + + +class AnalogClampResistor(Protection, KiCadImportableBlock): + """Inline resistor that limits the current (to a parameterized amount) which works in concert + with ESD diodes in the downstream device to clamp the signal voltage to allowable levels. + + The protection voltage can be extended beyond the modeled range from the input signal, + and can also be specified to allow zero output voltage (for when the downstream device + is powered down) + + TODO: clamp_target should be inferred from the target voltage_limits, + but voltage_limits doesn't always get propagated""" + + def __init__( + self, + clamp_target: RangeLike = (0, 3) * Volt, + clamp_current: RangeLike = (0.25, 2.5) * mAmp, + protection_voltage: RangeLike = (0, 0) * Volt, + zero_out: BoolLike = False, + ): + super().__init__() + + 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() + + # TODO bidirectional clamping calcs? + self.res = self.Block( + Resistor( + resistance=1 + / self.clamp_current + * self.zero_out.then_else( + self.signal_in.link().voltage.hull(self.protection_voltage).upper(), + self.signal_in.link().voltage.hull(self.protection_voltage).upper() - self.clamp_target.upper(), + ) + ) + ) + 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]: + assert symbol_name == "Device:R" + return {"1": self.signal_in, "2": self.signal_out} + + +class DigitalClampResistor(Protection, KiCadImportableBlock): + """Inline resistor that limits the current (to a parameterized amount) which works in concert + with ESD diodes in the downstream device to clamp the signal voltage to allowable levels. + + The protection voltage can be extended beyond the modeled range from the input signal, + and can also be specified to allow zero output voltage (for when the downstream device + is powered down) + + TODO: clamp_target should be inferred from the target voltage_limits, + but voltage_limits doesn't always get propagated.""" + + def __init__( + self, + clamp_target: RangeLike = (0, 3) * Volt, + clamp_current: RangeLike = (1.0, 10) * mAmp, + protection_voltage: RangeLike = (0, 0) * Volt, + zero_out: BoolLike = False, + ): + super().__init__() + + 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(DigitalSink(current_draw=RangeExpr()), [Input]) + self.signal_out = self.Port( + DigitalSource( + voltage_out=self.signal_in.link().voltage.intersect(self.clamp_target), + output_thresholds=self.signal_in.link().output_thresholds, + ), + [Output], + ) + + @override + def contents(self) -> None: + super().contents() + + # TODO bidirectional clamping calcs? + self.assign(self.signal_in.current_draw, self.signal_out.link().current_drawn) + self.res = self.Block( + Resistor( + resistance=1 + / self.clamp_current + * self.zero_out.then_else( + self.signal_in.link().voltage.hull(self.protection_voltage).upper(), + self.signal_in.link().voltage.hull(self.protection_voltage).upper() - self.clamp_target.upper(), + ) + ) + ) + self.connect(self.res.a, self.signal_in.net) + self.connect(self.res.b, self.signal_out.net) + + @override + def symbol_pinning(self, symbol_name: str) -> Dict[str, Port]: + assert symbol_name == "Device:R" + return {"1": self.signal_in, "2": self.signal_out} diff --git a/edg/circuits/__init__.py b/edg/circuits/__init__.py index 99beea4b9..7d3246713 100644 --- a/edg/circuits/__init__.py +++ b/edg/circuits/__init__.py @@ -11,6 +11,10 @@ PmosReverseProtection, PmosChargerReverseProtection, ) +from .BootstrapCapacitor import BootstrapCapacitor +from .BuckConverterPowerPath import BuckConverterPowerPath +from .BoostConverterPowerPath import BoostConverterPowerPath +from .BuckBoostConverterPowerPath import BuckBoostConverterPowerPath from .BootstrapVoltageAdder import BootstrapVoltageAdder @@ -26,6 +30,8 @@ from .LevelShifter import BidirectionalLevelShifter +from .VoltageClamping import AnalogClampResistor, DigitalClampResistor + from .OpampCircuits import OpampFollower, Amplifier, DifferentialAmplifier, IntegratorInverting, SummingAmplifier from .OpampCurrentSensor import OpampCurrentSensor from .VoltageComparator import VoltageComparator @@ -58,3 +64,4 @@ from .RfNetworks import DiscreteRfWarning, LLowPassFilter, LLowPassFilterWith2HNotch, LHighPassFilter, PiLowPassFilter from .UsbBitBang import UsbBitBang +from .UsbSeriesResistor import UsbSeriesResistor diff --git a/edg/abstract_parts/test_switching_converters.py b/edg/circuits/test_switching_converters.py similarity index 98% rename from edg/abstract_parts/test_switching_converters.py rename to edg/circuits/test_switching_converters.py index 8317160d3..0f3c7a68a 100644 --- a/edg/abstract_parts/test_switching_converters.py +++ b/edg/circuits/test_switching_converters.py @@ -2,10 +2,9 @@ from typing_extensions import override -from .PowerConverters import BuckConverterPowerPath, BoostConverterPowerPath -from ..electronics_interfaces import * -from .Inductor import Inductor -from .Capacitor import Capacitor +from ..abstract_parts import * +from .BuckConverterPowerPath import BuckConverterPowerPath +from .BoostConverterPowerPath import BoostConverterPowerPath class SwitchingConverterCalculationTest(unittest.TestCase): diff --git a/edg/parts/power/LedDriver_Al8861.py b/edg/parts/power/LedDriver_Al8861.py index de9c58a55..77903f5ce 100644 --- a/edg/parts/power/LedDriver_Al8861.py +++ b/edg/parts/power/LedDriver_Al8861.py @@ -52,20 +52,29 @@ def contents(self) -> None: self.assign(self.actual_basic_part, False) -class Al8861(LedDriverPwm, LedDriverSwitchingConverter, LedDriver, GeneratorBlock): +class Al8861(PowerConditioner, GeneratorBlock): """AL8861 buck LED driver.""" - def __init__(self, diode_voltage_drop: RangeLike = Range.all()): + def __init__( + self, + max_current: RangeLike, + *, + ripple_limit: FloatLike = float("inf"), + diode_voltage_drop: RangeLike = Range.all(), + ): super().__init__() self.ic = self.Block(Al8861_Device(FloatExpr())) - self.connect(self.pwr, self.ic.vin) - self.connect(self.gnd, self.ic.gnd) - - self.generator_param(self.max_current) + self.gnd = self.Export(self.ic.gnd, [Common]) + self.pwr = self.Export(self.ic.vin, [Power]) + self.pwm = self.Port(DigitalSink.empty(), optional=True) + self.leda = self.Port(Passive()) + self.ledk = self.Port(Passive()) + + self.max_current = self.ArgParameter(max_current) + self.ripple_limit = self.ArgParameter(ripple_limit) self.diode_voltage_drop = self.ArgParameter(diode_voltage_drop) - - self.generator_param(self.pwm.is_connected()) + self.generator_param(self.max_current, self.pwm.is_connected()) self.actual_ripple = self.Parameter(RangeExpr()) diff --git a/edg/parts/power/LedDriver_Tps92200.py b/edg/parts/power/LedDriver_Tps92200.py index 77ec66854..5f0912bf1 100644 --- a/edg/parts/power/LedDriver_Tps92200.py +++ b/edg/parts/power/LedDriver_Tps92200.py @@ -56,12 +56,13 @@ def contents(self) -> None: self.assign(self.actual_basic_part, False) -class Tps92200(LedDriverPwm, LedDriver, GeneratorBlock): +class Tps92200(PowerConditioner): """TPS92200 buck 4-30V 1.5A 1 MHz LED driver and 150nS min on-time. This is the -D2 variant, with PWM input for 1-100% range as a 20-200kHz digital signal""" def __init__( self, + max_current: RangeLike, led_voltage: RangeLike = (1, 4) * Volt, *, input_ripple_limit: FloatLike = 0.2 * Volt, # from 8.2 example application @@ -70,18 +71,22 @@ def __init__( super().__init__() self.ic = self.Block(Tps92200_Device(FloatExpr())) - self.connect(self.gnd, self.ic.gnd) - self.connect(self.pwr, self.ic.vin) - self.connect(self.pwm, self.ic.dim) + self.gnd = self.Export(self.ic.gnd, [Common]) + self.pwr = self.Export(self.ic.vin, [Power]) + self.pwm = self.Export(self.ic.dim) + self.leda = self.Port(Passive()) + self.ledk = self.Port(Passive()) + self.require(self.pwm.is_connected()) # DIM does not appear to have a internal pull + self.max_current = self.ArgParameter(max_current) self.led_voltage = self.ArgParameter(led_voltage) self.input_ripple_limit = self.ArgParameter(input_ripple_limit) self.output_ripple_limit = self.ArgParameter(output_ripple_limit) @override - def generate(self) -> None: - super().generate() + def contents(self) -> None: + super().contents() with self.implicit_connect( ImplicitConnect(self.pwr, [Power]), diff --git a/examples/BleJoystick/BleJoystick.net.ref b/examples/BleJoystick/BleJoystick.net.ref index 019323326..c755d6971 100644 --- a/examples/BleJoystick/BleJoystick.net.ref +++ b/examples/BleJoystick/BleJoystick.net.ref @@ -160,7 +160,7 @@ (value "mp2722.power_path.inductor") (footprint "Inductor_SMD:L_1210_3225Metric") (property (name "Sheetname") (value "power_path")) - (property (name "Sheetfile") (value "edg.abstract_parts.PowerConverters.BuckConverterPowerPath")) + (property (name "Sheetfile") (value "edg.circuits.BuckConverterPowerPath.BuckConverterPowerPath")) (property (name "edg_path") (value "mp2722.power_path.inductor")) (property (name "edg_short_path") (value "mp2722.power_path.inductor")) (property (name "edg_refdes") (value "JL1")) @@ -172,7 +172,7 @@ (value "mp2722.power_path.in_cap") (footprint "Capacitor_SMD:C_0805_2012Metric") (property (name "Sheetname") (value "power_path")) - (property (name "Sheetfile") (value "edg.abstract_parts.PowerConverters.BuckConverterPowerPath")) + (property (name "Sheetfile") (value "edg.circuits.BuckConverterPowerPath.BuckConverterPowerPath")) (property (name "edg_path") (value "mp2722.power_path.in_cap.cap")) (property (name "edg_short_path") (value "mp2722.power_path.in_cap")) (property (name "edg_refdes") (value "JC5")) @@ -184,7 +184,7 @@ (value "mp2722.power_path.out_cap") (footprint "Capacitor_SMD:C_0805_2012Metric") (property (name "Sheetname") (value "power_path")) - (property (name "Sheetfile") (value "edg.abstract_parts.PowerConverters.BuckConverterPowerPath")) + (property (name "Sheetfile") (value "edg.circuits.BuckConverterPowerPath.BuckConverterPowerPath")) (property (name "edg_path") (value "mp2722.power_path.out_cap.cap")) (property (name "edg_short_path") (value "mp2722.power_path.out_cap")) (property (name "edg_refdes") (value "JC6")) diff --git a/examples/CanAdapter/CanAdapter.net.ref b/examples/CanAdapter/CanAdapter.net.ref index 6a3fa4ef3..33731cce7 100644 --- a/examples/CanAdapter/CanAdapter.net.ref +++ b/examples/CanAdapter/CanAdapter.net.ref @@ -124,7 +124,7 @@ (value "reg_3v3.power_path.inductor") (footprint "Inductor_SMD:L_1210_3225Metric") (property (name "Sheetname") (value "power_path")) - (property (name "Sheetfile") (value "edg.abstract_parts.PowerConverters.BuckConverterPowerPath")) + (property (name "Sheetfile") (value "edg.circuits.BuckConverterPowerPath.BuckConverterPowerPath")) (property (name "edg_path") (value "reg_3v3.power_path.inductor")) (property (name "edg_short_path") (value "reg_3v3.power_path.inductor")) (property (name "edg_refdes") (value "OL1")) @@ -136,7 +136,7 @@ (value "reg_3v3.power_path.in_cap") (footprint "Capacitor_SMD:C_1206_3216Metric") (property (name "Sheetname") (value "power_path")) - (property (name "Sheetfile") (value "edg.abstract_parts.PowerConverters.BuckConverterPowerPath")) + (property (name "Sheetfile") (value "edg.circuits.BuckConverterPowerPath.BuckConverterPowerPath")) (property (name "edg_path") (value "reg_3v3.power_path.in_cap.cap")) (property (name "edg_short_path") (value "reg_3v3.power_path.in_cap")) (property (name "edg_refdes") (value "OC3")) @@ -148,7 +148,7 @@ (value "reg_3v3.power_path.out_cap") (footprint "Capacitor_SMD:C_0805_2012Metric") (property (name "Sheetname") (value "power_path")) - (property (name "Sheetfile") (value "edg.abstract_parts.PowerConverters.BuckConverterPowerPath")) + (property (name "Sheetfile") (value "edg.circuits.BuckConverterPowerPath.BuckConverterPowerPath")) (property (name "edg_path") (value "reg_3v3.power_path.out_cap.cap")) (property (name "edg_short_path") (value "reg_3v3.power_path.out_cap")) (property (name "edg_refdes") (value "OC4")) diff --git a/examples/Datalogger/Datalogger.net.ref b/examples/Datalogger/Datalogger.net.ref index bd59687bc..d23ef8910 100644 --- a/examples/Datalogger/Datalogger.net.ref +++ b/examples/Datalogger/Datalogger.net.ref @@ -124,7 +124,7 @@ (value "pwr_5v.power_path.inductor") (footprint "Inductor_SMD:L_Taiyo-Yuden_NR-50xx") (property (name "Sheetname") (value "power_path")) - (property (name "Sheetfile") (value "edg.abstract_parts.PowerConverters.BuckConverterPowerPath")) + (property (name "Sheetfile") (value "edg.circuits.BuckConverterPowerPath.BuckConverterPowerPath")) (property (name "edg_path") (value "pwr_5v.power_path.inductor")) (property (name "edg_short_path") (value "pwr_5v.power_path.inductor")) (property (name "edg_refdes") (value "L1")) @@ -136,7 +136,7 @@ (value "pwr_5v.power_path.in_cap") (footprint "Capacitor_SMD:C_0805_2012Metric") (property (name "Sheetname") (value "power_path")) - (property (name "Sheetfile") (value "edg.abstract_parts.PowerConverters.BuckConverterPowerPath")) + (property (name "Sheetfile") (value "edg.circuits.BuckConverterPowerPath.BuckConverterPowerPath")) (property (name "edg_path") (value "pwr_5v.power_path.in_cap.cap")) (property (name "edg_short_path") (value "pwr_5v.power_path.in_cap")) (property (name "edg_refdes") (value "C3")) @@ -148,7 +148,7 @@ (value "pwr_5v.power_path.out_cap") (footprint "Capacitor_SMD:C_0805_2012Metric") (property (name "Sheetname") (value "power_path")) - (property (name "Sheetfile") (value "edg.abstract_parts.PowerConverters.BuckConverterPowerPath")) + (property (name "Sheetfile") (value "edg.circuits.BuckConverterPowerPath.BuckConverterPowerPath")) (property (name "edg_path") (value "pwr_5v.power_path.out_cap.cap")) (property (name "edg_short_path") (value "pwr_5v.power_path.out_cap")) (property (name "edg_refdes") (value "C4")) diff --git a/examples/Fcml/Fcml.net.ref b/examples/Fcml/Fcml.net.ref index a956517fc..006ac7abe 100644 --- a/examples/Fcml/Fcml.net.ref +++ b/examples/Fcml/Fcml.net.ref @@ -244,7 +244,7 @@ (value "reg_vgate.power_path.inductor") (footprint "Inductor_SMD:L_Sunlord_SWPA3015S") (property (name "Sheetname") (value "power_path")) - (property (name "Sheetfile") (value "edg.abstract_parts.PowerConverters.BoostConverterPowerPath")) + (property (name "Sheetfile") (value "edg.circuits.BoostConverterPowerPath.BoostConverterPowerPath")) (property (name "edg_path") (value "reg_vgate.power_path.inductor")) (property (name "edg_short_path") (value "reg_vgate.power_path.inductor")) (property (name "edg_refdes") (value "L1")) @@ -256,7 +256,7 @@ (value "reg_vgate.power_path.in_cap") (footprint "Capacitor_SMD:C_0805_2012Metric") (property (name "Sheetname") (value "power_path")) - (property (name "Sheetfile") (value "edg.abstract_parts.PowerConverters.BoostConverterPowerPath")) + (property (name "Sheetfile") (value "edg.circuits.BoostConverterPowerPath.BoostConverterPowerPath")) (property (name "edg_path") (value "reg_vgate.power_path.in_cap.cap")) (property (name "edg_short_path") (value "reg_vgate.power_path.in_cap")) (property (name "edg_refdes") (value "C3")) @@ -268,7 +268,7 @@ (value "reg_vgate.power_path.out_cap") (footprint "Capacitor_SMD:C_0805_2012Metric") (property (name "Sheetname") (value "power_path")) - (property (name "Sheetfile") (value "edg.abstract_parts.PowerConverters.BoostConverterPowerPath")) + (property (name "Sheetfile") (value "edg.circuits.BoostConverterPowerPath.BoostConverterPowerPath")) (property (name "edg_path") (value "reg_vgate.power_path.out_cap.cap")) (property (name "edg_short_path") (value "reg_vgate.power_path.out_cap")) (property (name "edg_refdes") (value "C4")) @@ -1612,7 +1612,7 @@ (value "mcu.usb_res.dp") (footprint "Resistor_SMD:R_0603_1608Metric") (property (name "Sheetname") (value "usb_res")) - (property (name "Sheetfile") (value "edg.abstract_parts.Resistor.UsbSeriesResistor")) + (property (name "Sheetfile") (value "edg.circuits.UsbSeriesResistor.UsbSeriesResistor")) (property (name "edg_path") (value "mcu.usb_res.dp.res")) (property (name "edg_short_path") (value "mcu.usb_res.dp")) (property (name "edg_refdes") (value "R24")) @@ -1624,7 +1624,7 @@ (value "mcu.usb_res.dm") (footprint "Resistor_SMD:R_0603_1608Metric") (property (name "Sheetname") (value "usb_res")) - (property (name "Sheetfile") (value "edg.abstract_parts.Resistor.UsbSeriesResistor")) + (property (name "Sheetfile") (value "edg.circuits.UsbSeriesResistor.UsbSeriesResistor")) (property (name "edg_path") (value "mcu.usb_res.dm.res")) (property (name "edg_short_path") (value "mcu.usb_res.dm")) (property (name "edg_refdes") (value "R25")) diff --git a/examples/HighSwitch/HighSwitch.net.ref b/examples/HighSwitch/HighSwitch.net.ref index 5b33e9cbc..223386972 100644 --- a/examples/HighSwitch/HighSwitch.net.ref +++ b/examples/HighSwitch/HighSwitch.net.ref @@ -76,7 +76,7 @@ (value "pwr.power_path.inductor") (footprint "Inductor_SMD:L_0805_2012Metric") (property (name "Sheetname") (value "power_path")) - (property (name "Sheetfile") (value "edg.abstract_parts.PowerConverters.BuckConverterPowerPath")) + (property (name "Sheetfile") (value "edg.circuits.BuckConverterPowerPath.BuckConverterPowerPath")) (property (name "edg_path") (value "pwr.power_path.inductor")) (property (name "edg_short_path") (value "pwr.power_path.inductor")) (property (name "edg_refdes") (value "L1")) @@ -88,7 +88,7 @@ (value "pwr.power_path.in_cap") (footprint "Capacitor_SMD:C_0603_1608Metric") (property (name "Sheetname") (value "power_path")) - (property (name "Sheetfile") (value "edg.abstract_parts.PowerConverters.BuckConverterPowerPath")) + (property (name "Sheetfile") (value "edg.circuits.BuckConverterPowerPath.BuckConverterPowerPath")) (property (name "edg_path") (value "pwr.power_path.in_cap.cap")) (property (name "edg_short_path") (value "pwr.power_path.in_cap")) (property (name "edg_refdes") (value "C3")) @@ -100,7 +100,7 @@ (value "pwr.power_path.out_cap") (footprint "Capacitor_SMD:C_0805_2012Metric") (property (name "Sheetname") (value "power_path")) - (property (name "Sheetfile") (value "edg.abstract_parts.PowerConverters.BuckConverterPowerPath")) + (property (name "Sheetfile") (value "edg.circuits.BuckConverterPowerPath.BuckConverterPowerPath")) (property (name "edg_path") (value "pwr.power_path.out_cap.cap")) (property (name "edg_short_path") (value "pwr.power_path.out_cap")) (property (name "edg_refdes") (value "C4")) diff --git a/examples/IotCurtainCrawler/IotCurtainCrawler.net.ref b/examples/IotCurtainCrawler/IotCurtainCrawler.net.ref index e21da59ca..1196e2efb 100644 --- a/examples/IotCurtainCrawler/IotCurtainCrawler.net.ref +++ b/examples/IotCurtainCrawler/IotCurtainCrawler.net.ref @@ -172,7 +172,7 @@ (value "reg_3v3.power_path.inductor") (footprint "Inductor_SMD:L_Sunlord_SWPA4030S") (property (name "Sheetname") (value "power_path")) - (property (name "Sheetfile") (value "edg.abstract_parts.PowerConverters.BuckConverterPowerPath")) + (property (name "Sheetfile") (value "edg.circuits.BuckConverterPowerPath.BuckConverterPowerPath")) (property (name "edg_path") (value "reg_3v3.power_path.inductor")) (property (name "edg_short_path") (value "reg_3v3.power_path.inductor")) (property (name "edg_refdes") (value "RL1")) @@ -208,7 +208,7 @@ (value "reg_3v3.power_path.out_cap") (footprint "Capacitor_SMD:C_0805_2012Metric") (property (name "Sheetname") (value "power_path")) - (property (name "Sheetfile") (value "edg.abstract_parts.PowerConverters.BuckConverterPowerPath")) + (property (name "Sheetfile") (value "edg.circuits.BuckConverterPowerPath.BuckConverterPowerPath")) (property (name "edg_path") (value "reg_3v3.power_path.out_cap.cap")) (property (name "edg_short_path") (value "reg_3v3.power_path.out_cap")) (property (name "edg_refdes") (value "RC5")) diff --git a/examples/IotDisplay/IotDisplay.net.ref b/examples/IotDisplay/IotDisplay.net.ref index d9e4e47cc..c90c38c70 100644 --- a/examples/IotDisplay/IotDisplay.net.ref +++ b/examples/IotDisplay/IotDisplay.net.ref @@ -160,7 +160,7 @@ (value "reg_3v3.power_path.inductor") (footprint "Inductor_SMD:L_Sunlord_SWPA4030S") (property (name "Sheetname") (value "power_path")) - (property (name "Sheetfile") (value "edg.abstract_parts.PowerConverters.BuckConverterPowerPath")) + (property (name "Sheetfile") (value "edg.circuits.BuckConverterPowerPath.BuckConverterPowerPath")) (property (name "edg_path") (value "reg_3v3.power_path.inductor")) (property (name "edg_short_path") (value "reg_3v3.power_path.inductor")) (property (name "edg_refdes") (value "L1")) @@ -172,7 +172,7 @@ (value "reg_3v3.power_path.in_cap") (footprint "Capacitor_SMD:C_1206_3216Metric") (property (name "Sheetname") (value "power_path")) - (property (name "Sheetfile") (value "edg.abstract_parts.PowerConverters.BuckConverterPowerPath")) + (property (name "Sheetfile") (value "edg.circuits.BuckConverterPowerPath.BuckConverterPowerPath")) (property (name "edg_path") (value "reg_3v3.power_path.in_cap.cap")) (property (name "edg_short_path") (value "reg_3v3.power_path.in_cap")) (property (name "edg_refdes") (value "C3")) @@ -184,7 +184,7 @@ (value "reg_3v3.power_path.out_cap") (footprint "Capacitor_SMD:C_1206_3216Metric") (property (name "Sheetname") (value "power_path")) - (property (name "Sheetfile") (value "edg.abstract_parts.PowerConverters.BuckConverterPowerPath")) + (property (name "Sheetfile") (value "edg.circuits.BuckConverterPowerPath.BuckConverterPowerPath")) (property (name "edg_path") (value "reg_3v3.power_path.out_cap.cap")) (property (name "edg_short_path") (value "reg_3v3.power_path.out_cap")) (property (name "edg_refdes") (value "C4")) diff --git a/examples/IotFan/IotFan.net.ref b/examples/IotFan/IotFan.net.ref index 401f0e572..7467c0513 100644 --- a/examples/IotFan/IotFan.net.ref +++ b/examples/IotFan/IotFan.net.ref @@ -136,7 +136,7 @@ (value "reg_5v.power_path.inductor") (footprint "Inductor_SMD:L_Sunlord_SWPA4030S") (property (name "Sheetname") (value "power_path")) - (property (name "Sheetfile") (value "edg.abstract_parts.PowerConverters.BuckConverterPowerPath")) + (property (name "Sheetfile") (value "edg.circuits.BuckConverterPowerPath.BuckConverterPowerPath")) (property (name "edg_path") (value "reg_5v.power_path.inductor")) (property (name "edg_short_path") (value "reg_5v.power_path.inductor")) (property (name "edg_refdes") (value "FL1")) @@ -148,7 +148,7 @@ (value "reg_5v.power_path.in_cap") (footprint "Capacitor_SMD:C_1206_3216Metric") (property (name "Sheetname") (value "power_path")) - (property (name "Sheetfile") (value "edg.abstract_parts.PowerConverters.BuckConverterPowerPath")) + (property (name "Sheetfile") (value "edg.circuits.BuckConverterPowerPath.BuckConverterPowerPath")) (property (name "edg_path") (value "reg_5v.power_path.in_cap.cap")) (property (name "edg_short_path") (value "reg_5v.power_path.in_cap")) (property (name "edg_refdes") (value "FC3")) @@ -160,7 +160,7 @@ (value "reg_5v.power_path.out_cap") (footprint "Capacitor_SMD:C_1206_3216Metric") (property (name "Sheetname") (value "power_path")) - (property (name "Sheetfile") (value "edg.abstract_parts.PowerConverters.BuckConverterPowerPath")) + (property (name "Sheetfile") (value "edg.circuits.BuckConverterPowerPath.BuckConverterPowerPath")) (property (name "edg_path") (value "reg_5v.power_path.out_cap.cap")) (property (name "edg_short_path") (value "reg_5v.power_path.out_cap")) (property (name "edg_refdes") (value "FC4")) diff --git a/examples/IotIron/IotIron.net.ref b/examples/IotIron/IotIron.net.ref index 196602cf3..a76a5355b 100644 --- a/examples/IotIron/IotIron.net.ref +++ b/examples/IotIron/IotIron.net.ref @@ -136,7 +136,7 @@ (value "reg_3v3.power_path.inductor") (footprint "Inductor_SMD:L_Sunlord_SWPA5040S") (property (name "Sheetname") (value "power_path")) - (property (name "Sheetfile") (value "edg.abstract_parts.PowerConverters.BuckConverterPowerPath")) + (property (name "Sheetfile") (value "edg.circuits.BuckConverterPowerPath.BuckConverterPowerPath")) (property (name "edg_path") (value "reg_3v3.power_path.inductor")) (property (name "edg_short_path") (value "reg_3v3.power_path.inductor")) (property (name "edg_refdes") (value "IL1")) @@ -172,7 +172,7 @@ (value "reg_3v3.power_path.out_cap") (footprint "Capacitor_SMD:C_0805_2012Metric") (property (name "Sheetname") (value "power_path")) - (property (name "Sheetfile") (value "edg.abstract_parts.PowerConverters.BuckConverterPowerPath")) + (property (name "Sheetfile") (value "edg.circuits.BuckConverterPowerPath.BuckConverterPowerPath")) (property (name "edg_path") (value "reg_3v3.power_path.out_cap.cap")) (property (name "edg_short_path") (value "reg_3v3.power_path.out_cap")) (property (name "edg_refdes") (value "IC5")) @@ -652,7 +652,7 @@ (value "conv.power_path.inductor") (footprint "Inductor_SMD:L_TDK_SLF12575") (property (name "Sheetname") (value "power_path")) - (property (name "Sheetfile") (value "edg.abstract_parts.PowerConverters.BuckConverterPowerPath")) + (property (name "Sheetfile") (value "edg.circuits.BuckConverterPowerPath.BuckConverterPowerPath")) (property (name "edg_path") (value "conv.power_path.inductor")) (property (name "edg_short_path") (value "conv.power_path.inductor")) (property (name "edg_refdes") (value "IL2")) @@ -688,7 +688,7 @@ (value "conv.power_path.out_cap") (footprint "Capacitor_SMD:C_0805_2012Metric") (property (name "Sheetname") (value "power_path")) - (property (name "Sheetfile") (value "edg.abstract_parts.PowerConverters.BuckConverterPowerPath")) + (property (name "Sheetfile") (value "edg.circuits.BuckConverterPowerPath.BuckConverterPowerPath")) (property (name "edg_path") (value "conv.power_path.out_cap.cap")) (property (name "edg_short_path") (value "conv.power_path.out_cap")) (property (name "edg_refdes") (value "IC24")) diff --git a/examples/IotLedDriver/IotLedDriver.net.ref b/examples/IotLedDriver/IotLedDriver.net.ref index ae7d273bf..5369e8b5f 100644 --- a/examples/IotLedDriver/IotLedDriver.net.ref +++ b/examples/IotLedDriver/IotLedDriver.net.ref @@ -136,7 +136,7 @@ (value "reg_3v3.power_path.inductor") (footprint "Inductor_SMD:L_1210_3225Metric") (property (name "Sheetname") (value "power_path")) - (property (name "Sheetfile") (value "edg.abstract_parts.PowerConverters.BuckConverterPowerPath")) + (property (name "Sheetfile") (value "edg.circuits.BuckConverterPowerPath.BuckConverterPowerPath")) (property (name "edg_path") (value "reg_3v3.power_path.inductor")) (property (name "edg_short_path") (value "reg_3v3.power_path.inductor")) (property (name "edg_refdes") (value "LL1")) @@ -148,7 +148,7 @@ (value "reg_3v3.power_path.in_cap") (footprint "Capacitor_SMD:C_1206_3216Metric") (property (name "Sheetname") (value "power_path")) - (property (name "Sheetfile") (value "edg.abstract_parts.PowerConverters.BuckConverterPowerPath")) + (property (name "Sheetfile") (value "edg.circuits.BuckConverterPowerPath.BuckConverterPowerPath")) (property (name "edg_path") (value "reg_3v3.power_path.in_cap.cap")) (property (name "edg_short_path") (value "reg_3v3.power_path.in_cap")) (property (name "edg_refdes") (value "LC3")) @@ -160,7 +160,7 @@ (value "reg_3v3.power_path.out_cap") (footprint "Capacitor_SMD:C_1206_3216Metric") (property (name "Sheetname") (value "power_path")) - (property (name "Sheetfile") (value "edg.abstract_parts.PowerConverters.BuckConverterPowerPath")) + (property (name "Sheetfile") (value "edg.circuits.BuckConverterPowerPath.BuckConverterPowerPath")) (property (name "edg_path") (value "reg_3v3.power_path.out_cap.cap")) (property (name "edg_short_path") (value "reg_3v3.power_path.out_cap")) (property (name "edg_refdes") (value "LC4")) @@ -652,7 +652,7 @@ (value "led_drv[0].power_path.inductor") (footprint "Inductor_SMD:L_Sunlord_SWPA4030S") (property (name "Sheetname") (value "power_path")) - (property (name "Sheetfile") (value "edg.abstract_parts.PowerConverters.BuckConverterPowerPath")) + (property (name "Sheetfile") (value "edg.circuits.BuckConverterPowerPath.BuckConverterPowerPath")) (property (name "edg_path") (value "led_drv[0].power_path.inductor")) (property (name "edg_short_path") (value "led_drv[0].power_path.inductor")) (property (name "edg_refdes") (value "LL4")) @@ -664,7 +664,7 @@ (value "led_drv[0].power_path.in_cap") (footprint "Capacitor_SMD:C_0805_2012Metric") (property (name "Sheetname") (value "power_path")) - (property (name "Sheetfile") (value "edg.abstract_parts.PowerConverters.BuckConverterPowerPath")) + (property (name "Sheetfile") (value "edg.circuits.BuckConverterPowerPath.BuckConverterPowerPath")) (property (name "edg_path") (value "led_drv[0].power_path.in_cap.cap")) (property (name "edg_short_path") (value "led_drv[0].power_path.in_cap")) (property (name "edg_refdes") (value "LC22")) @@ -676,7 +676,7 @@ (value "led_drv[0].power_path.out_cap") (footprint "Capacitor_SMD:C_1206_3216Metric") (property (name "Sheetname") (value "power_path")) - (property (name "Sheetfile") (value "edg.abstract_parts.PowerConverters.BuckConverterPowerPath")) + (property (name "Sheetfile") (value "edg.circuits.BuckConverterPowerPath.BuckConverterPowerPath")) (property (name "edg_path") (value "led_drv[0].power_path.out_cap.cap")) (property (name "edg_short_path") (value "led_drv[0].power_path.out_cap")) (property (name "edg_refdes") (value "LC23")) @@ -736,7 +736,7 @@ (value "led_drv[1].power_path.inductor") (footprint "Inductor_SMD:L_Sunlord_SWPA4030S") (property (name "Sheetname") (value "power_path")) - (property (name "Sheetfile") (value "edg.abstract_parts.PowerConverters.BuckConverterPowerPath")) + (property (name "Sheetfile") (value "edg.circuits.BuckConverterPowerPath.BuckConverterPowerPath")) (property (name "edg_path") (value "led_drv[1].power_path.inductor")) (property (name "edg_short_path") (value "led_drv[1].power_path.inductor")) (property (name "edg_refdes") (value "LL5")) @@ -748,7 +748,7 @@ (value "led_drv[1].power_path.in_cap") (footprint "Capacitor_SMD:C_0805_2012Metric") (property (name "Sheetname") (value "power_path")) - (property (name "Sheetfile") (value "edg.abstract_parts.PowerConverters.BuckConverterPowerPath")) + (property (name "Sheetfile") (value "edg.circuits.BuckConverterPowerPath.BuckConverterPowerPath")) (property (name "edg_path") (value "led_drv[1].power_path.in_cap.cap")) (property (name "edg_short_path") (value "led_drv[1].power_path.in_cap")) (property (name "edg_refdes") (value "LC26")) @@ -760,7 +760,7 @@ (value "led_drv[1].power_path.out_cap") (footprint "Capacitor_SMD:C_1206_3216Metric") (property (name "Sheetname") (value "power_path")) - (property (name "Sheetfile") (value "edg.abstract_parts.PowerConverters.BuckConverterPowerPath")) + (property (name "Sheetfile") (value "edg.circuits.BuckConverterPowerPath.BuckConverterPowerPath")) (property (name "edg_path") (value "led_drv[1].power_path.out_cap.cap")) (property (name "edg_short_path") (value "led_drv[1].power_path.out_cap")) (property (name "edg_refdes") (value "LC27")) @@ -820,7 +820,7 @@ (value "led_drv[2].power_path.inductor") (footprint "Inductor_SMD:L_Sunlord_SWPA4030S") (property (name "Sheetname") (value "power_path")) - (property (name "Sheetfile") (value "edg.abstract_parts.PowerConverters.BuckConverterPowerPath")) + (property (name "Sheetfile") (value "edg.circuits.BuckConverterPowerPath.BuckConverterPowerPath")) (property (name "edg_path") (value "led_drv[2].power_path.inductor")) (property (name "edg_short_path") (value "led_drv[2].power_path.inductor")) (property (name "edg_refdes") (value "LL6")) @@ -832,7 +832,7 @@ (value "led_drv[2].power_path.in_cap") (footprint "Capacitor_SMD:C_0805_2012Metric") (property (name "Sheetname") (value "power_path")) - (property (name "Sheetfile") (value "edg.abstract_parts.PowerConverters.BuckConverterPowerPath")) + (property (name "Sheetfile") (value "edg.circuits.BuckConverterPowerPath.BuckConverterPowerPath")) (property (name "edg_path") (value "led_drv[2].power_path.in_cap.cap")) (property (name "edg_short_path") (value "led_drv[2].power_path.in_cap")) (property (name "edg_refdes") (value "LC30")) @@ -844,7 +844,7 @@ (value "led_drv[2].power_path.out_cap") (footprint "Capacitor_SMD:C_1206_3216Metric") (property (name "Sheetname") (value "power_path")) - (property (name "Sheetfile") (value "edg.abstract_parts.PowerConverters.BuckConverterPowerPath")) + (property (name "Sheetfile") (value "edg.circuits.BuckConverterPowerPath.BuckConverterPowerPath")) (property (name "edg_path") (value "led_drv[2].power_path.out_cap.cap")) (property (name "edg_short_path") (value "led_drv[2].power_path.out_cap")) (property (name "edg_refdes") (value "LC31")) @@ -904,7 +904,7 @@ (value "led_drv[3].power_path.inductor") (footprint "Inductor_SMD:L_Sunlord_SWPA4030S") (property (name "Sheetname") (value "power_path")) - (property (name "Sheetfile") (value "edg.abstract_parts.PowerConverters.BuckConverterPowerPath")) + (property (name "Sheetfile") (value "edg.circuits.BuckConverterPowerPath.BuckConverterPowerPath")) (property (name "edg_path") (value "led_drv[3].power_path.inductor")) (property (name "edg_short_path") (value "led_drv[3].power_path.inductor")) (property (name "edg_refdes") (value "LL7")) @@ -916,7 +916,7 @@ (value "led_drv[3].power_path.in_cap") (footprint "Capacitor_SMD:C_0805_2012Metric") (property (name "Sheetname") (value "power_path")) - (property (name "Sheetfile") (value "edg.abstract_parts.PowerConverters.BuckConverterPowerPath")) + (property (name "Sheetfile") (value "edg.circuits.BuckConverterPowerPath.BuckConverterPowerPath")) (property (name "edg_path") (value "led_drv[3].power_path.in_cap.cap")) (property (name "edg_short_path") (value "led_drv[3].power_path.in_cap")) (property (name "edg_refdes") (value "LC34")) @@ -928,7 +928,7 @@ (value "led_drv[3].power_path.out_cap") (footprint "Capacitor_SMD:C_1206_3216Metric") (property (name "Sheetname") (value "power_path")) - (property (name "Sheetfile") (value "edg.abstract_parts.PowerConverters.BuckConverterPowerPath")) + (property (name "Sheetfile") (value "edg.circuits.BuckConverterPowerPath.BuckConverterPowerPath")) (property (name "edg_path") (value "led_drv[3].power_path.out_cap.cap")) (property (name "edg_short_path") (value "led_drv[3].power_path.out_cap")) (property (name "edg_refdes") (value "LC35")) @@ -1125,15 +1125,15 @@ (node (ref LR12) (pin 2))) (net (code 24) (name "Ltof.ic.gpio1") (node (ref LU3) (pin 7))) -(net (code 25) (name "Lled_drv[0].leda") +(net (code 25) (name "Lled_drv[0].pwm") + (node (ref LU2) (pin 5)) + (node (ref LU4) (pin 2))) +(net (code 26) (name "Lled_drv[0].leda") (node (ref LL4) (pin 2)) (node (ref LC23) (pin 1))) -(net (code 26) (name "Lled_drv[0].ledk") +(net (code 27) (name "Lled_drv[0].ledk") (node (ref LU4) (pin 1)) (node (ref LR13) (pin 2))) -(net (code 27) (name "Lled_drv[0].pwm") - (node (ref LU2) (pin 5)) - (node (ref LU4) (pin 2))) (net (code 28) (name "Lled_drv[0].ic.sw") (node (ref LU4) (pin 5)) (node (ref LC21) (pin 2)) @@ -1141,15 +1141,15 @@ (net (code 29) (name "Lled_drv[0].ic.boot") (node (ref LU4) (pin 6)) (node (ref LC21) (pin 1))) -(net (code 30) (name "Lled_drv[1].leda") +(net (code 30) (name "Lled_drv[1].pwm") + (node (ref LU2) (pin 8)) + (node (ref LU5) (pin 2))) +(net (code 31) (name "Lled_drv[1].leda") (node (ref LL5) (pin 2)) (node (ref LC27) (pin 1))) -(net (code 31) (name "Lled_drv[1].ledk") +(net (code 32) (name "Lled_drv[1].ledk") (node (ref LU5) (pin 1)) (node (ref LR14) (pin 2))) -(net (code 32) (name "Lled_drv[1].pwm") - (node (ref LU2) (pin 8)) - (node (ref LU5) (pin 2))) (net (code 33) (name "Lled_drv[1].ic.sw") (node (ref LU5) (pin 5)) (node (ref LC25) (pin 2)) @@ -1157,15 +1157,15 @@ (net (code 34) (name "Lled_drv[1].ic.boot") (node (ref LU5) (pin 6)) (node (ref LC25) (pin 1))) -(net (code 35) (name "Lled_drv[2].leda") +(net (code 35) (name "Lled_drv[2].pwm") + (node (ref LU2) (pin 9)) + (node (ref LU6) (pin 2))) +(net (code 36) (name "Lled_drv[2].leda") (node (ref LL6) (pin 2)) (node (ref LC31) (pin 1))) -(net (code 36) (name "Lled_drv[2].ledk") +(net (code 37) (name "Lled_drv[2].ledk") (node (ref LU6) (pin 1)) (node (ref LR15) (pin 2))) -(net (code 37) (name "Lled_drv[2].pwm") - (node (ref LU2) (pin 9)) - (node (ref LU6) (pin 2))) (net (code 38) (name "Lled_drv[2].ic.sw") (node (ref LU6) (pin 5)) (node (ref LC29) (pin 2)) @@ -1173,15 +1173,15 @@ (net (code 39) (name "Lled_drv[2].ic.boot") (node (ref LU6) (pin 6)) (node (ref LC29) (pin 1))) -(net (code 40) (name "Lled_drv[3].leda") +(net (code 40) (name "Lled_drv[3].pwm") + (node (ref LU2) (pin 10)) + (node (ref LU7) (pin 2))) +(net (code 41) (name "Lled_drv[3].leda") (node (ref LL7) (pin 2)) (node (ref LC35) (pin 1))) -(net (code 41) (name "Lled_drv[3].ledk") +(net (code 42) (name "Lled_drv[3].ledk") (node (ref LU7) (pin 1)) (node (ref LR16) (pin 2))) -(net (code 42) (name "Lled_drv[3].pwm") - (node (ref LU2) (pin 10)) - (node (ref LU7) (pin 2))) (net (code 43) (name "Lled_drv[3].ic.sw") (node (ref LU7) (pin 5)) (node (ref LC33) (pin 2)) diff --git a/examples/IotLedDriver/IotLedDriver.svgpcb.js b/examples/IotLedDriver/IotLedDriver.svgpcb.js index 654d009de..e340e980b 100644 --- a/examples/IotLedDriver/IotLedDriver.svgpcb.js +++ b/examples/IotLedDriver/IotLedDriver.svgpcb.js @@ -416,24 +416,24 @@ board.setNetlist([ {name: "Ltof.i2c.scl", pads: [["LU2", "12"], ["LU3", "10"], ["LR11", "2"]]}, {name: "Ltof.i2c.sda", pads: [["LU2", "13"], ["LU3", "9"], ["LR12", "2"]]}, {name: "Ltof.ic.gpio1", pads: [["LU3", "7"]]}, + {name: "Lled_drv[0].pwm", pads: [["LU2", "5"], ["LU4", "2"]]}, {name: "Lled_drv[0].leda", pads: [["LL4", "2"], ["LC23", "1"]]}, {name: "Lled_drv[0].ledk", pads: [["LU4", "1"], ["LR13", "2"]]}, - {name: "Lled_drv[0].pwm", pads: [["LU2", "5"], ["LU4", "2"]]}, {name: "Lled_drv[0].ic.sw", pads: [["LU4", "5"], ["LC21", "2"], ["LL4", "1"]]}, {name: "Lled_drv[0].ic.boot", pads: [["LU4", "6"], ["LC21", "1"]]}, + {name: "Lled_drv[1].pwm", pads: [["LU2", "8"], ["LU5", "2"]]}, {name: "Lled_drv[1].leda", pads: [["LL5", "2"], ["LC27", "1"]]}, {name: "Lled_drv[1].ledk", pads: [["LU5", "1"], ["LR14", "2"]]}, - {name: "Lled_drv[1].pwm", pads: [["LU2", "8"], ["LU5", "2"]]}, {name: "Lled_drv[1].ic.sw", pads: [["LU5", "5"], ["LC25", "2"], ["LL5", "1"]]}, {name: "Lled_drv[1].ic.boot", pads: [["LU5", "6"], ["LC25", "1"]]}, + {name: "Lled_drv[2].pwm", pads: [["LU2", "9"], ["LU6", "2"]]}, {name: "Lled_drv[2].leda", pads: [["LL6", "2"], ["LC31", "1"]]}, {name: "Lled_drv[2].ledk", pads: [["LU6", "1"], ["LR15", "2"]]}, - {name: "Lled_drv[2].pwm", pads: [["LU2", "9"], ["LU6", "2"]]}, {name: "Lled_drv[2].ic.sw", pads: [["LU6", "5"], ["LC29", "2"], ["LL6", "1"]]}, {name: "Lled_drv[2].ic.boot", pads: [["LU6", "6"], ["LC29", "1"]]}, + {name: "Lled_drv[3].pwm", pads: [["LU2", "10"], ["LU7", "2"]]}, {name: "Lled_drv[3].leda", pads: [["LL7", "2"], ["LC35", "1"]]}, {name: "Lled_drv[3].ledk", pads: [["LU7", "1"], ["LR16", "2"]]}, - {name: "Lled_drv[3].pwm", pads: [["LU2", "10"], ["LU7", "2"]]}, {name: "Lled_drv[3].ic.sw", pads: [["LU7", "5"], ["LC33", "2"], ["LL7", "1"]]}, {name: "Lled_drv[3].ic.boot", pads: [["LU7", "6"], ["LC33", "1"]]} ]) diff --git a/examples/IotRollerBlinds/IotRollerBlinds.net.ref b/examples/IotRollerBlinds/IotRollerBlinds.net.ref index 0b4d715d7..a53dc5c36 100644 --- a/examples/IotRollerBlinds/IotRollerBlinds.net.ref +++ b/examples/IotRollerBlinds/IotRollerBlinds.net.ref @@ -184,7 +184,7 @@ (value "reg_3v3.power_path.inductor") (footprint "Inductor_SMD:L_Sunlord_SWPA4030S") (property (name "Sheetname") (value "power_path")) - (property (name "Sheetfile") (value "edg.abstract_parts.PowerConverters.BuckConverterPowerPath")) + (property (name "Sheetfile") (value "edg.circuits.BuckConverterPowerPath.BuckConverterPowerPath")) (property (name "edg_path") (value "reg_3v3.power_path.inductor")) (property (name "edg_short_path") (value "reg_3v3.power_path.inductor")) (property (name "edg_refdes") (value "BL1")) @@ -220,7 +220,7 @@ (value "reg_3v3.power_path.out_cap") (footprint "Capacitor_SMD:C_0805_2012Metric") (property (name "Sheetname") (value "power_path")) - (property (name "Sheetfile") (value "edg.abstract_parts.PowerConverters.BuckConverterPowerPath")) + (property (name "Sheetfile") (value "edg.circuits.BuckConverterPowerPath.BuckConverterPowerPath")) (property (name "edg_path") (value "reg_3v3.power_path.out_cap.cap")) (property (name "edg_short_path") (value "reg_3v3.power_path.out_cap")) (property (name "edg_refdes") (value "BC5")) diff --git a/examples/IotThermalCamera/IotThermalCamera.net.ref b/examples/IotThermalCamera/IotThermalCamera.net.ref index 831a9df31..b6a40f9cb 100644 --- a/examples/IotThermalCamera/IotThermalCamera.net.ref +++ b/examples/IotThermalCamera/IotThermalCamera.net.ref @@ -172,7 +172,7 @@ (value "reg_3v3.power_path.inductor") (footprint "Inductor_SMD:L_Sunlord_SWPA4030S") (property (name "Sheetname") (value "power_path")) - (property (name "Sheetfile") (value "edg.abstract_parts.PowerConverters.BuckConverterPowerPath")) + (property (name "Sheetfile") (value "edg.circuits.BuckConverterPowerPath.BuckConverterPowerPath")) (property (name "edg_path") (value "reg_3v3.power_path.inductor")) (property (name "edg_short_path") (value "reg_3v3.power_path.inductor")) (property (name "edg_refdes") (value "TL1")) @@ -184,7 +184,7 @@ (value "reg_3v3.power_path.in_cap") (footprint "Capacitor_SMD:C_0805_2012Metric") (property (name "Sheetname") (value "power_path")) - (property (name "Sheetfile") (value "edg.abstract_parts.PowerConverters.BuckConverterPowerPath")) + (property (name "Sheetfile") (value "edg.circuits.BuckConverterPowerPath.BuckConverterPowerPath")) (property (name "edg_path") (value "reg_3v3.power_path.in_cap.cap")) (property (name "edg_short_path") (value "reg_3v3.power_path.in_cap")) (property (name "edg_refdes") (value "TC3")) @@ -196,7 +196,7 @@ (value "reg_3v3.power_path.out_cap") (footprint "Capacitor_SMD:C_1206_3216Metric") (property (name "Sheetname") (value "power_path")) - (property (name "Sheetfile") (value "edg.abstract_parts.PowerConverters.BuckConverterPowerPath")) + (property (name "Sheetfile") (value "edg.circuits.BuckConverterPowerPath.BuckConverterPowerPath")) (property (name "edg_path") (value "reg_3v3.power_path.out_cap.cap")) (property (name "edg_short_path") (value "reg_3v3.power_path.out_cap")) (property (name "edg_refdes") (value "TC4")) diff --git a/examples/Multimeter/Multimeter.net.ref b/examples/Multimeter/Multimeter.net.ref index 254826720..7f5d241f9 100644 --- a/examples/Multimeter/Multimeter.net.ref +++ b/examples/Multimeter/Multimeter.net.ref @@ -184,7 +184,7 @@ (value "reg_5v.power_path.inductor") (footprint "Inductor_SMD:L_0603_1608Metric") (property (name "Sheetname") (value "power_path")) - (property (name "Sheetfile") (value "edg.abstract_parts.PowerConverters.BoostConverterPowerPath")) + (property (name "Sheetfile") (value "edg.circuits.BoostConverterPowerPath.BoostConverterPowerPath")) (property (name "edg_path") (value "reg_5v.power_path.inductor")) (property (name "edg_short_path") (value "reg_5v.power_path.inductor")) (property (name "edg_refdes") (value "L1")) @@ -196,7 +196,7 @@ (value "reg_5v.power_path.in_cap") (footprint "Capacitor_SMD:C_0805_2012Metric") (property (name "Sheetname") (value "power_path")) - (property (name "Sheetfile") (value "edg.abstract_parts.PowerConverters.BoostConverterPowerPath")) + (property (name "Sheetfile") (value "edg.circuits.BoostConverterPowerPath.BoostConverterPowerPath")) (property (name "edg_path") (value "reg_5v.power_path.in_cap.cap")) (property (name "edg_short_path") (value "reg_5v.power_path.in_cap")) (property (name "edg_refdes") (value "C1")) @@ -208,7 +208,7 @@ (value "reg_5v.power_path.out_cap") (footprint "Capacitor_SMD:C_0805_2012Metric") (property (name "Sheetname") (value "power_path")) - (property (name "Sheetfile") (value "edg.abstract_parts.PowerConverters.BoostConverterPowerPath")) + (property (name "Sheetfile") (value "edg.circuits.BoostConverterPowerPath.BoostConverterPowerPath")) (property (name "edg_path") (value "reg_5v.power_path.out_cap.cap")) (property (name "edg_short_path") (value "reg_5v.power_path.out_cap")) (property (name "edg_refdes") (value "C2")) @@ -412,7 +412,7 @@ (value "mcu.usb_res.dp") (footprint "Resistor_SMD:R_0603_1608Metric") (property (name "Sheetname") (value "usb_res")) - (property (name "Sheetfile") (value "edg.abstract_parts.Resistor.UsbSeriesResistor")) + (property (name "Sheetfile") (value "edg.circuits.UsbSeriesResistor.UsbSeriesResistor")) (property (name "edg_path") (value "mcu.usb_res.dp.res")) (property (name "edg_short_path") (value "mcu.usb_res.dp")) (property (name "edg_refdes") (value "R6")) @@ -424,7 +424,7 @@ (value "mcu.usb_res.dm") (footprint "Resistor_SMD:R_0603_1608Metric") (property (name "Sheetname") (value "usb_res")) - (property (name "Sheetfile") (value "edg.abstract_parts.Resistor.UsbSeriesResistor")) + (property (name "Sheetfile") (value "edg.circuits.UsbSeriesResistor.UsbSeriesResistor")) (property (name "edg_path") (value "mcu.usb_res.dm.res")) (property (name "edg_short_path") (value "mcu.usb_res.dm")) (property (name "edg_refdes") (value "R7")) diff --git a/examples/PicoProbe/PicoProbe.net.ref b/examples/PicoProbe/PicoProbe.net.ref index 8bc8f8a88..331683e48 100644 --- a/examples/PicoProbe/PicoProbe.net.ref +++ b/examples/PicoProbe/PicoProbe.net.ref @@ -340,7 +340,7 @@ (value "mcu.usb_res.dp") (footprint "Resistor_SMD:R_0603_1608Metric") (property (name "Sheetname") (value "usb_res")) - (property (name "Sheetfile") (value "edg.abstract_parts.Resistor.UsbSeriesResistor")) + (property (name "Sheetfile") (value "edg.circuits.UsbSeriesResistor.UsbSeriesResistor")) (property (name "edg_path") (value "mcu.usb_res.dp.res")) (property (name "edg_short_path") (value "mcu.usb_res.dp")) (property (name "edg_refdes") (value "SR3")) @@ -352,7 +352,7 @@ (value "mcu.usb_res.dm") (footprint "Resistor_SMD:R_0603_1608Metric") (property (name "Sheetname") (value "usb_res")) - (property (name "Sheetfile") (value "edg.abstract_parts.Resistor.UsbSeriesResistor")) + (property (name "Sheetfile") (value "edg.circuits.UsbSeriesResistor.UsbSeriesResistor")) (property (name "edg_path") (value "mcu.usb_res.dm.res")) (property (name "edg_short_path") (value "mcu.usb_res.dm")) (property (name "edg_refdes") (value "SR4")) diff --git a/examples/RobotDriver/RobotDriver.net.ref b/examples/RobotDriver/RobotDriver.net.ref index cb62c35e7..1261da392 100644 --- a/examples/RobotDriver/RobotDriver.net.ref +++ b/examples/RobotDriver/RobotDriver.net.ref @@ -196,7 +196,7 @@ (value "reg_3v3.power_path.inductor") (footprint "Inductor_SMD:L_0603_1608Metric") (property (name "Sheetname") (value "power_path")) - (property (name "Sheetfile") (value "edg.abstract_parts.PowerConverters.BuckConverterPowerPath")) + (property (name "Sheetfile") (value "edg.circuits.BuckConverterPowerPath.BuckConverterPowerPath")) (property (name "edg_path") (value "reg_3v3.power_path.inductor")) (property (name "edg_short_path") (value "reg_3v3.power_path.inductor")) (property (name "edg_refdes") (value "L1")) @@ -208,7 +208,7 @@ (value "reg_3v3.power_path.in_cap") (footprint "Capacitor_SMD:C_0805_2012Metric") (property (name "Sheetname") (value "power_path")) - (property (name "Sheetfile") (value "edg.abstract_parts.PowerConverters.BuckConverterPowerPath")) + (property (name "Sheetfile") (value "edg.circuits.BuckConverterPowerPath.BuckConverterPowerPath")) (property (name "edg_path") (value "reg_3v3.power_path.in_cap.cap")) (property (name "edg_short_path") (value "reg_3v3.power_path.in_cap")) (property (name "edg_refdes") (value "C2")) @@ -220,7 +220,7 @@ (value "reg_3v3.power_path.out_cap") (footprint "Capacitor_SMD:C_0805_2012Metric") (property (name "Sheetname") (value "power_path")) - (property (name "Sheetfile") (value "edg.abstract_parts.PowerConverters.BuckConverterPowerPath")) + (property (name "Sheetfile") (value "edg.circuits.BuckConverterPowerPath.BuckConverterPowerPath")) (property (name "edg_path") (value "reg_3v3.power_path.out_cap.cap")) (property (name "edg_short_path") (value "reg_3v3.power_path.out_cap")) (property (name "edg_refdes") (value "C3")) diff --git a/examples/RobotOwl/RobotOwl.net.ref b/examples/RobotOwl/RobotOwl.net.ref index be9213378..3ae07f94f 100644 --- a/examples/RobotOwl/RobotOwl.net.ref +++ b/examples/RobotOwl/RobotOwl.net.ref @@ -124,7 +124,7 @@ (value "reg_12v.power_path.inductor") (footprint "Inductor_SMD:L_1210_3225Metric") (property (name "Sheetname") (value "power_path")) - (property (name "Sheetfile") (value "edg.abstract_parts.PowerConverters.BoostConverterPowerPath")) + (property (name "Sheetfile") (value "edg.circuits.BoostConverterPowerPath.BoostConverterPowerPath")) (property (name "edg_path") (value "reg_12v.power_path.inductor")) (property (name "edg_short_path") (value "reg_12v.power_path.inductor")) (property (name "edg_refdes") (value "L1")) @@ -136,7 +136,7 @@ (value "reg_12v.power_path.in_cap") (footprint "Capacitor_SMD:C_0805_2012Metric") (property (name "Sheetname") (value "power_path")) - (property (name "Sheetfile") (value "edg.abstract_parts.PowerConverters.BoostConverterPowerPath")) + (property (name "Sheetfile") (value "edg.circuits.BoostConverterPowerPath.BoostConverterPowerPath")) (property (name "edg_path") (value "reg_12v.power_path.in_cap.cap")) (property (name "edg_short_path") (value "reg_12v.power_path.in_cap")) (property (name "edg_refdes") (value "C1")) @@ -148,7 +148,7 @@ (value "reg_12v.power_path.out_cap") (footprint "Capacitor_SMD:C_0805_2012Metric") (property (name "Sheetname") (value "power_path")) - (property (name "Sheetfile") (value "edg.abstract_parts.PowerConverters.BoostConverterPowerPath")) + (property (name "Sheetfile") (value "edg.circuits.BoostConverterPowerPath.BoostConverterPowerPath")) (property (name "edg_path") (value "reg_12v.power_path.out_cap.cap")) (property (name "edg_short_path") (value "reg_12v.power_path.out_cap")) (property (name "edg_refdes") (value "C2")) diff --git a/examples/Simon/Simon.net.ref b/examples/Simon/Simon.net.ref index 02fddad91..ab1d6f630 100644 --- a/examples/Simon/Simon.net.ref +++ b/examples/Simon/Simon.net.ref @@ -304,7 +304,7 @@ (value "pwr.power_path.inductor") (footprint "Inductor_SMD:L_0805_2012Metric") (property (name "Sheetname") (value "power_path")) - (property (name "Sheetfile") (value "edg.abstract_parts.PowerConverters.BoostConverterPowerPath")) + (property (name "Sheetfile") (value "edg.circuits.BoostConverterPowerPath.BoostConverterPowerPath")) (property (name "edg_path") (value "pwr.power_path.inductor")) (property (name "edg_short_path") (value "pwr.power_path.inductor")) (property (name "edg_refdes") (value "L1")) @@ -316,7 +316,7 @@ (value "pwr.power_path.in_cap") (footprint "Capacitor_SMD:C_0603_1608Metric") (property (name "Sheetname") (value "power_path")) - (property (name "Sheetfile") (value "edg.abstract_parts.PowerConverters.BoostConverterPowerPath")) + (property (name "Sheetfile") (value "edg.circuits.BoostConverterPowerPath.BoostConverterPowerPath")) (property (name "edg_path") (value "pwr.power_path.in_cap.cap")) (property (name "edg_short_path") (value "pwr.power_path.in_cap")) (property (name "edg_refdes") (value "C4")) @@ -328,7 +328,7 @@ (value "pwr.power_path.out_cap") (footprint "Capacitor_SMD:C_0603_1608Metric") (property (name "Sheetname") (value "power_path")) - (property (name "Sheetfile") (value "edg.abstract_parts.PowerConverters.BoostConverterPowerPath")) + (property (name "Sheetfile") (value "edg.circuits.BoostConverterPowerPath.BoostConverterPowerPath")) (property (name "edg_path") (value "pwr.power_path.out_cap.cap")) (property (name "edg_short_path") (value "pwr.power_path.out_cap")) (property (name "edg_refdes") (value "C5")) diff --git a/examples/TestBlinkyArray/TestBlinkyArray.net.ref b/examples/TestBlinkyArray/TestBlinkyArray.net.ref index 22b00719b..688045de3 100644 --- a/examples/TestBlinkyArray/TestBlinkyArray.net.ref +++ b/examples/TestBlinkyArray/TestBlinkyArray.net.ref @@ -100,7 +100,7 @@ (value "reg.power_path.inductor") (footprint "Inductor_SMD:L_0805_2012Metric") (property (name "Sheetname") (value "power_path")) - (property (name "Sheetfile") (value "edg.abstract_parts.PowerConverters.BuckConverterPowerPath")) + (property (name "Sheetfile") (value "edg.circuits.BuckConverterPowerPath.BuckConverterPowerPath")) (property (name "edg_path") (value "reg.power_path.inductor")) (property (name "edg_short_path") (value "reg.power_path.inductor")) (property (name "edg_refdes") (value "L1")) @@ -112,7 +112,7 @@ (value "reg.power_path.in_cap") (footprint "Capacitor_SMD:C_0805_2012Metric") (property (name "Sheetname") (value "power_path")) - (property (name "Sheetfile") (value "edg.abstract_parts.PowerConverters.BuckConverterPowerPath")) + (property (name "Sheetfile") (value "edg.circuits.BuckConverterPowerPath.BuckConverterPowerPath")) (property (name "edg_path") (value "reg.power_path.in_cap.cap")) (property (name "edg_short_path") (value "reg.power_path.in_cap")) (property (name "edg_refdes") (value "C3")) @@ -124,7 +124,7 @@ (value "reg.power_path.out_cap") (footprint "Capacitor_SMD:C_0805_2012Metric") (property (name "Sheetname") (value "power_path")) - (property (name "Sheetfile") (value "edg.abstract_parts.PowerConverters.BuckConverterPowerPath")) + (property (name "Sheetfile") (value "edg.circuits.BuckConverterPowerPath.BuckConverterPowerPath")) (property (name "edg_path") (value "reg.power_path.out_cap.cap")) (property (name "edg_short_path") (value "reg.power_path.out_cap")) (property (name "edg_refdes") (value "C4")) diff --git a/examples/TestBlinkyChain/TestBlinkyChain.net.ref b/examples/TestBlinkyChain/TestBlinkyChain.net.ref index 0de99af0e..4bb9ecab6 100644 --- a/examples/TestBlinkyChain/TestBlinkyChain.net.ref +++ b/examples/TestBlinkyChain/TestBlinkyChain.net.ref @@ -100,7 +100,7 @@ (value "reg.power_path.inductor") (footprint "Inductor_SMD:L_0603_1608Metric") (property (name "Sheetname") (value "power_path")) - (property (name "Sheetfile") (value "edg.abstract_parts.PowerConverters.BuckConverterPowerPath")) + (property (name "Sheetfile") (value "edg.circuits.BuckConverterPowerPath.BuckConverterPowerPath")) (property (name "edg_path") (value "reg.power_path.inductor")) (property (name "edg_short_path") (value "reg.power_path.inductor")) (property (name "edg_refdes") (value "L1")) @@ -112,7 +112,7 @@ (value "reg.power_path.in_cap") (footprint "Capacitor_SMD:C_0603_1608Metric") (property (name "Sheetname") (value "power_path")) - (property (name "Sheetfile") (value "edg.abstract_parts.PowerConverters.BuckConverterPowerPath")) + (property (name "Sheetfile") (value "edg.circuits.BuckConverterPowerPath.BuckConverterPowerPath")) (property (name "edg_path") (value "reg.power_path.in_cap.cap")) (property (name "edg_short_path") (value "reg.power_path.in_cap")) (property (name "edg_refdes") (value "C3")) @@ -124,7 +124,7 @@ (value "reg.power_path.out_cap") (footprint "Capacitor_SMD:C_0805_2012Metric") (property (name "Sheetname") (value "power_path")) - (property (name "Sheetfile") (value "edg.abstract_parts.PowerConverters.BuckConverterPowerPath")) + (property (name "Sheetfile") (value "edg.circuits.BuckConverterPowerPath.BuckConverterPowerPath")) (property (name "edg_path") (value "reg.power_path.out_cap.cap")) (property (name "edg_short_path") (value "reg.power_path.out_cap")) (property (name "edg_refdes") (value "C4")) diff --git a/examples/TestBlinkyComplete/TestBlinkyComplete.net.ref b/examples/TestBlinkyComplete/TestBlinkyComplete.net.ref index 64df03e16..aa8091a27 100644 --- a/examples/TestBlinkyComplete/TestBlinkyComplete.net.ref +++ b/examples/TestBlinkyComplete/TestBlinkyComplete.net.ref @@ -100,7 +100,7 @@ (value "reg.power_path.inductor") (footprint "Inductor_SMD:L_0603_1608Metric") (property (name "Sheetname") (value "power_path")) - (property (name "Sheetfile") (value "edg.abstract_parts.PowerConverters.BuckConverterPowerPath")) + (property (name "Sheetfile") (value "edg.circuits.BuckConverterPowerPath.BuckConverterPowerPath")) (property (name "edg_path") (value "reg.power_path.inductor")) (property (name "edg_short_path") (value "reg.power_path.inductor")) (property (name "edg_refdes") (value "L1")) @@ -112,7 +112,7 @@ (value "reg.power_path.in_cap") (footprint "Capacitor_SMD:C_0603_1608Metric") (property (name "Sheetname") (value "power_path")) - (property (name "Sheetfile") (value "edg.abstract_parts.PowerConverters.BuckConverterPowerPath")) + (property (name "Sheetfile") (value "edg.circuits.BuckConverterPowerPath.BuckConverterPowerPath")) (property (name "edg_path") (value "reg.power_path.in_cap.cap")) (property (name "edg_short_path") (value "reg.power_path.in_cap")) (property (name "edg_refdes") (value "C3")) @@ -124,7 +124,7 @@ (value "reg.power_path.out_cap") (footprint "Capacitor_SMD:C_0805_2012Metric") (property (name "Sheetname") (value "power_path")) - (property (name "Sheetfile") (value "edg.abstract_parts.PowerConverters.BuckConverterPowerPath")) + (property (name "Sheetfile") (value "edg.circuits.BuckConverterPowerPath.BuckConverterPowerPath")) (property (name "edg_path") (value "reg.power_path.out_cap.cap")) (property (name "edg_short_path") (value "reg.power_path.out_cap")) (property (name "edg_refdes") (value "C4")) diff --git a/examples/TestBlinkyExpanded/TestBlinkyExpanded.net.ref b/examples/TestBlinkyExpanded/TestBlinkyExpanded.net.ref index 0de99af0e..4bb9ecab6 100644 --- a/examples/TestBlinkyExpanded/TestBlinkyExpanded.net.ref +++ b/examples/TestBlinkyExpanded/TestBlinkyExpanded.net.ref @@ -100,7 +100,7 @@ (value "reg.power_path.inductor") (footprint "Inductor_SMD:L_0603_1608Metric") (property (name "Sheetname") (value "power_path")) - (property (name "Sheetfile") (value "edg.abstract_parts.PowerConverters.BuckConverterPowerPath")) + (property (name "Sheetfile") (value "edg.circuits.BuckConverterPowerPath.BuckConverterPowerPath")) (property (name "edg_path") (value "reg.power_path.inductor")) (property (name "edg_short_path") (value "reg.power_path.inductor")) (property (name "edg_refdes") (value "L1")) @@ -112,7 +112,7 @@ (value "reg.power_path.in_cap") (footprint "Capacitor_SMD:C_0603_1608Metric") (property (name "Sheetname") (value "power_path")) - (property (name "Sheetfile") (value "edg.abstract_parts.PowerConverters.BuckConverterPowerPath")) + (property (name "Sheetfile") (value "edg.circuits.BuckConverterPowerPath.BuckConverterPowerPath")) (property (name "edg_path") (value "reg.power_path.in_cap.cap")) (property (name "edg_short_path") (value "reg.power_path.in_cap")) (property (name "edg_refdes") (value "C3")) @@ -124,7 +124,7 @@ (value "reg.power_path.out_cap") (footprint "Capacitor_SMD:C_0805_2012Metric") (property (name "Sheetname") (value "power_path")) - (property (name "Sheetfile") (value "edg.abstract_parts.PowerConverters.BuckConverterPowerPath")) + (property (name "Sheetfile") (value "edg.circuits.BuckConverterPowerPath.BuckConverterPowerPath")) (property (name "edg_path") (value "reg.power_path.out_cap.cap")) (property (name "edg_short_path") (value "reg.power_path.out_cap")) (property (name "edg_refdes") (value "C4")) diff --git a/examples/TestBlinkyImplicit/TestBlinkyImplicit.net.ref b/examples/TestBlinkyImplicit/TestBlinkyImplicit.net.ref index 0de99af0e..4bb9ecab6 100644 --- a/examples/TestBlinkyImplicit/TestBlinkyImplicit.net.ref +++ b/examples/TestBlinkyImplicit/TestBlinkyImplicit.net.ref @@ -100,7 +100,7 @@ (value "reg.power_path.inductor") (footprint "Inductor_SMD:L_0603_1608Metric") (property (name "Sheetname") (value "power_path")) - (property (name "Sheetfile") (value "edg.abstract_parts.PowerConverters.BuckConverterPowerPath")) + (property (name "Sheetfile") (value "edg.circuits.BuckConverterPowerPath.BuckConverterPowerPath")) (property (name "edg_path") (value "reg.power_path.inductor")) (property (name "edg_short_path") (value "reg.power_path.inductor")) (property (name "edg_refdes") (value "L1")) @@ -112,7 +112,7 @@ (value "reg.power_path.in_cap") (footprint "Capacitor_SMD:C_0603_1608Metric") (property (name "Sheetname") (value "power_path")) - (property (name "Sheetfile") (value "edg.abstract_parts.PowerConverters.BuckConverterPowerPath")) + (property (name "Sheetfile") (value "edg.circuits.BuckConverterPowerPath.BuckConverterPowerPath")) (property (name "edg_path") (value "reg.power_path.in_cap.cap")) (property (name "edg_short_path") (value "reg.power_path.in_cap")) (property (name "edg_refdes") (value "C3")) @@ -124,7 +124,7 @@ (value "reg.power_path.out_cap") (footprint "Capacitor_SMD:C_0805_2012Metric") (property (name "Sheetname") (value "power_path")) - (property (name "Sheetfile") (value "edg.abstract_parts.PowerConverters.BuckConverterPowerPath")) + (property (name "Sheetfile") (value "edg.circuits.BuckConverterPowerPath.BuckConverterPowerPath")) (property (name "edg_path") (value "reg.power_path.out_cap.cap")) (property (name "edg_short_path") (value "reg.power_path.out_cap")) (property (name "edg_refdes") (value "C4")) diff --git a/examples/TestBlinkyMicro/TestBlinkyMicro.net.ref b/examples/TestBlinkyMicro/TestBlinkyMicro.net.ref index c18fd48fe..836d2403d 100644 --- a/examples/TestBlinkyMicro/TestBlinkyMicro.net.ref +++ b/examples/TestBlinkyMicro/TestBlinkyMicro.net.ref @@ -100,7 +100,7 @@ (value "reg.power_path.inductor") (footprint "Inductor_SMD:L_0805_2012Metric") (property (name "Sheetname") (value "power_path")) - (property (name "Sheetfile") (value "edg.abstract_parts.PowerConverters.BuckConverterPowerPath")) + (property (name "Sheetfile") (value "edg.circuits.BuckConverterPowerPath.BuckConverterPowerPath")) (property (name "edg_path") (value "reg.power_path.inductor")) (property (name "edg_short_path") (value "reg.power_path.inductor")) (property (name "edg_refdes") (value "L1")) @@ -112,7 +112,7 @@ (value "reg.power_path.in_cap") (footprint "Capacitor_SMD:C_0805_2012Metric") (property (name "Sheetname") (value "power_path")) - (property (name "Sheetfile") (value "edg.abstract_parts.PowerConverters.BuckConverterPowerPath")) + (property (name "Sheetfile") (value "edg.circuits.BuckConverterPowerPath.BuckConverterPowerPath")) (property (name "edg_path") (value "reg.power_path.in_cap.cap")) (property (name "edg_short_path") (value "reg.power_path.in_cap")) (property (name "edg_refdes") (value "C3")) @@ -124,7 +124,7 @@ (value "reg.power_path.out_cap") (footprint "Capacitor_SMD:C_0805_2012Metric") (property (name "Sheetname") (value "power_path")) - (property (name "Sheetfile") (value "edg.abstract_parts.PowerConverters.BuckConverterPowerPath")) + (property (name "Sheetfile") (value "edg.circuits.BuckConverterPowerPath.BuckConverterPowerPath")) (property (name "edg_path") (value "reg.power_path.out_cap.cap")) (property (name "edg_short_path") (value "reg.power_path.out_cap")) (property (name "edg_refdes") (value "C4")) diff --git a/examples/TestBlinkyPacked/TestBlinkyPacked.net.ref b/examples/TestBlinkyPacked/TestBlinkyPacked.net.ref index 38a660b5d..62645f9b9 100644 --- a/examples/TestBlinkyPacked/TestBlinkyPacked.net.ref +++ b/examples/TestBlinkyPacked/TestBlinkyPacked.net.ref @@ -100,7 +100,7 @@ (value "reg.power_path.inductor") (footprint "Inductor_SMD:L_0805_2012Metric") (property (name "Sheetname") (value "power_path")) - (property (name "Sheetfile") (value "edg.abstract_parts.PowerConverters.BuckConverterPowerPath")) + (property (name "Sheetfile") (value "edg.circuits.BuckConverterPowerPath.BuckConverterPowerPath")) (property (name "edg_path") (value "reg.power_path.inductor")) (property (name "edg_short_path") (value "reg.power_path.inductor")) (property (name "edg_refdes") (value "L1")) @@ -112,7 +112,7 @@ (value "reg.power_path.in_cap") (footprint "Capacitor_SMD:C_0805_2012Metric") (property (name "Sheetname") (value "power_path")) - (property (name "Sheetfile") (value "edg.abstract_parts.PowerConverters.BuckConverterPowerPath")) + (property (name "Sheetfile") (value "edg.circuits.BuckConverterPowerPath.BuckConverterPowerPath")) (property (name "edg_path") (value "reg.power_path.in_cap.cap")) (property (name "edg_short_path") (value "reg.power_path.in_cap")) (property (name "edg_refdes") (value "C3")) @@ -124,7 +124,7 @@ (value "reg.power_path.out_cap") (footprint "Capacitor_SMD:C_0805_2012Metric") (property (name "Sheetname") (value "power_path")) - (property (name "Sheetfile") (value "edg.abstract_parts.PowerConverters.BuckConverterPowerPath")) + (property (name "Sheetfile") (value "edg.circuits.BuckConverterPowerPath.BuckConverterPowerPath")) (property (name "edg_path") (value "reg.power_path.out_cap.cap")) (property (name "edg_short_path") (value "reg.power_path.out_cap")) (property (name "edg_refdes") (value "C4")) diff --git a/examples/TestBlinkyWithLibrary/TestBlinkyWithLibrary.net.ref b/examples/TestBlinkyWithLibrary/TestBlinkyWithLibrary.net.ref index dd9379da6..42e1019ae 100644 --- a/examples/TestBlinkyWithLibrary/TestBlinkyWithLibrary.net.ref +++ b/examples/TestBlinkyWithLibrary/TestBlinkyWithLibrary.net.ref @@ -100,7 +100,7 @@ (value "reg.power_path.inductor") (footprint "Inductor_SMD:L_0805_2012Metric") (property (name "Sheetname") (value "power_path")) - (property (name "Sheetfile") (value "edg.abstract_parts.PowerConverters.BuckConverterPowerPath")) + (property (name "Sheetfile") (value "edg.circuits.BuckConverterPowerPath.BuckConverterPowerPath")) (property (name "edg_path") (value "reg.power_path.inductor")) (property (name "edg_short_path") (value "reg.power_path.inductor")) (property (name "edg_refdes") (value "L1")) @@ -112,7 +112,7 @@ (value "reg.power_path.in_cap") (footprint "Capacitor_SMD:C_0805_2012Metric") (property (name "Sheetname") (value "power_path")) - (property (name "Sheetfile") (value "edg.abstract_parts.PowerConverters.BuckConverterPowerPath")) + (property (name "Sheetfile") (value "edg.circuits.BuckConverterPowerPath.BuckConverterPowerPath")) (property (name "edg_path") (value "reg.power_path.in_cap.cap")) (property (name "edg_short_path") (value "reg.power_path.in_cap")) (property (name "edg_refdes") (value "C3")) @@ -124,7 +124,7 @@ (value "reg.power_path.out_cap") (footprint "Capacitor_SMD:C_0805_2012Metric") (property (name "Sheetname") (value "power_path")) - (property (name "Sheetfile") (value "edg.abstract_parts.PowerConverters.BuckConverterPowerPath")) + (property (name "Sheetfile") (value "edg.circuits.BuckConverterPowerPath.BuckConverterPowerPath")) (property (name "edg_path") (value "reg.power_path.out_cap.cap")) (property (name "edg_short_path") (value "reg.power_path.out_cap")) (property (name "edg_refdes") (value "C4")) diff --git a/examples/TestBlinkyWithLibraryExport/TestBlinkyWithLibraryExport.net.ref b/examples/TestBlinkyWithLibraryExport/TestBlinkyWithLibraryExport.net.ref index 9f65813fa..6e9d9329e 100644 --- a/examples/TestBlinkyWithLibraryExport/TestBlinkyWithLibraryExport.net.ref +++ b/examples/TestBlinkyWithLibraryExport/TestBlinkyWithLibraryExport.net.ref @@ -100,7 +100,7 @@ (value "reg.power_path.inductor") (footprint "Inductor_SMD:L_0805_2012Metric") (property (name "Sheetname") (value "power_path")) - (property (name "Sheetfile") (value "edg.abstract_parts.PowerConverters.BuckConverterPowerPath")) + (property (name "Sheetfile") (value "edg.circuits.BuckConverterPowerPath.BuckConverterPowerPath")) (property (name "edg_path") (value "reg.power_path.inductor")) (property (name "edg_short_path") (value "reg.power_path.inductor")) (property (name "edg_refdes") (value "L1")) @@ -112,7 +112,7 @@ (value "reg.power_path.in_cap") (footprint "Capacitor_SMD:C_0805_2012Metric") (property (name "Sheetname") (value "power_path")) - (property (name "Sheetfile") (value "edg.abstract_parts.PowerConverters.BuckConverterPowerPath")) + (property (name "Sheetfile") (value "edg.circuits.BuckConverterPowerPath.BuckConverterPowerPath")) (property (name "edg_path") (value "reg.power_path.in_cap.cap")) (property (name "edg_short_path") (value "reg.power_path.in_cap")) (property (name "edg_refdes") (value "C3")) @@ -124,7 +124,7 @@ (value "reg.power_path.out_cap") (footprint "Capacitor_SMD:C_0805_2012Metric") (property (name "Sheetname") (value "power_path")) - (property (name "Sheetfile") (value "edg.abstract_parts.PowerConverters.BuckConverterPowerPath")) + (property (name "Sheetfile") (value "edg.circuits.BuckConverterPowerPath.BuckConverterPowerPath")) (property (name "edg_path") (value "reg.power_path.out_cap.cap")) (property (name "edg_short_path") (value "reg.power_path.out_cap")) (property (name "edg_refdes") (value "C4")) diff --git a/examples/TestBlinkyWithModeledSchematicImport/TestBlinkyWithModeledSchematicImport.net.ref b/examples/TestBlinkyWithModeledSchematicImport/TestBlinkyWithModeledSchematicImport.net.ref index b718daeb7..fa1238e85 100644 --- a/examples/TestBlinkyWithModeledSchematicImport/TestBlinkyWithModeledSchematicImport.net.ref +++ b/examples/TestBlinkyWithModeledSchematicImport/TestBlinkyWithModeledSchematicImport.net.ref @@ -100,7 +100,7 @@ (value "reg.power_path.inductor") (footprint "Inductor_SMD:L_0805_2012Metric") (property (name "Sheetname") (value "power_path")) - (property (name "Sheetfile") (value "edg.abstract_parts.PowerConverters.BuckConverterPowerPath")) + (property (name "Sheetfile") (value "edg.circuits.BuckConverterPowerPath.BuckConverterPowerPath")) (property (name "edg_path") (value "reg.power_path.inductor")) (property (name "edg_short_path") (value "reg.power_path.inductor")) (property (name "edg_refdes") (value "L1")) @@ -112,7 +112,7 @@ (value "reg.power_path.in_cap") (footprint "Capacitor_SMD:C_0805_2012Metric") (property (name "Sheetname") (value "power_path")) - (property (name "Sheetfile") (value "edg.abstract_parts.PowerConverters.BuckConverterPowerPath")) + (property (name "Sheetfile") (value "edg.circuits.BuckConverterPowerPath.BuckConverterPowerPath")) (property (name "edg_path") (value "reg.power_path.in_cap.cap")) (property (name "edg_short_path") (value "reg.power_path.in_cap")) (property (name "edg_refdes") (value "C3")) @@ -124,7 +124,7 @@ (value "reg.power_path.out_cap") (footprint "Capacitor_SMD:C_0805_2012Metric") (property (name "Sheetname") (value "power_path")) - (property (name "Sheetfile") (value "edg.abstract_parts.PowerConverters.BuckConverterPowerPath")) + (property (name "Sheetfile") (value "edg.circuits.BuckConverterPowerPath.BuckConverterPowerPath")) (property (name "edg_path") (value "reg.power_path.out_cap.cap")) (property (name "edg_short_path") (value "reg.power_path.out_cap")) (property (name "edg_refdes") (value "C4")) diff --git a/examples/TestBlinkyWithSchematicImport/TestBlinkyWithSchematicImport.net.ref b/examples/TestBlinkyWithSchematicImport/TestBlinkyWithSchematicImport.net.ref index 833917a16..893180881 100644 --- a/examples/TestBlinkyWithSchematicImport/TestBlinkyWithSchematicImport.net.ref +++ b/examples/TestBlinkyWithSchematicImport/TestBlinkyWithSchematicImport.net.ref @@ -100,7 +100,7 @@ (value "reg.power_path.inductor") (footprint "Inductor_SMD:L_0805_2012Metric") (property (name "Sheetname") (value "power_path")) - (property (name "Sheetfile") (value "edg.abstract_parts.PowerConverters.BuckConverterPowerPath")) + (property (name "Sheetfile") (value "edg.circuits.BuckConverterPowerPath.BuckConverterPowerPath")) (property (name "edg_path") (value "reg.power_path.inductor")) (property (name "edg_short_path") (value "reg.power_path.inductor")) (property (name "edg_refdes") (value "L1")) @@ -112,7 +112,7 @@ (value "reg.power_path.in_cap") (footprint "Capacitor_SMD:C_0805_2012Metric") (property (name "Sheetname") (value "power_path")) - (property (name "Sheetfile") (value "edg.abstract_parts.PowerConverters.BuckConverterPowerPath")) + (property (name "Sheetfile") (value "edg.circuits.BuckConverterPowerPath.BuckConverterPowerPath")) (property (name "edg_path") (value "reg.power_path.in_cap.cap")) (property (name "edg_short_path") (value "reg.power_path.in_cap")) (property (name "edg_refdes") (value "C3")) @@ -124,7 +124,7 @@ (value "reg.power_path.out_cap") (footprint "Capacitor_SMD:C_0805_2012Metric") (property (name "Sheetname") (value "power_path")) - (property (name "Sheetfile") (value "edg.abstract_parts.PowerConverters.BuckConverterPowerPath")) + (property (name "Sheetfile") (value "edg.circuits.BuckConverterPowerPath.BuckConverterPowerPath")) (property (name "edg_path") (value "reg.power_path.out_cap.cap")) (property (name "edg_short_path") (value "reg.power_path.out_cap")) (property (name "edg_refdes") (value "C4")) diff --git a/examples/UsbSourceMeasure/UsbSourceMeasure.net.ref b/examples/UsbSourceMeasure/UsbSourceMeasure.net.ref index dab4eecbe..3ca677891 100644 --- a/examples/UsbSourceMeasure/UsbSourceMeasure.net.ref +++ b/examples/UsbSourceMeasure/UsbSourceMeasure.net.ref @@ -292,7 +292,7 @@ (value "reg_v5.power_path.inductor") (footprint "Inductor_SMD:L_Sunlord_SWPA5040S") (property (name "Sheetname") (value "power_path")) - (property (name "Sheetfile") (value "edg.abstract_parts.PowerConverters.BuckConverterPowerPath")) + (property (name "Sheetfile") (value "edg.circuits.BuckConverterPowerPath.BuckConverterPowerPath")) (property (name "edg_path") (value "reg_v5.power_path.inductor")) (property (name "edg_short_path") (value "reg_v5.power_path.inductor")) (property (name "edg_refdes") (value "L1")) @@ -304,7 +304,7 @@ (value "reg_v5.power_path.in_cap") (footprint "Capacitor_SMD:C_0805_2012Metric") (property (name "Sheetname") (value "power_path")) - (property (name "Sheetfile") (value "edg.abstract_parts.PowerConverters.BuckConverterPowerPath")) + (property (name "Sheetfile") (value "edg.circuits.BuckConverterPowerPath.BuckConverterPowerPath")) (property (name "edg_path") (value "reg_v5.power_path.in_cap.cap")) (property (name "edg_short_path") (value "reg_v5.power_path.in_cap")) (property (name "edg_refdes") (value "C7")) @@ -316,7 +316,7 @@ (value "reg_v5.power_path.out_cap") (footprint "Capacitor_SMD:C_1206_3216Metric") (property (name "Sheetname") (value "power_path")) - (property (name "Sheetfile") (value "edg.abstract_parts.PowerConverters.BuckConverterPowerPath")) + (property (name "Sheetfile") (value "edg.circuits.BuckConverterPowerPath.BuckConverterPowerPath")) (property (name "edg_path") (value "reg_v5.power_path.out_cap.cap")) (property (name "edg_short_path") (value "reg_v5.power_path.out_cap")) (property (name "edg_refdes") (value "C8")) @@ -412,7 +412,7 @@ (value "reg_3v3.power_path.inductor") (footprint "Inductor_SMD:L_Sunlord_SWPA5040S") (property (name "Sheetname") (value "power_path")) - (property (name "Sheetfile") (value "edg.abstract_parts.PowerConverters.BuckConverterPowerPath")) + (property (name "Sheetfile") (value "edg.circuits.BuckConverterPowerPath.BuckConverterPowerPath")) (property (name "edg_path") (value "reg_3v3.power_path.inductor")) (property (name "edg_short_path") (value "reg_3v3.power_path.inductor")) (property (name "edg_refdes") (value "L2")) @@ -448,7 +448,7 @@ (value "reg_3v3.power_path.out_cap") (footprint "Capacitor_SMD:C_0805_2012Metric") (property (name "Sheetname") (value "power_path")) - (property (name "Sheetfile") (value "edg.abstract_parts.PowerConverters.BuckConverterPowerPath")) + (property (name "Sheetfile") (value "edg.circuits.BuckConverterPowerPath.BuckConverterPowerPath")) (property (name "edg_path") (value "reg_3v3.power_path.out_cap.cap")) (property (name "edg_short_path") (value "reg_3v3.power_path.out_cap")) (property (name "edg_refdes") (value "C13")) @@ -532,7 +532,7 @@ (value "reg_v12.power_path.inductor") (footprint "Inductor_SMD:L_0805_2012Metric") (property (name "Sheetname") (value "power_path")) - (property (name "Sheetfile") (value "edg.abstract_parts.PowerConverters.BoostConverterPowerPath")) + (property (name "Sheetfile") (value "edg.circuits.BoostConverterPowerPath.BoostConverterPowerPath")) (property (name "edg_path") (value "reg_v12.power_path.inductor")) (property (name "edg_short_path") (value "reg_v12.power_path.inductor")) (property (name "edg_refdes") (value "L3")) @@ -544,7 +544,7 @@ (value "reg_v12.power_path.in_cap") (footprint "Capacitor_SMD:C_0805_2012Metric") (property (name "Sheetname") (value "power_path")) - (property (name "Sheetfile") (value "edg.abstract_parts.PowerConverters.BoostConverterPowerPath")) + (property (name "Sheetfile") (value "edg.circuits.BoostConverterPowerPath.BoostConverterPowerPath")) (property (name "edg_path") (value "reg_v12.power_path.in_cap.cap")) (property (name "edg_short_path") (value "reg_v12.power_path.in_cap")) (property (name "edg_refdes") (value "C14")) @@ -556,7 +556,7 @@ (value "reg_v12.power_path.out_cap") (footprint "Capacitor_SMD:C_0603_1608Metric") (property (name "Sheetname") (value "power_path")) - (property (name "Sheetfile") (value "edg.abstract_parts.PowerConverters.BoostConverterPowerPath")) + (property (name "Sheetfile") (value "edg.circuits.BoostConverterPowerPath.BoostConverterPowerPath")) (property (name "edg_path") (value "reg_v12.power_path.out_cap.cap")) (property (name "edg_short_path") (value "reg_v12.power_path.out_cap")) (property (name "edg_refdes") (value "C15")) @@ -628,7 +628,7 @@ (value "conv.power_path.inductor") (footprint "Inductor_SMD:L_Bourns_SRP1245A") (property (name "Sheetname") (value "power_path")) - (property (name "Sheetfile") (value "edg.abstract_parts.PowerConverters.BuckBoostConverterPowerPath")) + (property (name "Sheetfile") (value "edg.circuits.BuckBoostConverterPowerPath.BuckBoostConverterPowerPath")) (property (name "edg_path") (value "conv.power_path.inductor")) (property (name "edg_short_path") (value "conv.power_path.inductor")) (property (name "edg_refdes") (value "L4")) @@ -1204,7 +1204,7 @@ (value "reg_vcontrol.power_path.inductor") (footprint "Inductor_SMD:L_0805_2012Metric") (property (name "Sheetname") (value "power_path")) - (property (name "Sheetfile") (value "edg.abstract_parts.PowerConverters.BoostConverterPowerPath")) + (property (name "Sheetfile") (value "edg.circuits.BoostConverterPowerPath.BoostConverterPowerPath")) (property (name "edg_path") (value "reg_vcontrol.power_path.inductor")) (property (name "edg_short_path") (value "reg_vcontrol.power_path.inductor")) (property (name "edg_refdes") (value "L5")) @@ -1216,7 +1216,7 @@ (value "reg_vcontrol.power_path.in_cap") (footprint "Capacitor_SMD:C_0603_1608Metric") (property (name "Sheetname") (value "power_path")) - (property (name "Sheetfile") (value "edg.abstract_parts.PowerConverters.BoostConverterPowerPath")) + (property (name "Sheetfile") (value "edg.circuits.BoostConverterPowerPath.BoostConverterPowerPath")) (property (name "edg_path") (value "reg_vcontrol.power_path.in_cap.cap")) (property (name "edg_short_path") (value "reg_vcontrol.power_path.in_cap")) (property (name "edg_refdes") (value "C41")) @@ -1228,7 +1228,7 @@ (value "reg_vcontrol.power_path.out_cap") (footprint "Capacitor_SMD:C_0805_2012Metric") (property (name "Sheetname") (value "power_path")) - (property (name "Sheetfile") (value "edg.abstract_parts.PowerConverters.BoostConverterPowerPath")) + (property (name "Sheetfile") (value "edg.circuits.BoostConverterPowerPath.BoostConverterPowerPath")) (property (name "edg_path") (value "reg_vcontrol.power_path.out_cap.cap")) (property (name "edg_short_path") (value "reg_vcontrol.power_path.out_cap")) (property (name "edg_refdes") (value "C42")) diff --git a/examples/test_iot_led_driver.py b/examples/test_iot_led_driver.py index e48fd2072..ee0a76a23 100644 --- a/examples/test_iot_led_driver.py +++ b/examples/test_iot_led_driver.py @@ -85,15 +85,15 @@ def contents(self) -> None: self.connect(self.mcu.i2c.request("tof"), self.tof_pull.i2c, self.tof.i2c) # 12V DOMAIN - self.led_drv = ElementDict[LedDriver]() + self.led_drv = ElementDict[Tps92200]() self.led_sink = ElementDict[DummyPassive]() with self.implicit_connect( ImplicitConnect(self.v12, [Power]), ImplicitConnect(self.gnd, [Common]), ) as imp: for i in range(4): - led_drv = self.led_drv[i] = imp.Block(LedDriver(max_current=750 * mAmp(tol=0.1))) - self.connect(self.mcu.gpio.request(f"led_pwm_{i}"), led_drv.with_mixin(LedDriverPwm()).pwm) + led_drv = self.led_drv[i] = imp.Block(Tps92200(max_current=750 * mAmp(tol=0.1))) + self.connect(self.mcu.gpio.request(f"led_pwm_{i}"), led_drv.pwm) # no connectors to save space, just solder to one of the SMD pads leda_sink = self.led_sink[i * 2] = imp.Block(DummyPassive()) @@ -203,7 +203,6 @@ def refinements(self) -> Refinements: (EspProgrammingHeader, EspProgrammingTc2030), (PowerBarrelJack, Pj_036ah), (Neopixel, Sk6805_Ec15), - (LedDriver, Tps92200), (RfConnector, UflConnector), (TestPoint, CompactKeystone5015), (TagConnect, TagConnectNonLegged),