ee-toolkit 0.0.2__tar.gz → 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {ee_toolkit-0.0.2 → ee_toolkit-0.1.0}/PKG-INFO +1 -1
- {ee_toolkit-0.0.2 → ee_toolkit-0.1.0}/src/ee_toolkit/__about__.py +1 -1
- {ee_toolkit-0.0.2 → ee_toolkit-0.1.0}/src/ee_toolkit/cli.py +7 -0
- ee_toolkit-0.1.0/src/ee_toolkit/mosfet.py +95 -0
- ee_toolkit-0.1.0/src/ee_toolkit/resistor.py +258 -0
- {ee_toolkit-0.0.2 → ee_toolkit-0.1.0}/LICENSE.txt +0 -0
- {ee_toolkit-0.0.2 → ee_toolkit-0.1.0}/README.md +0 -0
- {ee_toolkit-0.0.2 → ee_toolkit-0.1.0}/pyproject.toml +0 -0
- {ee_toolkit-0.0.2 → ee_toolkit-0.1.0}/src/ee_toolkit/__init__.py +0 -0
- {ee_toolkit-0.0.2 → ee_toolkit-0.1.0}/src/ee_toolkit/eseries.py +0 -0
- {ee_toolkit-0.0.2 → ee_toolkit-0.1.0}/src/ee_toolkit/filters.py +0 -0
- {ee_toolkit-0.0.2 → ee_toolkit-0.1.0}/src/ee_toolkit/opamp.py +0 -0
- {ee_toolkit-0.0.2 → ee_toolkit-0.1.0}/src/ee_toolkit/oscillator.py +0 -0
- {ee_toolkit-0.0.2 → ee_toolkit-0.1.0}/src/ee_toolkit/units.py +0 -0
- {ee_toolkit-0.0.2 → ee_toolkit-0.1.0}/tests/test_ee_calc.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: ee-toolkit
|
|
3
|
-
Version: 0.0
|
|
3
|
+
Version: 0.1.0
|
|
4
4
|
Project-URL: Documentation, https://git.sr.ht/~laplace/ee-toolkit#readme
|
|
5
5
|
Project-URL: Issues, https://git.sr.ht/~laplace/ee-toolkit/todo
|
|
6
6
|
Project-URL: Source, https://git.sr.ht/~laplace/ee-toolkit
|
|
@@ -6,12 +6,15 @@ Commands:
|
|
|
6
6
|
eseries E-series standard value lookup
|
|
7
7
|
oscillator LC/Colpitts/Hartley resonance frequencies
|
|
8
8
|
opamp Op-amp gain, integrator, differentiator
|
|
9
|
+
resistor Series / parallel resistor combinations
|
|
9
10
|
"""
|
|
10
11
|
import click
|
|
11
12
|
from .filters import filter_group
|
|
12
13
|
from .eseries import eseries_group
|
|
13
14
|
from .oscillator import oscillator_group
|
|
14
15
|
from .opamp import opamp_group
|
|
16
|
+
from .mosfet import mosfet_group
|
|
17
|
+
from .resistor import resistor_group
|
|
15
18
|
|
|
16
19
|
|
|
17
20
|
@click.group()
|
|
@@ -25,6 +28,8 @@ def cli():
|
|
|
25
28
|
eseries Nearest E-series value / two-component decomposition
|
|
26
29
|
oscillator LC, Colpitts, Hartley resonance frequency
|
|
27
30
|
opamp Inverting / non-inverting gain, integrator, differentiator
|
|
31
|
+
mosfet Power MOSFET calculations (gate drive, switching)
|
|
32
|
+
resistor Series / parallel resistor combinations
|
|
28
33
|
|
|
29
34
|
Run ee-calc COMMAND --help for details on a command.
|
|
30
35
|
"""
|
|
@@ -34,3 +39,5 @@ cli.add_command(filter_group, name='filter')
|
|
|
34
39
|
cli.add_command(eseries_group, name='eseries')
|
|
35
40
|
cli.add_command(oscillator_group, name='oscillator')
|
|
36
41
|
cli.add_command(opamp_group, name='opamp')
|
|
42
|
+
cli.add_command(mosfet_group, name='mosfet')
|
|
43
|
+
cli.add_command(resistor_group, name='resistor')
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Power MOSFET calculations.
|
|
3
|
+
|
|
4
|
+
Gate Drive Requirements
|
|
5
|
+
-----------------------
|
|
6
|
+
Required Drive Current: Ig = Qg / t_sw
|
|
7
|
+
Switching Time: t_sw = Qg / Ig
|
|
8
|
+
Gate Drive Power: Pgate = Qg * Vdr * f_sw
|
|
9
|
+
Peak Current: Ig_peak = Vdr / Rg_total
|
|
10
|
+
"""
|
|
11
|
+
import click
|
|
12
|
+
from .units import parse_si, fmt_si
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def ig_from_tsw(qg: float, tsw: float) -> float:
|
|
16
|
+
"""Average gate current required for a specific switching time."""
|
|
17
|
+
return qg / tsw
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def tsw_from_ig(qg: float, ig: float) -> float:
|
|
21
|
+
"""Estimated switching time for a given average gate current."""
|
|
22
|
+
return qg / ig
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def pgate_power(qg: float, vdr: float, fsw: float) -> float:
|
|
26
|
+
"""Power dissipated in the gate driver."""
|
|
27
|
+
return qg * vdr * fsw
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def ig_peak_from_rg(vdr: float, rg: float) -> float:
|
|
31
|
+
"""Peak gate drive current limited by total gate resistance."""
|
|
32
|
+
return vdr / rg
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
@click.group()
|
|
36
|
+
def mosfet_group():
|
|
37
|
+
"""Power MOSFET calculations (gate drive, switching)."""
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
@mosfet_group.command('gate')
|
|
41
|
+
@click.option('--qg', 'qg_str', required=True, metavar='VALUE',
|
|
42
|
+
help='Total gate charge (Qg), e.g. 50n')
|
|
43
|
+
@click.option('--vdr', 'vdr_str', required=True, metavar='VALUE',
|
|
44
|
+
help='Gate drive voltage (Vdr), e.g. 12')
|
|
45
|
+
@click.option('--tsw', 'tsw_str', default=None, metavar='VALUE',
|
|
46
|
+
help='Desired switching time (t_sw), e.g. 20n')
|
|
47
|
+
@click.option('--ig', 'ig_str', default=None, metavar='VALUE',
|
|
48
|
+
help='Available gate drive current (Ig), e.g. 1.5')
|
|
49
|
+
@click.option('--rg', 'rg_str', default=None, metavar='VALUE',
|
|
50
|
+
help='Total gate resistance (driver + ext + int), e.g. 10')
|
|
51
|
+
@click.option('--fsw', 'fsw_str', default=None, metavar='VALUE',
|
|
52
|
+
help='Switching frequency, e.g. 100k')
|
|
53
|
+
def cmd_gate(qg_str, vdr_str, tsw_str, ig_str, rg_str, fsw_str):
|
|
54
|
+
"""Gate driver requirements for power MOSFETs.
|
|
55
|
+
|
|
56
|
+
\b
|
|
57
|
+
Formulas:
|
|
58
|
+
Ig_req = Qg / t_sw
|
|
59
|
+
t_sw = Qg / Ig
|
|
60
|
+
P_gate = Qg * Vdr * f_sw
|
|
61
|
+
Ig_peak = Vdr / Rg_total
|
|
62
|
+
|
|
63
|
+
Example:
|
|
64
|
+
ee-calc mosfet gate --qg 50n --vdr 12 --tsw 20n --fsw 100k
|
|
65
|
+
"""
|
|
66
|
+
qg = parse_si(qg_str)
|
|
67
|
+
vdr = parse_si(vdr_str)
|
|
68
|
+
|
|
69
|
+
click.echo("Power MOSFET Gate Drive")
|
|
70
|
+
click.echo(f" Qg = {fmt_si(qg, 'C')}")
|
|
71
|
+
click.echo(f" Vdr = {fmt_si(vdr, 'V')}")
|
|
72
|
+
|
|
73
|
+
if tsw_str:
|
|
74
|
+
tsw = parse_si(tsw_str)
|
|
75
|
+
ig_req = ig_from_tsw(qg, tsw)
|
|
76
|
+
click.echo(f"\nTarget Switching Time: t_sw = {fmt_si(tsw, 's')}")
|
|
77
|
+
click.echo(f" Required average gate current (Ig) = {fmt_si(ig_req, 'A')}")
|
|
78
|
+
|
|
79
|
+
if ig_str:
|
|
80
|
+
ig = parse_si(ig_str)
|
|
81
|
+
tsw_est = tsw_from_ig(qg, ig)
|
|
82
|
+
click.echo(f"\nAvailable Gate Current: Ig = {fmt_si(ig, 'A')}")
|
|
83
|
+
click.echo(f" Estimated switching time (t_sw) = {fmt_si(tsw_est, 's')}")
|
|
84
|
+
|
|
85
|
+
if rg_str:
|
|
86
|
+
rg = parse_si(rg_str)
|
|
87
|
+
ig_peak = ig_peak_from_rg(vdr, rg)
|
|
88
|
+
click.echo(f"\nTotal Gate Resistance: Rg = {fmt_si(rg, 'Ω')}")
|
|
89
|
+
click.echo(f" Peak driver current (Ipk) = {fmt_si(ig_peak, 'A')}")
|
|
90
|
+
|
|
91
|
+
if fsw_str:
|
|
92
|
+
fsw = parse_si(fsw_str)
|
|
93
|
+
pd = pgate_power(qg, vdr, fsw)
|
|
94
|
+
click.echo(f"\nSwitching Frequency: f_sw = {fmt_si(fsw, 'Hz')}")
|
|
95
|
+
click.echo(f" Gate driver power (Pd) = {fmt_si(pd, 'W')}")
|
|
@@ -0,0 +1,258 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Resistor series / parallel combination calculator.
|
|
3
|
+
|
|
4
|
+
Series: R_total = R1 + R2 + … + Rn
|
|
5
|
+
Parallel: 1/R_total = 1/R1 + 1/R2 + … + 1/Rn
|
|
6
|
+
|
|
7
|
+
The CLI command accepts one or more --sg (series group) options.
|
|
8
|
+
Each --sg VALUE VALUE … is treated as resistors wired in parallel.
|
|
9
|
+
Multiple --sg groups are then summed in series.
|
|
10
|
+
|
|
11
|
+
Example
|
|
12
|
+
-------
|
|
13
|
+
Two 10 kΩ in parallel, in series with a 4.7 kΩ:
|
|
14
|
+
|
|
15
|
+
ee-calc resistor combine --sg 10k 10k --sg 4.7k
|
|
16
|
+
"""
|
|
17
|
+
from __future__ import annotations
|
|
18
|
+
from typing import List, Tuple
|
|
19
|
+
from .eseries import all_values
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def parallel(*resistances: float) -> float:
|
|
23
|
+
"""Return the equivalent resistance of *resistances* wired in parallel.
|
|
24
|
+
|
|
25
|
+
Raises ValueError if any resistance is zero (short circuit).
|
|
26
|
+
"""
|
|
27
|
+
if any(r == 0.0 for r in resistances):
|
|
28
|
+
raise ValueError("A resistor value of 0 Ω creates a short circuit.")
|
|
29
|
+
return 1.0 / sum(1.0 / r for r in resistances)
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def series(*resistances: float) -> float:
|
|
33
|
+
"""Return the equivalent resistance of *resistances* wired in series."""
|
|
34
|
+
return sum(resistances)
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def series_parallel_groups(groups: List[List[float]]) -> float:
|
|
38
|
+
"""
|
|
39
|
+
Compute the total resistance of groups wired in series, where each
|
|
40
|
+
group is a list of resistors wired in parallel.
|
|
41
|
+
|
|
42
|
+
Parameters
|
|
43
|
+
----------
|
|
44
|
+
groups : list of lists
|
|
45
|
+
Each inner list is a parallel group. Groups are combined in series.
|
|
46
|
+
|
|
47
|
+
Returns
|
|
48
|
+
-------
|
|
49
|
+
float
|
|
50
|
+
Total equivalent resistance in Ω.
|
|
51
|
+
"""
|
|
52
|
+
group_values = []
|
|
53
|
+
for g in groups:
|
|
54
|
+
if len(g) == 1:
|
|
55
|
+
group_values.append(g[0])
|
|
56
|
+
else:
|
|
57
|
+
group_values.append(parallel(*g))
|
|
58
|
+
return series(*group_values)
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
def voltage_divider(
|
|
62
|
+
v_in: float,
|
|
63
|
+
v_out: float,
|
|
64
|
+
r_total_target: float,
|
|
65
|
+
series: str,
|
|
66
|
+
n_results: int = 5,
|
|
67
|
+
) -> List[Tuple[float, float, float, float, float, float]]:
|
|
68
|
+
"""
|
|
69
|
+
Find best voltage divider resistor pair (r1, r2) for a given E-series.
|
|
70
|
+
Returns: list of (r1, r2, actual_vout, err_vout_percent, actual_rtot, err_rtot_percent)
|
|
71
|
+
"""
|
|
72
|
+
base_vals = all_values(series)
|
|
73
|
+
ratio = v_out / v_in
|
|
74
|
+
if ratio >= 1.0 or ratio <= 0.0:
|
|
75
|
+
raise ValueError("V_out must be strictly between 0 and V_in.")
|
|
76
|
+
|
|
77
|
+
multiplier = ratio / (1.0 - ratio)
|
|
78
|
+
r1_opt = r_total_target / (1.0 + multiplier)
|
|
79
|
+
|
|
80
|
+
# Restrict search space
|
|
81
|
+
lo, hi = r1_opt * 0.01, r1_opt * 100.0
|
|
82
|
+
r1_cands = [v for v in base_vals if lo <= v <= hi]
|
|
83
|
+
|
|
84
|
+
best_for_ratio = {}
|
|
85
|
+
|
|
86
|
+
for r1 in r1_cands:
|
|
87
|
+
r2_ideal = r1 * multiplier
|
|
88
|
+
# Find nearest 5 standard values for R2 for this R1
|
|
89
|
+
r2_sorted = sorted(base_vals, key=lambda v: abs(v - r2_ideal))
|
|
90
|
+
for r2 in r2_sorted[:5]:
|
|
91
|
+
act_v = v_in * r2 / (r1 + r2)
|
|
92
|
+
# bin identical ratios together
|
|
93
|
+
err_v_abs = round(abs(act_v - v_out) / v_out * 100, 8)
|
|
94
|
+
|
|
95
|
+
act_r = r1 + r2
|
|
96
|
+
err_r = abs(act_r - r_total_target) / r_total_target * 100.0
|
|
97
|
+
|
|
98
|
+
item = (
|
|
99
|
+
r1, r2, act_v,
|
|
100
|
+
(act_v - v_out) / v_out * 100.0,
|
|
101
|
+
act_r,
|
|
102
|
+
(act_r - r_total_target) / r_total_target * 100.0
|
|
103
|
+
)
|
|
104
|
+
|
|
105
|
+
# keep the decade-shifted pair that is closest to r_total_target
|
|
106
|
+
if err_v_abs not in best_for_ratio or err_r < abs(best_for_ratio[err_v_abs][5]):
|
|
107
|
+
best_for_ratio[err_v_abs] = item
|
|
108
|
+
|
|
109
|
+
results = list(best_for_ratio.values())
|
|
110
|
+
results.sort(key=lambda x: (abs(x[3]), abs(x[5])))
|
|
111
|
+
return results[:n_results]
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
# ---------------------------------------------------------------------------
|
|
115
|
+
# Click commands
|
|
116
|
+
# ---------------------------------------------------------------------------
|
|
117
|
+
import re
|
|
118
|
+
import click
|
|
119
|
+
from .units import parse_si, fmt_si
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
class _SeriesGroupParam(click.ParamType):
|
|
123
|
+
"""Custom Click parameter type that collects --sg arguments.
|
|
124
|
+
|
|
125
|
+
Accepts a string of whitespace- or comma-separated SI resistor values
|
|
126
|
+
(e.g. "10k 10k" or "10k,10k"). The option is declared with
|
|
127
|
+
multiple=True so it may appear several times on the command line.
|
|
128
|
+
"""
|
|
129
|
+
name = "VALUES"
|
|
130
|
+
|
|
131
|
+
def convert(self, value, param, ctx):
|
|
132
|
+
tokens = re.split(r'[\s,]+', value.strip())
|
|
133
|
+
tokens = [t for t in tokens if t]
|
|
134
|
+
if not tokens:
|
|
135
|
+
self.fail("at least one resistor value is required.", param, ctx)
|
|
136
|
+
try:
|
|
137
|
+
return [parse_si(t) for t in tokens]
|
|
138
|
+
except ValueError as exc:
|
|
139
|
+
self.fail(str(exc), param, ctx)
|
|
140
|
+
|
|
141
|
+
|
|
142
|
+
_SG = _SeriesGroupParam()
|
|
143
|
+
|
|
144
|
+
|
|
145
|
+
@click.group()
|
|
146
|
+
def resistor_group():
|
|
147
|
+
"""Resistor combination calculations (series / parallel)."""
|
|
148
|
+
|
|
149
|
+
|
|
150
|
+
@resistor_group.command('combine')
|
|
151
|
+
@click.option(
|
|
152
|
+
'--sg', 'groups',
|
|
153
|
+
type=_SG,
|
|
154
|
+
multiple=True,
|
|
155
|
+
metavar='VALUES',
|
|
156
|
+
help=(
|
|
157
|
+
'Parallel group: a quoted, space- or comma-separated list of resistor '
|
|
158
|
+
'values (e.g. --sg "10k 10k"). Repeat --sg to wire groups in series.'
|
|
159
|
+
),
|
|
160
|
+
)
|
|
161
|
+
def cmd_combine(groups):
|
|
162
|
+
"""Series / parallel resistor combination.
|
|
163
|
+
|
|
164
|
+
\b
|
|
165
|
+
Each --sg group is treated as resistors wired IN PARALLEL.
|
|
166
|
+
Multiple --sg groups are combined IN SERIES with each other.
|
|
167
|
+
|
|
168
|
+
\b
|
|
169
|
+
Formulas:
|
|
170
|
+
Parallel: 1/R = 1/R1 + 1/R2 + …
|
|
171
|
+
Series: R = R1 + R2 + …
|
|
172
|
+
|
|
173
|
+
\b
|
|
174
|
+
Examples:
|
|
175
|
+
# Two 10 kΩ in parallel → 5 kΩ
|
|
176
|
+
ee-calc resistor combine --sg "10k 10k"
|
|
177
|
+
|
|
178
|
+
# Two 10 kΩ in parallel, then in series with 4.7 kΩ
|
|
179
|
+
ee-calc resistor combine --sg "10k 10k" --sg 4.7k
|
|
180
|
+
|
|
181
|
+
# Three groups in series, each with mixed values
|
|
182
|
+
ee-calc resistor combine --sg "1k 2k" --sg 470 --sg "3.3k 3.3k"
|
|
183
|
+
"""
|
|
184
|
+
if not groups:
|
|
185
|
+
raise click.UsageError("At least one --sg group is required.")
|
|
186
|
+
|
|
187
|
+
# Compute and display
|
|
188
|
+
click.echo("Resistor combination")
|
|
189
|
+
click.echo("")
|
|
190
|
+
|
|
191
|
+
group_results: List[float] = []
|
|
192
|
+
for i, values in enumerate(groups, start=1):
|
|
193
|
+
if len(values) == 1:
|
|
194
|
+
r_eq = values[0]
|
|
195
|
+
click.echo(f" Group {i} (series): {fmt_si(r_eq, 'Ω')}")
|
|
196
|
+
else:
|
|
197
|
+
try:
|
|
198
|
+
r_eq = parallel(*values)
|
|
199
|
+
except ValueError as exc:
|
|
200
|
+
raise click.UsageError(str(exc)) from exc
|
|
201
|
+
parts = " ‖ ".join(fmt_si(v, 'Ω') for v in values)
|
|
202
|
+
click.echo(f" Group {i} (parallel): {parts} → {fmt_si(r_eq, 'Ω')}")
|
|
203
|
+
group_results.append(r_eq)
|
|
204
|
+
|
|
205
|
+
total = series(*group_results)
|
|
206
|
+
click.echo("")
|
|
207
|
+
if len(group_results) > 1:
|
|
208
|
+
series_str = " + ".join(fmt_si(r, 'Ω') for r in group_results)
|
|
209
|
+
click.echo(f" Total (series sum): {series_str}")
|
|
210
|
+
click.echo(f" R_total = {fmt_si(total, 'Ω')}")
|
|
211
|
+
|
|
212
|
+
|
|
213
|
+
_SERIES_CHOICE = click.Choice(['E12', 'E24', 'E48', 'E96', 'E192'], case_sensitive=False)
|
|
214
|
+
|
|
215
|
+
@resistor_group.command('divider')
|
|
216
|
+
@click.option('--vin', 'vin_str', required=True, metavar='VALUE', help='Input voltage.')
|
|
217
|
+
@click.option('--vout', 'vout_str', required=True, metavar='VALUE', help='Target output voltage.')
|
|
218
|
+
@click.option('--ztot', 'ztot_str', required=True, metavar='VALUE', help='Target total impedance (R1 + R2), e.g. 10k.')
|
|
219
|
+
@click.option('--series', default='E24', show_default=True, type=_SERIES_CHOICE, help='E-series to use.')
|
|
220
|
+
@click.option('-n', 'n', default=5, show_default=True, help='Number of combinations to show.')
|
|
221
|
+
def cmd_divider(vin_str, vout_str, ztot_str, series, n):
|
|
222
|
+
"""Calculate voltage divider resistors.
|
|
223
|
+
|
|
224
|
+
\b
|
|
225
|
+
Finds the best R1 (top) and R2 (bottom) in the specified E-series
|
|
226
|
+
that provide the target output voltage, while keeping the sum
|
|
227
|
+
R1 + R2 close to the target total impedance.
|
|
228
|
+
|
|
229
|
+
\b
|
|
230
|
+
Formula:
|
|
231
|
+
V_out = V_in * (R2 / (R1 + R2))
|
|
232
|
+
|
|
233
|
+
\b
|
|
234
|
+
Example:
|
|
235
|
+
ee-calc resistor divider --vin 5 --vout 3.3 --ztot 10k --series E48
|
|
236
|
+
"""
|
|
237
|
+
try:
|
|
238
|
+
v_in = parse_si(vin_str)
|
|
239
|
+
v_out = parse_si(vout_str)
|
|
240
|
+
r_tot = parse_si(ztot_str)
|
|
241
|
+
results = voltage_divider(v_in, v_out, r_tot, series, n)
|
|
242
|
+
except ValueError as exc:
|
|
243
|
+
raise click.UsageError(str(exc)) from exc
|
|
244
|
+
|
|
245
|
+
click.echo(f"Voltage Divider (series {series.upper()})")
|
|
246
|
+
click.echo(f" V_in: {fmt_si(v_in, 'V')}")
|
|
247
|
+
click.echo(f" V_out: {fmt_si(v_out, 'V')} (target)")
|
|
248
|
+
click.echo(f" Z_tot: {fmt_si(r_tot, 'Ω')} (target)")
|
|
249
|
+
click.echo("")
|
|
250
|
+
click.echo(f"{'Rank':<5} {'R1 (top)':<12} {'R2 (bot)':<12} {'V_out':<10} {'Error V':>8} {'Z_total':<10} {'Error Z':>8}")
|
|
251
|
+
click.echo("─" * 76)
|
|
252
|
+
for i, (r1, r2, act_v, err_v, act_rtot, err_rtot) in enumerate(results, 1):
|
|
253
|
+
marker = " ◀" if i == 1 else ""
|
|
254
|
+
click.echo(
|
|
255
|
+
f" {i:<3} {fmt_si(r1, 'Ω'):<12} {fmt_si(r2, 'Ω'):<12} "
|
|
256
|
+
f"{fmt_si(act_v, 'V'):<10} {err_v:>+7.2f}% "
|
|
257
|
+
f"{fmt_si(act_rtot, 'Ω'):<10} {err_rtot:>+7.1f}%{marker}"
|
|
258
|
+
)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|