Coverage for src / tracekit / analyzers / power / efficiency.py: 100%
64 statements
« prev ^ index » next coverage.py v7.13.1, created at 2026-01-11 23:04 +0000
« prev ^ index » next coverage.py v7.13.1, created at 2026-01-11 23:04 +0000
1"""Power efficiency calculations for TraceKit.
3Provides efficiency calculations for power converters and systems.
6Example:
7 >>> from tracekit.analyzers.power.efficiency import efficiency
8 >>> eta = efficiency(v_in, i_in, v_out, i_out)
9 >>> print(f"Efficiency: {eta*100:.1f}%")
10"""
12from __future__ import annotations
14from typing import TYPE_CHECKING
16import numpy as np
18from tracekit.analyzers.power.basic import average_power, instantaneous_power
20if TYPE_CHECKING:
21 from numpy.typing import NDArray
23 from tracekit.core.types import WaveformTrace
26def efficiency(
27 v_in: WaveformTrace,
28 i_in: WaveformTrace,
29 v_out: WaveformTrace,
30 i_out: WaveformTrace,
31) -> float:
32 """Calculate power conversion efficiency.
34 eta = P_out / P_in * 100%
36 Args:
37 v_in: Input voltage trace.
38 i_in: Input current trace.
39 v_out: Output voltage trace.
40 i_out: Output current trace.
42 Returns:
43 Efficiency as a ratio (0 to 1).
45 Example:
46 >>> eta = efficiency(v_in, i_in, v_out, i_out)
47 >>> print(f"Efficiency: {eta*100:.1f}%")
48 """
49 p_in = average_power(voltage=v_in, current=i_in)
50 p_out = average_power(voltage=v_out, current=i_out)
52 if p_in <= 0:
53 return 0.0
55 return p_out / p_in
58def power_conversion_efficiency(
59 p_in: float,
60 p_out: float,
61) -> float:
62 """Calculate efficiency from power values.
64 Args:
65 p_in: Input power in Watts.
66 p_out: Output power in Watts.
68 Returns:
69 Efficiency as a ratio (0 to 1).
71 Example:
72 >>> eta = power_conversion_efficiency(p_in=100, p_out=90)
73 >>> print(f"Efficiency: {eta*100:.1f}%")
74 """
75 if p_in <= 0:
76 return 0.0
77 return p_out / p_in
80def multi_output_efficiency(
81 v_in: WaveformTrace,
82 i_in: WaveformTrace,
83 outputs: list[tuple[WaveformTrace, WaveformTrace]],
84) -> dict[str, float]:
85 """Calculate efficiency for multi-output power supply.
87 Args:
88 v_in: Input voltage trace.
89 i_in: Input current trace.
90 outputs: List of (v_out, i_out) trace tuples for each output.
92 Returns:
93 Dictionary with:
94 - total_efficiency: Overall efficiency
95 - output_N_efficiency: Per-output efficiency (contribution)
96 - output_N_power: Per-output power
97 - total_output_power: Sum of all output powers
98 - input_power: Input power
99 - losses: Power losses (P_in - P_out_total)
101 Example:
102 >>> outputs = [(v1, i1), (v2, i2), (v3, i3)]
103 >>> result = multi_output_efficiency(v_in, i_in, outputs)
104 >>> print(f"Total efficiency: {result['total_efficiency']*100:.1f}%")
105 """
106 p_in = average_power(voltage=v_in, current=i_in)
108 result = {
109 "input_power": p_in,
110 }
112 total_output = 0.0
113 for idx, (v_out, i_out) in enumerate(outputs):
114 p_out = average_power(voltage=v_out, current=i_out)
115 result[f"output_{idx + 1}_power"] = p_out
116 result[f"output_{idx + 1}_efficiency"] = p_out / p_in if p_in > 0 else 0.0
117 total_output += p_out
119 result["total_output_power"] = total_output
120 result["total_efficiency"] = total_output / p_in if p_in > 0 else 0.0
121 result["losses"] = p_in - total_output
123 return result
126def efficiency_vs_load(
127 v_in: WaveformTrace,
128 i_in: WaveformTrace,
129 v_out: WaveformTrace,
130 i_out: WaveformTrace,
131 *,
132 n_points: int = 100,
133) -> dict[str, NDArray[np.float64]]:
134 """Calculate efficiency across the load range.
136 Segments the waveforms and calculates efficiency at each load level.
138 Args:
139 v_in: Input voltage trace.
140 i_in: Input current trace.
141 v_out: Output voltage trace.
142 i_out: Output current trace.
143 n_points: Number of load points to evaluate.
145 Returns:
146 Dictionary with:
147 - load_percent: Load levels as percentage of max
148 - efficiency: Efficiency at each load level
149 - output_power: Output power at each load level
150 - input_power: Input power at each load level
152 Example:
153 >>> result = efficiency_vs_load(v_in, i_in, v_out, i_out)
154 >>> plt.plot(result['load_percent'], result['efficiency'] * 100)
155 """
156 # Calculate instantaneous power
157 p_out_trace = instantaneous_power(v_out, i_out)
158 p_in_trace = instantaneous_power(v_in, i_in)
160 p_out_data = p_out_trace.data
161 p_in_data = p_in_trace.data[: len(p_out_data)]
163 # Sort by output power to get load curve
164 sort_idx = np.argsort(p_out_data)
165 p_out_sorted = p_out_data[sort_idx]
166 p_in_sorted = p_in_data[sort_idx]
168 # Divide into bins
169 bin_size = len(p_out_sorted) // n_points
170 bin_size = max(bin_size, 1)
172 load_pct = []
173 efficiency_vals = []
174 p_out_vals = []
175 p_in_vals = []
177 max_p_out = np.max(p_out_data)
179 for i in range(0, len(p_out_sorted), bin_size):
180 bin_p_out = np.mean(p_out_sorted[i : i + bin_size])
181 bin_p_in = np.mean(p_in_sorted[i : i + bin_size])
183 load_pct.append(bin_p_out / max_p_out * 100 if max_p_out > 0 else 0)
184 p_out_vals.append(bin_p_out)
185 p_in_vals.append(bin_p_in)
186 efficiency_vals.append(bin_p_out / bin_p_in if bin_p_in > 0 else 0)
188 return {
189 "load_percent": np.array(load_pct),
190 "efficiency": np.array(efficiency_vals),
191 "output_power": np.array(p_out_vals),
192 "input_power": np.array(p_in_vals),
193 }
196def loss_breakdown(
197 v_in: WaveformTrace,
198 i_in: WaveformTrace,
199 v_out: WaveformTrace,
200 i_out: WaveformTrace,
201 *,
202 switching_loss: float = 0.0,
203 conduction_loss: float = 0.0,
204 magnetic_loss: float = 0.0,
205 gate_drive_loss: float = 0.0,
206) -> dict[str, float]:
207 """Break down power losses by category.
209 Args:
210 v_in: Input voltage trace.
211 i_in: Input current trace.
212 v_out: Output voltage trace.
213 i_out: Output current trace.
214 switching_loss: Known switching losses in Watts.
215 conduction_loss: Known conduction losses in Watts.
216 magnetic_loss: Known magnetic (core/copper) losses in Watts.
217 gate_drive_loss: Known gate drive losses in Watts.
219 Returns:
220 Dictionary with loss breakdown.
222 Example:
223 >>> result = loss_breakdown(v_in, i_in, v_out, i_out,
224 ... switching_loss=2.0, conduction_loss=1.5, magnetic_loss=0.5)
225 >>> print(f"Other losses: {result['other_loss']:.2f} W")
226 """
227 p_in = average_power(voltage=v_in, current=i_in)
228 p_out = average_power(voltage=v_out, current=i_out)
229 total_loss = p_in - p_out
231 known_losses = switching_loss + conduction_loss + magnetic_loss + gate_drive_loss
232 other_loss = total_loss - known_losses
234 eta = p_out / p_in if p_in > 0 else 0.0
236 return {
237 "input_power": p_in,
238 "output_power": p_out,
239 "efficiency": eta,
240 "total_loss": total_loss,
241 "switching_loss": switching_loss,
242 "conduction_loss": conduction_loss,
243 "magnetic_loss": magnetic_loss,
244 "gate_drive_loss": gate_drive_loss,
245 "other_loss": max(0, other_loss), # Clamp to non-negative
246 "switching_loss_percent": switching_loss / total_loss * 100 if total_loss > 0 else 0,
247 "conduction_loss_percent": conduction_loss / total_loss * 100 if total_loss > 0 else 0,
248 "magnetic_loss_percent": magnetic_loss / total_loss * 100 if total_loss > 0 else 0,
249 }
252def thermal_efficiency(
253 p_in: float,
254 p_out: float,
255 ambient_temp: float,
256 case_temp: float,
257 thermal_resistance: float,
258) -> dict[str, float]:
259 """Calculate thermal-related efficiency metrics.
261 Args:
262 p_in: Input power in Watts.
263 p_out: Output power in Watts.
264 ambient_temp: Ambient temperature in Celsius.
265 case_temp: Case/junction temperature in Celsius.
266 thermal_resistance: Thermal resistance (Rth_j-a) in C/W.
268 Returns:
269 Dictionary with thermal analysis.
271 Example:
272 >>> result = thermal_efficiency(100, 90, 25, 65, 2.5)
273 >>> print(f"Estimated losses: {result['estimated_losses']:.1f} W")
274 """
275 losses = p_in - p_out
276 eta = p_out / p_in if p_in > 0 else 0.0
278 # Estimate losses from thermal measurement
279 thermal_losses = (case_temp - ambient_temp) / thermal_resistance
281 return {
282 "efficiency": eta,
283 "electrical_losses": losses,
284 "thermal_estimated_losses": thermal_losses,
285 "temperature_rise": case_temp - ambient_temp,
286 "loss_discrepancy": abs(losses - thermal_losses),
287 }
290__all__ = [
291 "efficiency",
292 "efficiency_vs_load",
293 "loss_breakdown",
294 "multi_output_efficiency",
295 "power_conversion_efficiency",
296 "thermal_efficiency",
297]