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

1"""Power analysis workflow. 

2 

3This module implements comprehensive power consumption analysis from 

4voltage and current traces. 

5 

6 

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") 

13 

14References: 

15 IEC 61000: Electromagnetic compatibility 

16 IEEE 1241-2010: ADC terminology and test methods 

17""" 

18 

19from __future__ import annotations 

20 

21from typing import TYPE_CHECKING, Any 

22 

23import numpy as np 

24 

25from tracekit.core.exceptions import AnalysisError 

26 

27if TYPE_CHECKING: 

28 from tracekit.core.types import WaveformTrace 

29 

30 

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. 

40 

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 

47 

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. 

54 

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) 

68 

69 Raises: 

70 AnalysisError: If traces have incompatible sample rates or lengths. 

71 

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") 

79 

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 ) 

89 

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 ) 

97 

98 # Calculate instantaneous power 

99 power_trace = instantaneous_power(voltage, current) 

100 

101 # Calculate power statistics 

102 stats = power_statistics(power_trace) 

103 

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 } 

115 

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) 

120 

121 input_power_avg = input_stats["average"] 

122 output_power_avg = stats["average"] 

123 

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 

130 

131 result["efficiency"] = efficiency 

132 result["power_loss"] = power_loss 

133 result["input_power_avg"] = input_power_avg 

134 

135 # Generate report if requested 

136 if report is not None: 

137 _generate_power_report(result, report) 

138 

139 return result 

140 

141 

142def _generate_power_report(result: dict[str, Any], output_path: str) -> None: 

143 """Generate HTML report for power analysis. 

144 

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) 

176 

177 

178__all__ = ["power_analysis"]