Skip to content

Commit 23ea64f

Browse files
committed
lots of fixes
1 parent cb84066 commit 23ea64f

File tree

7 files changed

+1189
-1183
lines changed

7 files changed

+1189
-1183
lines changed

edg/abstract_parts/AbstractPowerConverters.py

Lines changed: 40 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -204,6 +204,25 @@ class BuckConverterPowerPath(InternalSubcircuit, GeneratorBlock):
204204
Very detailed analysis including component sizing, operating modes, calculating losses
205205
"""
206206

207+
@staticmethod
208+
def _d_inverse_d(d_range: Range) -> Range:
209+
"""Some power calculations require the maximum of D*(1-D), which has a maximum at D=0.5"""
210+
# can't use range ops since they will double-count the tolerance of D, so calculate endpoints separately
211+
range_endpoints = [d_range.lower * (1 - d_range.lower), d_range.upper * (1 - d_range.upper)]
212+
raw_range = Range(min(range_endpoints), max(range_endpoints))
213+
if 0.5 in d_range: # the function has a maximum at 0.5
214+
return raw_range.hull(Range.exact(0.5 * (1 - 0.5)))
215+
else:
216+
return raw_range
217+
218+
@staticmethod
219+
def _ripple_current_from_sw_current(sw_current: float, ripple_ratio: Range) -> Range:
220+
"""Calculates the ripple current from a total switch current and ripple ratio."""
221+
return Range( # separate range parts to avoid double-counting tolerances
222+
sw_current / (1 + ripple_ratio.lower) * ripple_ratio.lower,
223+
sw_current / (1 + ripple_ratio.upper) * ripple_ratio.upper
224+
)
225+
207226
class Values(NamedTuple):
208227
dutycycle: Range
209228
inductance: Range
@@ -259,10 +278,9 @@ def _calculate_parameters(cls, input_voltage: Range, output_voltage: Range, freq
259278
inductance = Range.all()
260279
min_ripple = 0.0
261280
if sw_current_limits.upper > 0: # fallback for light-load
262-
# since limits are defined in terms of the switch current which should have ripple factored in already,
263-
# assume a safe-ish 0.25 ripple ratio was specified and unapply that before applying the limit ratio
264-
inductance = inductance.intersect(inductance_scale / (sw_current_limits.upper / 1.25 * limit_ripple_ratio))
265-
min_ripple = sw_current_limits.upper / 1.25 * limit_ripple_ratio.lower
281+
ripple_current = cls._ripple_current_from_sw_current(sw_current_limits.upper, limit_ripple_ratio)
282+
inductance = inductance.intersect(inductance_scale / ripple_current)
283+
min_ripple = ripple_current.lower
266284
if ripple_ratio.upper < float('inf'):
267285
assert ripple_ratio.lower > 0, f"invalid non-inf ripple ratio {ripple_ratio}"
268286

@@ -283,28 +301,19 @@ def _calculate_parameters(cls, input_voltage: Range, output_voltage: Range, freq
283301

284302
return cls.Values(dutycycle=dutycycle, inductance=inductance,
285303
input_capacitance=input_capacitance, output_capacitance=output_capacitance,
286-
inductor_avg_current=output_current, ripple_scale=inductance_scale, min_ripple=min_ripple,
304+
inductor_avg_current=output_current / efficiency,
305+
ripple_scale=inductance_scale, min_ripple=min_ripple,
287306
output_capacitance_scale=output_capacitance_scale,
288307
inductor_peak_currents=inductor_peak_currents,
289308
effective_dutycycle=effective_dutycycle)
290309

291-
@staticmethod
292-
def _d_inverse_d(d_range: Range) -> Range:
293-
"""Some power calculations require the maximum of D*(1-D), which has a maximum at D=0.5"""
294-
# can't use range ops since they will double-count the tolerance of D, so calculate endpoints separately
295-
range_endpoints = [d_range.lower * (1 - d_range.lower), d_range.upper * (1 - d_range.upper)]
296-
raw_range = Range(min(range_endpoints), max(range_endpoints))
297-
if 0.5 in d_range: # the function has a maximum at 0.5
298-
return raw_range.hull(Range.exact(0.5 * (1 - 0.5)))
299-
else:
300-
return raw_range
301-
302310
@staticmethod
303311
@ExperimentalUserFnPartsTable.user_fn([float, float, float])
304312
def _buck_inductor_filter(max_avg_current: float, ripple_scale: float, min_ripple: float):
305313
"""Applies further filtering to inductors using the trade-off between inductance and peak-peak current.
306-
max_avg_current is the maximum average current (not accounting for ripple) seem by the inductor
307-
ripple_scale is the scaling factor from 1/L to ripple, Vo/(Vi-Vo)/fs/Vi"""
314+
max_avg_current is the maximum average current (not accounting for ripple) seen by the inductor
315+
ripple_scale is the scaling factor from 1/L to ripple
316+
This structure also works for boost converters, which would have its ripple_scale calculated differently."""
308317
def filter_fn(row: PartsTableRow) -> bool:
309318
ripple_current = max(ripple_scale / row[TableInductor.INDUCTANCE].lower, min_ripple)
310319
max_current_pp = max_avg_current + ripple_current / 2
@@ -377,7 +386,7 @@ def generate(self) -> None:
377386

378387
self.inductor = self.Block(Inductor(
379388
inductance=values.inductance * Henry,
380-
current=self.output_current, # min-bound only, the real filter happens in the filter_fn
389+
current=values.inductor_avg_current, # min-bound only, the real filter happens in the filter_fn
381390
frequency=self.frequency,
382391
experimental_filter_fn=ExperimentalUserFnPartsTable.serialize_fn(
383392
self._buck_inductor_filter, values.inductor_avg_current.upper, values.ripple_scale, values.min_ripple)
@@ -389,8 +398,8 @@ def generate(self) -> None:
389398
)))
390399
self.connect(self.pwr_out, self.inductor.b.adapt_to(VoltageSource(
391400
voltage_out=self.output_voltage,
392-
current_limits=BuckConverterPowerPath._ilim_expr(self.inductor.actual_current_rating, self.sw_current_limits,
393-
self.actual_inductor_current_ripple)
401+
current_limits=self._ilim_expr(self.inductor.actual_current_rating, self.sw_current_limits,
402+
self.actual_inductor_current_ripple)
394403
)))
395404

396405
self.in_cap = self.Block(DecouplingCapacitor(
@@ -407,9 +416,8 @@ def generate(self) -> None:
407416
@abstract_block_default(lambda: IdealBoostConverter)
408417
class BoostConverter(SwitchingVoltageRegulator):
409418
"""Step-up switching converter"""
410-
def __init__(self, *args, ripple_current_factor: RangeLike = (0.2, 0.5), **kwargs) -> None:
411-
# TODO default ripple is very heuristic, intended 0.3-0.4, loosely adjusted for inductor tolerance
412-
super().__init__(*args, ripple_current_factor=ripple_current_factor, **kwargs)
419+
def __init__(self, *args, **kwargs) -> None:
420+
super().__init__(*args, **kwargs)
413421
self.require(self.pwr_out.voltage_out.lower() >= self.pwr_in.voltage_limits.lower())
414422

415423

@@ -464,7 +472,7 @@ def _calculate_parameters(cls, input_voltage: Range, output_voltage: Range, freq
464472
"""See BuckConverterPowerPath._calculate_parameters, this performs a similar function."""
465473
dutycycle = 1 - input_voltage / output_voltage * efficiency
466474
effective_dutycycle = dutycycle.bound_to(dutycycle_limit) # account for tracking behavior
467-
inductor_avg_current = output_current * (output_voltage / input_voltage)
475+
inductor_avg_current = output_current / (1 - effective_dutycycle)
468476

469477
# calculate minimum inductance based on worst case values (operating range corners producing maximum inductance)
470478
# worst-case input/output voltages and frequency is used to avoid double-counting tolerances as ranges
@@ -482,10 +490,9 @@ def _calculate_parameters(cls, input_voltage: Range, output_voltage: Range, freq
482490
inductance = Range.all()
483491
min_ripple = 0.0
484492
if sw_current_limits.upper > 0: # fallback for light-load
485-
# since limits are defined in terms of the switch current which should have ripple factored in already,
486-
# assume a safe-ish 0.25 ripple ratio was specified and unapply that before applying the limit ratio
487-
inductance = inductance.intersect(inductance_scale / (sw_current_limits.upper / 1.25 * limit_ripple_ratio))
488-
min_ripple = sw_current_limits.upper / 1.25 * limit_ripple_ratio.lower
493+
ripple_current = BuckConverterPowerPath._ripple_current_from_sw_current(sw_current_limits.upper, limit_ripple_ratio)
494+
inductance = inductance.intersect(inductance_scale / ripple_current)
495+
min_ripple = ripple_current.lower
489496
if ripple_ratio.upper < float('inf'):
490497
assert ripple_ratio.lower > 0, f"invalid non-inf ripple ratio {ripple_ratio}"
491498
inductance = inductance.intersect(inductance_scale / (inductor_avg_current.upper * ripple_ratio))
@@ -570,7 +577,7 @@ def generate(self) -> None:
570577

571578
self.inductor = self.Block(Inductor(
572579
inductance=values.inductance * Henry,
573-
current=values.inductor_peak_currents, # min-bound only, the real filter happens in the filter_fn
580+
current=values.inductor_avg_current, # min-bound only, the real filter happens in the filter_fn
574581
frequency=self.frequency,
575582
experimental_filter_fn=ExperimentalUserFnPartsTable.serialize_fn(
576583
BuckConverterPowerPath._buck_inductor_filter,
@@ -602,9 +609,8 @@ def generate(self) -> None:
602609
@abstract_block_default(lambda: IdealVoltageRegulator)
603610
class BuckBoostConverter(SwitchingVoltageRegulator):
604611
"""Step-up or switch-down switching converter"""
605-
def __init__(self, *args, ripple_current_factor: RangeLike = (0.2, 0.5), **kwargs) -> None:
606-
# TODO default ripple is very heuristic, intended 0.3-0.4, loosely adjusted for inductor tolerance
607-
super().__init__(*args, ripple_current_factor=ripple_current_factor, **kwargs)
612+
def __init__(self, *args, **kwargs) -> None:
613+
super().__init__(*args, **kwargs)
608614

609615

610616
@abstract_block_default(lambda: IdealVoltageRegulator)
@@ -705,7 +711,7 @@ def generate(self) -> None:
705711

706712
self.inductor = self.Block(Inductor(
707713
inductance=buck_values.inductance.intersect(boost_values.inductance) * Henry,
708-
current=buck_values.inductor_peak_currents.hull(boost_values.inductor_peak_currents),
714+
current=buck_values.inductor_avg_current.hull(boost_values.inductor_avg_current),
709715
frequency=self.frequency,
710716
experimental_filter_fn=ExperimentalUserFnPartsTable.serialize_fn(
711717
BuckConverterPowerPath._buck_inductor_filter,

edg/parts/BoostConverter_AnalogDevices.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,8 @@ def contents(self):
7272
self.pwr_in.link().voltage, self.fb.actual_input_voltage, self.actual_frequency,
7373
self.pwr_out.link().current_drawn, (0, self.NMOS_CURRENT_LIMIT)*Amp,
7474
input_voltage_ripple=self.input_ripple_limit,
75-
output_voltage_ripple=self.output_ripple_limit
75+
output_voltage_ripple=self.output_ripple_limit,
76+
ripple_ratio=self.ripple_current_factor,
7677
))
7778
self.connect(self.power_path.pwr_out, self.pwr_out)
7879
self.connect(self.power_path.switch, self.ic.sw)

edg/parts/BoostConverter_DiodesInc.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,8 @@ def contents(self):
6767
self.pwr_in.link().voltage, self.fb.actual_input_voltage, self.actual_frequency,
6868
self.pwr_out.link().current_drawn, (0, 0.5)*Amp,
6969
input_voltage_ripple=self.input_ripple_limit,
70-
output_voltage_ripple=self.output_ripple_limit
70+
output_voltage_ripple=self.output_ripple_limit,
71+
ripple_ratio=self.ripple_current_factor,
7172
))
7273
self.connect(self.power_path.pwr_out, self.pwr_out)
7374
self.connect(self.power_path.switch, self.ic.sw)

edg/parts/BoostConverter_TexasInstruments.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -223,7 +223,8 @@ def contents(self):
223223
self.pwr_in.link().voltage, self.fb.actual_input_voltage, self.actual_frequency,
224224
self.pwr_out.link().current_drawn, (0, 1)*Amp,
225225
input_voltage_ripple=self.input_ripple_limit,
226-
output_voltage_ripple=self.output_ripple_limit
226+
output_voltage_ripple=self.output_ripple_limit,
227+
ripple_ratio=self.ripple_current_factor,
227228
))
228229
self.connect(self.power_path.pwr_out, self.pwr_out)
229230
self.connect(self.power_path.switch, self.ic.sw)

edg/parts/BoostConverter_Torex.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,8 @@ def contents(self):
9090
self.pwr_in.link().voltage, self.ic.vout.voltage_out, self.actual_frequency,
9191
self.pwr_out.link().current_drawn, self.ic.actual_current_limit,
9292
input_voltage_ripple=self.input_ripple_limit,
93-
output_voltage_ripple=self.output_ripple_limit
93+
output_voltage_ripple=self.output_ripple_limit,
94+
ripple_ratio=self.ripple_current_factor,
9495
))
9596
self.connect(self.power_path.pwr_out, self.pwr_out)
9697
self.connect(self.power_path.switch, self.ic.sw)

0 commit comments

Comments
 (0)