Coverage for src / tracekit / workflows / power.py: 100%
35 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 analysis workflow.
3This module implements comprehensive power consumption analysis from
4voltage and current traces.
7Example:
8 >>> import tracekit as tk
9 >>> voltage = tk.load('vdd.wfm')
10 >>> current = tk.load('idd.wfm')
11 >>> result = tk.power_analysis(voltage, current)
12 >>> print(f"Average Power: {result['average_power']*1e3:.2f} mW")
14References:
15 IEC 61000: Electromagnetic compatibility
16 IEEE 1241-2010: ADC terminology and test methods
17"""
19from __future__ import annotations
21from typing import TYPE_CHECKING, Any
23import numpy as np
25from tracekit.core.exceptions import AnalysisError
27if TYPE_CHECKING:
28 from tracekit.core.types import WaveformTrace
31def power_analysis(
32 voltage: WaveformTrace,
33 current: WaveformTrace,
34 *,
35 input_voltage: WaveformTrace | None = None,
36 input_current: WaveformTrace | None = None,
37 report: str | None = None,
38) -> dict[str, Any]:
39 """Comprehensive power consumption analysis.
41 Analyzes power consumption from voltage and current measurements:
42 - Instantaneous power calculation
43 - Average, RMS, and peak power
44 - Energy consumption
45 - Efficiency (if input power provided)
46 - Power profile generation
48 Args:
49 voltage: Output voltage trace.
50 current: Output current trace.
51 input_voltage: Optional input voltage for efficiency calculation.
52 input_current: Optional input current for efficiency calculation.
53 report: Optional path to save HTML report.
55 Returns:
56 Dictionary containing:
57 - power_trace: WaveformTrace of instantaneous power P(t)
58 - average_power: Mean power in watts
59 - output_power_avg: Average output power (same as average_power)
60 - output_power_rms: RMS output power in watts
61 - peak_power: Maximum power in watts
62 - min_power: Minimum power in watts
63 - energy: Total energy in joules
64 - duration: Measurement duration in seconds
65 - efficiency: Efficiency percentage (if input provided)
66 - power_loss: Power loss in watts (if input provided)
67 - input_power_avg: Average input power (if input provided)
69 Raises:
70 AnalysisError: If traces have incompatible sample rates or lengths.
72 Example:
73 >>> voltage = tk.load('vout.wfm')
74 >>> current = tk.load('iout.wfm')
75 >>> result = tk.power_analysis(voltage, current)
76 >>> print(f"Average: {result['average_power']*1e3:.2f} mW")
77 >>> print(f"Peak: {result['peak_power']*1e3:.2f} mW")
78 >>> print(f"Energy: {result['energy']*1e6:.2f} µJ")
80 References:
81 IEC 61000-4-7: Harmonics and interharmonics measurement
82 IEEE 1459-2010: Definitions for measurement of electric power
83 """
84 # Import power analysis functions
85 from tracekit.analyzers.power.basic import (
86 instantaneous_power,
87 power_statistics,
88 )
90 # Validate traces
91 if voltage.metadata.sample_rate != current.metadata.sample_rate:
92 # Would need interpolation in real implementation
93 raise AnalysisError(
94 "Voltage and current traces must have same sample rate. "
95 f"Got {voltage.metadata.sample_rate} and {current.metadata.sample_rate}"
96 )
98 # Calculate instantaneous power
99 power_trace = instantaneous_power(voltage, current)
101 # Calculate power statistics
102 stats = power_statistics(power_trace)
104 # Build result with output power
105 result = {
106 "power_trace": power_trace,
107 "average_power": stats["average"],
108 "output_power_avg": stats["average"],
109 "output_power_rms": stats["rms"],
110 "peak_power": stats["peak"],
111 "min_power": stats.get("min", np.min(power_trace.data)),
112 "energy": stats["energy"],
113 "duration": stats["duration"],
114 }
116 # Calculate efficiency if input provided
117 if input_voltage is not None and input_current is not None:
118 input_power_trace = instantaneous_power(input_voltage, input_current)
119 input_stats = power_statistics(input_power_trace)
121 input_power_avg = input_stats["average"]
122 output_power_avg = stats["average"]
124 if input_power_avg > 0:
125 efficiency = (output_power_avg / input_power_avg) * 100.0
126 power_loss = input_power_avg - output_power_avg
127 else:
128 efficiency = 0.0
129 power_loss = 0.0
131 result["efficiency"] = efficiency
132 result["power_loss"] = power_loss
133 result["input_power_avg"] = input_power_avg
135 # Generate report if requested
136 if report is not None:
137 _generate_power_report(result, report)
139 return result
142def _generate_power_report(result: dict[str, Any], output_path: str) -> None:
143 """Generate HTML report for power analysis.
145 Args:
146 result: Power analysis result dictionary.
147 output_path: Path to save HTML report.
148 """
149 html = f"""
150 <html>
151 <head><title>Power Analysis Report</title></head>
152 <body>
153 <h1>Power Analysis Report</h1>
154 <h2>Power Statistics</h2>
155 <table>
156 <tr><th>Parameter</th><th>Value</th><th>Units</th></tr>
157 <tr><td>Average Power</td><td>{result["average_power"] * 1e3:.3f}</td><td>mW</td></tr>
158 <tr><td>RMS Power</td><td>{result["output_power_rms"] * 1e3:.3f}</td><td>mW</td></tr>
159 <tr><td>Peak Power</td><td>{result["peak_power"] * 1e3:.3f}</td><td>mW</td></tr>
160 <tr><td>Total Energy</td><td>{result["energy"] * 1e6:.3f}</td><td>µJ</td></tr>
161 <tr><td>Duration</td><td>{result["duration"] * 1e3:.3f}</td><td>ms</td></tr>
162 """
163 if "efficiency" in result:
164 html += f"""
165 <tr><td>Efficiency</td><td>{result["efficiency"]:.1f}</td><td>%</td></tr>
166 <tr><td>Input Power</td><td>{result["input_power_avg"] * 1e3:.3f}</td><td>mW</td></tr>
167 <tr><td>Power Loss</td><td>{result["power_loss"] * 1e3:.3f}</td><td>mW</td></tr>
168 """
169 html += """
170 </table>
171 </body>
172 </html>
173 """
174 with open(output_path, "w") as f:
175 f.write(html)
178__all__ = ["power_analysis"]