Learning Objectives
After using this tool, you will be able to:
Select appropriate energy harvesting sources for specific applications
Configure harvester parameters for solar, vibration, thermal, and RF sources
Define device power requirements including sleep, active, and peak consumption
Configure energy storage options (supercapacitors, batteries, hybrid)
Energy Harvesting Calculator
This interactive calculator helps you design energy harvesting systems by allowing you to configure various energy sources and device power requirements. Use the tabs below to work through your design.
Show code
// Source Selection Tab
sourceSelectionPanel = {
if (activeTab !== "Source Selection" ) return html `` ;
const state = harvesterState;
return html `
<div style="padding: 20px; font-family: system-ui, sans-serif;">
<h3 style="color: ${ ieeeColors. navy } ; margin-bottom: 20px;">
Energy Harvesting Source Selection
</h3>
<div style="display: grid; grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); gap: 20px;">
<!-- Solar Panel -->
<div style="border: 2px solid ${ state. sources . solar ? ieeeColors. teal : ieeeColors. gray } ;
border-radius: 12px; padding: 20px; background: ${ state. sources . solar ? '#E8F6F3' : 'white' } ;">
<div style="display: flex; align-items: center; gap: 10px; margin-bottom: 15px;">
<input type="checkbox" ${ state. sources . solar ? 'checked' : '' }
onchange= ${ (e) => updateState ('sources.solar' , e. target . checked )}
style="width: 20px; height: 20px;">
<span style="font-size: 24px;">☀️</span>
<h4 style="margin: 0; color: ${ ieeeColors. navy } ;">Solar Photovoltaic</h4>
</div>
<p style="color: ${ ieeeColors. gray } ; font-size: 14px; margin: 0;">
Converts light energy to electricity. Best for outdoor applications
or well-lit indoor environments.
</p>
<div style="margin-top: 15px; padding: 10px; background: rgba(44,62,80,0.05); border-radius: 8px;">
<div style="font-size: 12px; color: ${ ieeeColors. darkGray } ;">
<strong>Typical Power:</strong> 10-100 mW/cm² (outdoor)<br>
<strong>Best For:</strong> Environmental sensors, agriculture<br>
<strong>Challenge:</strong> Intermittent, weather dependent
</div>
</div>
</div>
<!-- Vibration/Piezo -->
<div style="border: 2px solid ${ state. sources . vibration ? ieeeColors. teal : ieeeColors. gray } ;
border-radius: 12px; padding: 20px; background: ${ state. sources . vibration ? '#E8F6F3' : 'white' } ;">
<div style="display: flex; align-items: center; gap: 10px; margin-bottom: 15px;">
<input type="checkbox" ${ state. sources . vibration ? 'checked' : '' }
onchange= ${ (e) => updateState ('sources.vibration' , e. target . checked )}
style="width: 20px; height: 20px;">
<span style="font-size: 24px;">📳</span>
<h4 style="margin: 0; color: ${ ieeeColors. navy } ;">Vibration / Piezoelectric</h4>
</div>
<p style="color: ${ ieeeColors. gray } ; font-size: 14px; margin: 0;">
Harvests mechanical vibration energy using piezoelectric or
electromagnetic transducers.
</p>
<div style="margin-top: 15px; padding: 10px; background: rgba(44,62,80,0.05); border-radius: 8px;">
<div style="font-size: 12px; color: ${ ieeeColors. darkGray } ;">
<strong>Typical Power:</strong> 0.1-10 mW<br>
<strong>Best For:</strong> Industrial machinery, vehicles<br>
<strong>Challenge:</strong> Frequency matching required
</div>
</div>
</div>
<!-- Thermal (TEG) -->
<div style="border: 2px solid ${ state. sources . thermal ? ieeeColors. teal : ieeeColors. gray } ;
border-radius: 12px; padding: 20px; background: ${ state. sources . thermal ? '#E8F6F3' : 'white' } ;">
<div style="display: flex; align-items: center; gap: 10px; margin-bottom: 15px;">
<input type="checkbox" ${ state. sources . thermal ? 'checked' : '' }
onchange= ${ (e) => updateState ('sources.thermal' , e. target . checked )}
style="width: 20px; height: 20px;">
<span style="font-size: 24px;">🌡️</span>
<h4 style="margin: 0; color: ${ ieeeColors. navy } ;">Thermoelectric (TEG)</h4>
</div>
<p style="color: ${ ieeeColors. gray } ; font-size: 14px; margin: 0;">
Generates power from temperature differentials using the
Seebeck effect.
</p>
<div style="margin-top: 15px; padding: 10px; background: rgba(44,62,80,0.05); border-radius: 8px;">
<div style="font-size: 12px; color: ${ ieeeColors. darkGray } ;">
<strong>Typical Power:</strong> 1-50 mW (ΔT > 10°C)<br>
<strong>Best For:</strong> HVAC, industrial heat sources<br>
<strong>Challenge:</strong> Requires sustained ΔT
</div>
</div>
</div>
<!-- RF Harvesting -->
<div style="border: 2px solid ${ state. sources . rf ? ieeeColors. teal : ieeeColors. gray } ;
border-radius: 12px; padding: 20px; background: ${ state. sources . rf ? '#E8F6F3' : 'white' } ;">
<div style="display: flex; align-items: center; gap: 10px; margin-bottom: 15px;">
<input type="checkbox" ${ state. sources . rf ? 'checked' : '' }
onchange= ${ (e) => updateState ('sources.rf' , e. target . checked )}
style="width: 20px; height: 20px;">
<span style="font-size: 24px;">📡</span>
<h4 style="margin: 0; color: ${ ieeeColors. navy } ;">RF Energy Harvesting</h4>
</div>
<p style="color: ${ ieeeColors. gray } ; font-size: 14px; margin: 0;">
Captures ambient radio frequency energy from Wi-Fi, cellular,
or dedicated RF sources.
</p>
<div style="margin-top: 15px; padding: 10px; background: rgba(44,62,80,0.05); border-radius: 8px;">
<div style="font-size: 12px; color: ${ ieeeColors. darkGray } ;">
<strong>Typical Power:</strong> 0.001-1 mW<br>
<strong>Best For:</strong> Low-power sensors, RFID<br>
<strong>Challenge:</strong> Very low power density
</div>
</div>
</div>
</div>
<!-- Hybrid Mode Info -->
${ Object . values (state. sources ). filter (v => v). length > 1 ? html `
<div style="margin-top: 25px; padding: 15px; background: linear-gradient(135deg, ${ ieeeColors. teal } 15, ${ ieeeColors. orange } 15);
border-radius: 12px; border-left: 4px solid ${ ieeeColors. teal } ;">
<h4 style="margin: 0 0 10px 0; color: ${ ieeeColors. navy } ;">
🔋 Hybrid Harvesting Mode Active
</h4>
<p style="margin: 0; color: ${ ieeeColors. darkGray } ; font-size: 14px;">
You've selected ${ Object . values (state. sources ). filter (v => v). length } energy sources.
Hybrid systems combine multiple harvesting sources to improve reliability and total energy capture.
The calculator will sum the available power from all selected sources.
</p>
</div>
` : '' }
<!-- Source Comparison Table -->
<div style="margin-top: 25px;">
<h4 style="color: ${ ieeeColors. navy } ;">Source Comparison Reference</h4>
<div style="overflow-x: auto;">
<table style="width: 100%; border-collapse: collapse; font-size: 13px;">
<thead>
<tr style="background: ${ ieeeColors. navy } ; color: white;">
<th style="padding: 12px; text-align: left;">Source</th>
<th style="padding: 12px; text-align: center;">Power Density</th>
<th style="padding: 12px; text-align: center;">Availability</th>
<th style="padding: 12px; text-align: center;">Cost/W</th>
<th style="padding: 12px; text-align: center;">Lifetime</th>
</tr>
</thead>
<tbody>
<tr style="background: #f8f9fa;">
<td style="padding: 10px;">☀️ Solar (Outdoor)</td>
<td style="padding: 10px; text-align: center;">10-100 mW/cm²</td>
<td style="padding: 10px; text-align: center;">4-12 hrs/day</td>
<td style="padding: 10px; text-align: center;">$1-5</td>
<td style="padding: 10px; text-align: center;">20+ years</td>
</tr>
<tr>
<td style="padding: 10px;">💡 Solar (Indoor)</td>
<td style="padding: 10px; text-align: center;">10-100 µW/cm²</td>
<td style="padding: 10px; text-align: center;">8-16 hrs/day</td>
<td style="padding: 10px; text-align: center;">$5-20</td>
<td style="padding: 10px; text-align: center;">10+ years</td>
</tr>
<tr style="background: #f8f9fa;">
<td style="padding: 10px;">📳 Vibration</td>
<td style="padding: 10px; text-align: center;">0.1-1 mW/cm³</td>
<td style="padding: 10px; text-align: center;">Variable</td>
<td style="padding: 10px; text-align: center;">$10-50</td>
<td style="padding: 10px; text-align: center;">10+ years</td>
</tr>
<tr>
<td style="padding: 10px;">🌡️ Thermal</td>
<td style="padding: 10px; text-align: center;">1-10 mW/cm²</td>
<td style="padding: 10px; text-align: center;">Continuous*</td>
<td style="padding: 10px; text-align: center;">$5-30</td>
<td style="padding: 10px; text-align: center;">15+ years</td>
</tr>
<tr style="background: #f8f9fa;">
<td style="padding: 10px;">📡 RF</td>
<td style="padding: 10px; text-align: center;">0.1-1 µW/cm²</td>
<td style="padding: 10px; text-align: center;">Continuous</td>
<td style="padding: 10px; text-align: center;">$20-100</td>
<td style="padding: 10px; text-align: center;">10+ years</td>
</tr>
</tbody>
</table>
</div>
<p style="font-size: 12px; color: ${ ieeeColors. gray } ; margin-top: 5px;">
*When temperature differential is maintained
</p>
</div>
</div>
` ;
}
Show code
// Environment Configuration Tab
environmentPanel = {
if (activeTab !== "Environment" ) return html `` ;
const state = harvesterState;
return html `
<div style="padding: 20px; font-family: system-ui, sans-serif;">
<h3 style="color: ${ ieeeColors. navy } ; margin-bottom: 20px;">
Environment Configuration
</h3>
<div style="display: grid; grid-template-columns: repeat(auto-fit, minmax(350px, 1fr)); gap: 25px;">
<!-- Solar Configuration -->
${ state. sources . solar ? html `
<div style="border: 1px solid ${ ieeeColors. lightGray } ; border-radius: 12px; padding: 20px;">
<h4 style="color: ${ ieeeColors. navy } ; margin: 0 0 20px 0; display: flex; align-items: center; gap: 8px;">
☀️ Solar Configuration
</h4>
<div style="margin-bottom: 20px;">
<label style="display: block; font-weight: 600; margin-bottom: 8px; color: ${ ieeeColors. darkGray } ;">
Environment Type
</label>
<select onchange= ${ (e) => {
updateState ('solar.type' , e. target . value );
// Update light level based on type
const levels = { outdoor : 50000 , indoor_bright : 500 , indoor_dim : 100 , shade : 10000 };
updateState ('solar.lightLevel' , levels[e. target . value ] || 50000 );
}} style="width: 100%; padding: 10px; border: 1px solid ${ ieeeColors. lightGray } ; border-radius: 6px;">
<option value="outdoor" ${ state. solar . type === 'outdoor' ? 'selected' : '' } >Outdoor (Full Sun)</option>
<option value="shade" ${ state. solar . type === 'shade' ? 'selected' : '' } >Outdoor (Shade)</option>
<option value="indoor_bright" ${ state. solar . type === 'indoor_bright' ? 'selected' : '' } >Indoor (Bright Office)</option>
<option value="indoor_dim" ${ state. solar . type === 'indoor_dim' ? 'selected' : '' } >Indoor (Dim/Warehouse)</option>
</select>
</div>
<div style="margin-bottom: 20px;">
<label style="display: block; font-weight: 600; margin-bottom: 8px; color: ${ ieeeColors. darkGray } ;">
Light Level: ${ state. solar . lightLevel . toLocaleString ()} lux
</label>
<input type="range" min="50" max="100000" value= ${ state. solar . lightLevel }
onchange= ${ (e) => updateState ('solar.lightLevel' , Number (e. target . value ))}
style="width: 100%;">
<div style="display: flex; justify-content: space-between; font-size: 11px; color: ${ ieeeColors. gray } ;">
<span>50 lux (dim)</span>
<span>100,000 lux (bright sun)</span>
</div>
</div>
<div style="margin-bottom: 20px;">
<label style="display: block; font-weight: 600; margin-bottom: 8px; color: ${ ieeeColors. darkGray } ;">
Solar Panel Area: ${ state. solar . panelArea } cm²
</label>
<input type="range" min="1" max="200" value= ${ state. solar . panelArea }
onchange= ${ (e) => updateState ('solar.panelArea' , Number (e. target . value ))}
style="width: 100%;">
<div style="display: flex; justify-content: space-between; font-size: 11px; color: ${ ieeeColors. gray } ;">
<span>1 cm² (tiny)</span>
<span>200 cm² (large)</span>
</div>
</div>
<div style="margin-bottom: 20px;">
<label style="display: block; font-weight: 600; margin-bottom: 8px; color: ${ ieeeColors. darkGray } ;">
Panel Efficiency: ${ state. solar . efficiency } %
</label>
<input type="range" min="5" max="25" value= ${ state. solar . efficiency }
onchange= ${ (e) => updateState ('solar.efficiency' , Number (e. target . value ))}
style="width: 100%;">
<div style="display: flex; justify-content: space-between; font-size: 11px; color: ${ ieeeColors. gray } ;">
<span>5% (low-cost)</span>
<span>25% (high-eff)</span>
</div>
</div>
<div style="margin-bottom: 10px;">
<label style="display: block; font-weight: 600; margin-bottom: 8px; color: ${ ieeeColors. darkGray } ;">
Available Hours/Day: ${ state. solar . availableHours } hours
</label>
<input type="range" min="1" max="16" value= ${ state. solar . availableHours }
onchange= ${ (e) => updateState ('solar.availableHours' , Number (e. target . value ))}
style="width: 100%;">
<div style="display: flex; justify-content: space-between; font-size: 11px; color: ${ ieeeColors. gray } ;">
<span>1 hr (winter/cloudy)</span>
<span>16 hrs (summer/indoor)</span>
</div>
</div>
</div>
` : '' }
<!-- Vibration Configuration -->
${ state. sources . vibration ? html `
<div style="border: 1px solid ${ ieeeColors. lightGray } ; border-radius: 12px; padding: 20px;">
<h4 style="color: ${ ieeeColors. navy } ; margin: 0 0 20px 0; display: flex; align-items: center; gap: 8px;">
📳 Vibration Configuration
</h4>
<div style="margin-bottom: 20px;">
<label style="display: block; font-weight: 600; margin-bottom: 8px; color: ${ ieeeColors. darkGray } ;">
Harvester Type
</label>
<select onchange= ${ (e) => updateState ('vibration.type' , e. target . value )}
style="width: 100%; padding: 10px; border: 1px solid ${ ieeeColors. lightGray } ; border-radius: 6px;">
<option value="piezo" ${ state. vibration . type === 'piezo' ? 'selected' : '' } >Piezoelectric</option>
<option value="electromagnetic" ${ state. vibration . type === 'electromagnetic' ? 'selected' : '' } >Electromagnetic</option>
<option value="electrostatic" ${ state. vibration . type === 'electrostatic' ? 'selected' : '' } >Electrostatic (MEMS)</option>
</select>
</div>
<div style="margin-bottom: 20px;">
<label style="display: block; font-weight: 600; margin-bottom: 8px; color: ${ ieeeColors. darkGray } ;">
Vibration Frequency: ${ state. vibration . frequency } Hz
</label>
<input type="range" min="10" max="500" value= ${ state. vibration . frequency }
onchange= ${ (e) => updateState ('vibration.frequency' , Number (e. target . value ))}
style="width: 100%;">
<div style="display: flex; justify-content: space-between; font-size: 11px; color: ${ ieeeColors. gray } ;">
<span>10 Hz (slow)</span>
<span>500 Hz (fast machinery)</span>
</div>
</div>
<div style="margin-bottom: 20px;">
<label style="display: block; font-weight: 600; margin-bottom: 8px; color: ${ ieeeColors. darkGray } ;">
Acceleration: ${ state. vibration . acceleration . toFixed (2 )} g
</label>
<input type="range" min="0.01" max="2" step="0.01" value= ${ state. vibration . acceleration }
onchange= ${ (e) => updateState ('vibration.acceleration' , Number (e. target . value ))}
style="width: 100%;">
<div style="display: flex; justify-content: space-between; font-size: 11px; color: ${ ieeeColors. gray } ;">
<span>0.01g (subtle)</span>
<span>2g (heavy machinery)</span>
</div>
</div>
<div style="margin-bottom: 20px;">
<label style="display: block; font-weight: 600; margin-bottom: 8px; color: ${ ieeeColors. darkGray } ;">
Harvester Size
</label>
<select onchange= ${ (e) => updateState ('vibration.harvesterSize' , e. target . value )}
style="width: 100%; padding: 10px; border: 1px solid ${ ieeeColors. lightGray } ; border-radius: 6px;">
<option value="small" ${ state. vibration . harvesterSize === 'small' ? 'selected' : '' } >Small (1 cm³)</option>
<option value="medium" ${ state. vibration . harvesterSize === 'medium' ? 'selected' : '' } >Medium (5 cm³)</option>
<option value="large" ${ state. vibration . harvesterSize === 'large' ? 'selected' : '' } >Large (20 cm³)</option>
</select>
</div>
<div style="margin-bottom: 10px;">
<label style="display: block; font-weight: 600; margin-bottom: 8px; color: ${ ieeeColors. darkGray } ;">
Available Hours/Day: ${ state. vibration . availableHours } hours
</label>
<input type="range" min="1" max="24" value= ${ state. vibration . availableHours }
onchange= ${ (e) => updateState ('vibration.availableHours' , Number (e. target . value ))}
style="width: 100%;">
</div>
</div>
` : '' }
<!-- Thermal Configuration -->
${ state. sources . thermal ? html `
<div style="border: 1px solid ${ ieeeColors. lightGray } ; border-radius: 12px; padding: 20px;">
<h4 style="color: ${ ieeeColors. navy } ; margin: 0 0 20px 0; display: flex; align-items: center; gap: 8px;">
🌡️ Thermal (TEG) Configuration
</h4>
<div style="margin-bottom: 20px;">
<label style="display: block; font-weight: 600; margin-bottom: 8px; color: ${ ieeeColors. darkGray } ;">
Temperature Differential: ${ state. thermal . deltaT } °C
</label>
<input type="range" min="1" max="100" value= ${ state. thermal . deltaT }
onchange= ${ (e) => updateState ('thermal.deltaT' , Number (e. target . value ))}
style="width: 100%;">
<div style="display: flex; justify-content: space-between; font-size: 11px; color: ${ ieeeColors. gray } ;">
<span>1°C (body heat)</span>
<span>100°C (industrial)</span>
</div>
</div>
<div style="margin-bottom: 20px;">
<label style="display: block; font-weight: 600; margin-bottom: 8px; color: ${ ieeeColors. darkGray } ;">
TEG Module Area: ${ state. thermal . tegArea } cm²
</label>
<input type="range" min="1" max="100" value= ${ state. thermal . tegArea }
onchange= ${ (e) => updateState ('thermal.tegArea' , Number (e. target . value ))}
style="width: 100%;">
<div style="display: flex; justify-content: space-between; font-size: 11px; color: ${ ieeeColors. gray } ;">
<span>1 cm² (tiny)</span>
<span>100 cm² (large)</span>
</div>
</div>
<div style="margin-bottom: 20px;">
<label style="display: block; font-weight: 600; margin-bottom: 8px; color: ${ ieeeColors. darkGray } ;">
TEG Efficiency: ${ state. thermal . tegEfficiency } %
</label>
<input type="range" min="1" max="10" step="0.5" value= ${ state. thermal . tegEfficiency }
onchange= ${ (e) => updateState ('thermal.tegEfficiency' , Number (e. target . value ))}
style="width: 100%;">
<div style="display: flex; justify-content: space-between; font-size: 11px; color: ${ ieeeColors. gray } ;">
<span>1% (low-cost)</span>
<span>10% (optimized)</span>
</div>
</div>
<div style="margin-bottom: 10px;">
<label style="display: block; font-weight: 600; margin-bottom: 8px; color: ${ ieeeColors. darkGray } ;">
Available Hours/Day: ${ state. thermal . availableHours } hours
</label>
<input type="range" min="1" max="24" value= ${ state. thermal . availableHours }
onchange= ${ (e) => updateState ('thermal.availableHours' , Number (e. target . value ))}
style="width: 100%;">
</div>
</div>
` : '' }
<!-- RF Configuration -->
${ state. sources . rf ? html `
<div style="border: 1px solid ${ ieeeColors. lightGray } ; border-radius: 12px; padding: 20px;">
<h4 style="color: ${ ieeeColors. navy } ; margin: 0 0 20px 0; display: flex; align-items: center; gap: 8px;">
📡 RF Harvesting Configuration
</h4>
<div style="margin-bottom: 20px;">
<label style="display: block; font-weight: 600; margin-bottom: 8px; color: ${ ieeeColors. darkGray } ;">
RF Source Frequency: ${ state. rf . frequency } MHz
</label>
<select onchange= ${ (e) => updateState ('rf.frequency' , Number (e. target . value ))}
style="width: 100%; padding: 10px; border: 1px solid ${ ieeeColors. lightGray } ; border-radius: 6px;">
<option value="433" ${ state. rf . frequency === 433 ? 'selected' : '' } >433 MHz (ISM)</option>
<option value="868" ${ state. rf . frequency === 868 ? 'selected' : '' } >868 MHz (LoRa EU)</option>
<option value="915" ${ state. rf . frequency === 915 ? 'selected' : '' } >915 MHz (LoRa US)</option>
<option value="2400" ${ state. rf . frequency === 2400 ? 'selected' : '' } >2.4 GHz (Wi-Fi/BLE)</option>
<option value="5800" ${ state. rf . frequency === 5800 ? 'selected' : '' } >5.8 GHz (Wi-Fi)</option>
</select>
</div>
<div style="margin-bottom: 20px;">
<label style="display: block; font-weight: 600; margin-bottom: 8px; color: ${ ieeeColors. darkGray } ;">
Power Density: ${ state. rf . powerDensity } µW/cm²
</label>
<input type="range" min="0.001" max="10" step="0.001" value= ${ state. rf . powerDensity }
onchange= ${ (e) => updateState ('rf.powerDensity' , Number (e. target . value ))}
style="width: 100%;">
<div style="display: flex; justify-content: space-between; font-size: 11px; color: ${ ieeeColors. gray } ;">
<span>0.001 µW/cm² (far)</span>
<span>10 µW/cm² (near TX)</span>
</div>
</div>
<div style="margin-bottom: 20px;">
<label style="display: block; font-weight: 600; margin-bottom: 8px; color: ${ ieeeColors. darkGray } ;">
Antenna Gain: ${ state. rf . antennaGain } dBi
</label>
<input type="range" min="0" max="12" step="0.5" value= ${ state. rf . antennaGain }
onchange= ${ (e) => updateState ('rf.antennaGain' , Number (e. target . value ))}
style="width: 100%;">
</div>
<div style="margin-bottom: 20px;">
<label style="display: block; font-weight: 600; margin-bottom: 8px; color: ${ ieeeColors. darkGray } ;">
Effective Antenna Area: ${ state. rf . antennaArea } cm²
</label>
<input type="range" min="1" max="100" value= ${ state. rf . antennaArea }
onchange= ${ (e) => updateState ('rf.antennaArea' , Number (e. target . value ))}
style="width: 100%;">
</div>
<div style="margin-bottom: 10px;">
<label style="display: block; font-weight: 600; margin-bottom: 8px; color: ${ ieeeColors. darkGray } ;">
Available Hours/Day: ${ state. rf . availableHours } hours
</label>
<input type="range" min="1" max="24" value= ${ state. rf . availableHours }
onchange= ${ (e) => updateState ('rf.availableHours' , Number (e. target . value ))}
style="width: 100%;">
</div>
</div>
` : '' }
</div>
${ ! state. sources . solar && ! state. sources . vibration && ! state. sources . thermal && ! state. sources . rf ? html `
<div style="text-align: center; padding: 60px 20px; color: ${ ieeeColors. gray } ;">
<p style="font-size: 48px; margin-bottom: 20px;">⚡</p>
<h4 style="color: ${ ieeeColors. navy } ;">No Energy Sources Selected</h4>
<p>Go to the "Source Selection" tab to choose your energy harvesting sources.</p>
</div>
` : '' }
</div>
` ;
}
Show code
devicePowerPanel = {
if (activeTab !== "Device Power" ) return html `` ;
const state = harvesterState;
return html `
<div style="padding: 20px; font-family: system-ui, sans-serif;">
<h3 style="color: ${ ieeeColors. navy } ; margin-bottom: 20px;">
Device Power Requirements
</h3>
<div style="display: grid; grid-template-columns: repeat(auto-fit, minmax(350px, 1fr)); gap: 25px;">
<!-- Power Consumption -->
<div style="border: 1px solid ${ ieeeColors. lightGray } ; border-radius: 12px; padding: 20px;">
<h4 style="color: ${ ieeeColors. navy } ; margin: 0 0 20px 0;">
⚡ Power Consumption
</h4>
<div style="margin-bottom: 20px;">
<label style="display: block; font-weight: 600; margin-bottom: 8px; color: ${ ieeeColors. darkGray } ;">
Operating Voltage: ${ state. device . voltage } V
</label>
<input type="range" min="1.8" max="5" step="0.1" value= ${ state. device . voltage }
onchange= ${ (e) => updateState ('device.voltage' , Number (e. target . value ))}
style="width: 100%;">
<div style="display: flex; justify-content: space-between; font-size: 11px; color: ${ ieeeColors. gray } ;">
<span>1.8V</span>
<span>5V</span>
</div>
</div>
<div style="margin-bottom: 20px;">
<label style="display: block; font-weight: 600; margin-bottom: 8px; color: ${ ieeeColors. darkGray } ;">
Sleep Current: ${ state. device . sleepCurrent } µA
</label>
<input type="range" min="0.1" max="100" step="0.1" value= ${ state. device . sleepCurrent }
onchange= ${ (e) => updateState ('device.sleepCurrent' , Number (e. target . value ))}
style="width: 100%;">
<div style="display: flex; justify-content: space-between; font-size: 11px; color: ${ ieeeColors. gray } ;">
<span>0.1 µA (ultra-low)</span>
<span>100 µA</span>
</div>
</div>
<div style="margin-bottom: 20px;">
<label style="display: block; font-weight: 600; margin-bottom: 8px; color: ${ ieeeColors. darkGray } ;">
Active Current: ${ state. device . activeCurrent } mA
</label>
<input type="range" min="0.1" max="100" step="0.1" value= ${ state. device . activeCurrent }
onchange= ${ (e) => updateState ('device.activeCurrent' , Number (e. target . value ))}
style="width: 100%;">
<div style="display: flex; justify-content: space-between; font-size: 11px; color: ${ ieeeColors. gray } ;">
<span>0.1 mA</span>
<span>100 mA</span>
</div>
</div>
<div style="margin-bottom: 20px;">
<label style="display: block; font-weight: 600; margin-bottom: 8px; color: ${ ieeeColors. darkGray } ;">
Peak Power: ${ state. device . peakPower } mW
</label>
<input type="range" min="10" max="1000" step="10" value= ${ state. device . peakPower }
onchange= ${ (e) => updateState ('device.peakPower' , Number (e. target . value ))}
style="width: 100%;">
<div style="display: flex; justify-content: space-between; font-size: 11px; color: ${ ieeeColors. gray } ;">
<span>10 mW</span>
<span>1000 mW (TX burst)</span>
</div>
</div>
<div style="margin-bottom: 10px;">
<label style="display: block; font-weight: 600; margin-bottom: 8px; color: ${ ieeeColors. darkGray } ;">
Peak Duration: ${ state. device . peakDuration } ms
</label>
<input type="range" min="1" max="1000" value= ${ state. device . peakDuration }
onchange= ${ (e) => updateState ('device.peakDuration' , Number (e. target . value ))}
style="width: 100%;">
</div>
</div>
<!-- Duty Cycle Configuration -->
<div style="border: 1px solid ${ ieeeColors. lightGray } ; border-radius: 12px; padding: 20px;">
<h4 style="color: ${ ieeeColors. navy } ; margin: 0 0 20px 0;">
🔄 Duty Cycle & Timing
</h4>
<div style="margin-bottom: 20px;">
<label style="display: block; font-weight: 600; margin-bottom: 8px; color: ${ ieeeColors. darkGray } ;">
Duty Cycle: ${ state. device . dutyCycle } %
</label>
<input type="range" min="0.01" max="100" step="0.01" value= ${ state. device . dutyCycle }
onchange= ${ (e) => updateState ('device.dutyCycle' , Number (e. target . value ))}
style="width: 100%;">
<div style="display: flex; justify-content: space-between; font-size: 11px; color: ${ ieeeColors. gray } ;">
<span>0.01% (rare wakeup)</span>
<span>100% (always on)</span>
</div>
</div>
<div style="margin-bottom: 20px;">
<label style="display: block; font-weight: 600; margin-bottom: 8px; color: ${ ieeeColors. darkGray } ;">
Wakeup Interval: ${ state. device . wakeupInterval } seconds
</label>
<input type="range" min="1" max="3600" value= ${ state. device . wakeupInterval }
onchange= ${ (e) => updateState ('device.wakeupInterval' , Number (e. target . value ))}
style="width: 100%;">
<div style="display: flex; justify-content: space-between; font-size: 11px; color: ${ ieeeColors. gray } ;">
<span>1 sec</span>
<span>1 hour</span>
</div>
</div>
<div style="margin-bottom: 20px;">
<label style="display: block; font-weight: 600; margin-bottom: 8px; color: ${ ieeeColors. darkGray } ;">
Required Autonomy: ${ state. device . requiredAutonomy } days
</label>
<input type="range" min="1" max="30" value= ${ state. device . requiredAutonomy }
onchange= ${ (e) => updateState ('device.requiredAutonomy' , Number (e. target . value ))}
style="width: 100%;">
<div style="display: flex; justify-content: space-between; font-size: 11px; color: ${ ieeeColors. gray } ;">
<span>1 day</span>
<span>30 days</span>
</div>
<p style="font-size: 12px; color: ${ ieeeColors. gray } ; margin-top: 5px;">
Days the device must operate without any energy harvesting
</p>
</div>
<!-- Calculated Values -->
<div style="background: ${ ieeeColors. lightGray } ; padding: 15px; border-radius: 8px; margin-top: 20px;">
<h5 style="margin: 0 0 10px 0; color: ${ ieeeColors. navy } ;">Calculated Power Profile</h5>
<div style="font-size: 13px; color: ${ ieeeColors. darkGray } ;">
<p style="margin: 5px 0;"><strong>Sleep Power:</strong> ${ (state. device . sleepCurrent * state. device . voltage / 1000 ). toFixed (3 )} mW</p>
<p style="margin: 5px 0;"><strong>Active Power:</strong> ${ (state. device . activeCurrent * state. device . voltage ). toFixed (2 )} mW</p>
<p style="margin: 5px 0;"><strong>Average Power:</strong> ${ calculateAveragePower (state). toFixed (3 )} mW</p>
<p style="margin: 5px 0;"><strong>Daily Energy:</strong> ${ (calculateAveragePower (state) * 24 ). toFixed (2 )} mWh</p>
</div>
</div>
</div>
<!-- Storage Configuration -->
<div style="border: 1px solid ${ ieeeColors. lightGray } ; border-radius: 12px; padding: 20px;">
<h4 style="color: ${ ieeeColors. navy } ; margin: 0 0 20px 0;">
🔋 Energy Storage
</h4>
<div style="margin-bottom: 20px;">
<label style="display: block; font-weight: 600; margin-bottom: 8px; color: ${ ieeeColors. darkGray } ;">
Storage Type
</label>
<select onchange= ${ (e) => updateState ('storage.type' , e. target . value )}
style="width: 100%; padding: 10px; border: 1px solid ${ ieeeColors. lightGray } ; border-radius: 6px;">
<option value="supercap" ${ state. storage . type === 'supercap' ? 'selected' : '' } >Supercapacitor Only</option>
<option value="battery" ${ state. storage . type === 'battery' ? 'selected' : '' } >Battery Only</option>
<option value="hybrid" ${ state. storage . type === 'hybrid' ? 'selected' : '' } >Hybrid (Supercap + Battery)</option>
</select>
</div>
${ state. storage . type !== 'battery' ? html `
<div style="margin-bottom: 20px;">
<label style="display: block; font-weight: 600; margin-bottom: 8px; color: ${ ieeeColors. darkGray } ;">
Supercapacitor Size: ${ state. storage . supercapSize } F
</label>
<input type="range" min="0.1" max="10" step="0.1" value= ${ state. storage . supercapSize }
onchange= ${ (e) => updateState ('storage.supercapSize' , Number (e. target . value ))}
style="width: 100%;">
</div>
` : '' }
${ state. storage . type !== 'supercap' ? html `
<div style="margin-bottom: 20px;">
<label style="display: block; font-weight: 600; margin-bottom: 8px; color: ${ ieeeColors. darkGray } ;">
Battery Capacity: ${ state. storage . batteryCapacity } mAh
</label>
<input type="range" min="10" max="5000" step="10" value= ${ state. storage . batteryCapacity }
onchange= ${ (e) => updateState ('storage.batteryCapacity' , Number (e. target . value ))}
style="width: 100%;">
</div>
<div style="margin-bottom: 20px;">
<label style="display: block; font-weight: 600; margin-bottom: 8px; color: ${ ieeeColors. darkGray } ;">
Battery Voltage: ${ state. storage . batteryVoltage } V
</label>
<input type="range" min="1.5" max="7.4" step="0.1" value= ${ state. storage . batteryVoltage }
onchange= ${ (e) => updateState ('storage.batteryVoltage' , Number (e. target . value ))}
style="width: 100%;">
</div>
` : '' }
<div style="margin-bottom: 20px;">
<label style="display: block; font-weight: 600; margin-bottom: 8px; color: ${ ieeeColors. darkGray } ;">
Operating Voltage Range: ${ state. storage . minVoltage } V - ${ state. storage . maxVoltage } V
</label>
<div style="display: flex; gap: 10px;">
<input type="number" step="0.1" value= ${ state. storage . minVoltage }
onchange= ${ (e) => updateState ('storage.minVoltage' , Number (e. target . value ))}
style="flex: 1; padding: 8px; border: 1px solid ${ ieeeColors. lightGray } ; border-radius: 4px;">
<span style="padding: 8px;">to</span>
<input type="number" step="0.1" value= ${ state. storage . maxVoltage }
onchange= ${ (e) => updateState ('storage.maxVoltage' , Number (e. target . value ))}
style="flex: 1; padding: 8px; border: 1px solid ${ ieeeColors. lightGray } ; border-radius: 4px;">
</div>
</div>
<!-- Storage Capacity Info -->
<div style="background: ${ ieeeColors. lightGray } ; padding: 15px; border-radius: 8px; margin-top: 20px;">
<h5 style="margin: 0 0 10px 0; color: ${ ieeeColors. navy } ;">Storage Capacity</h5>
<div style="font-size: 13px; color: ${ ieeeColors. darkGray } ;">
${ state. storage . type !== 'battery' ? html `
<p style="margin: 5px 0;">
<strong>Supercap Energy:</strong>
${ (0.5 * state. storage . supercapSize * (Math . pow (state. storage . maxVoltage , 2 ) - Math . pow (state. storage . minVoltage , 2 )) / 3.6 ). toFixed (2 )} mWh
</p>
` : '' }
${ state. storage . type !== 'supercap' ? html `
<p style="margin: 5px 0;">
<strong>Battery Energy:</strong>
${ (state. storage . batteryCapacity * state. storage . batteryVoltage ). toFixed (0 )} mWh
</p>
` : '' }
<p style="margin: 5px 0;">
<strong>Total Usable:</strong> ${ calculateTotalStorage (state). toFixed (1 )} mWh
</p>
</div>
</div>
</div>
</div>
</div>
` ;
}
// Helper function for average power
function calculateAveragePower (state) {
const sleepPower = state. device . sleepCurrent * state. device . voltage / 1000 ; // mW
const activePower = state. device . activeCurrent * state. device . voltage ; // mW
const dutyCycle = state. device . dutyCycle / 100 ;
return sleepPower * (1 - dutyCycle) + activePower * dutyCycle;
}
// Helper function for total storage
function calculateTotalStorage (state) {
let total = 0 ;
if (state. storage . type !== 'battery' ) {
// Supercap energy: E = 0.5 * C * (V_max^2 - V_min^2)
total += 0.5 * state. storage . supercapSize *
(Math . pow (state. storage . maxVoltage , 2 ) - Math . pow (state. storage . minVoltage , 2 )) / 3.6 ; // Convert J to mWh
}
if (state. storage . type !== 'supercap' ) {
total += state. storage . batteryCapacity * state. storage . batteryVoltage ;
}
return total;
}
Summary
This calculator tool helps you configure:
Energy Sources : Select from solar, vibration, thermal, and RF harvesting
Environment Settings : Configure harvester-specific parameters
Device Requirements : Define power consumption and duty cycle
Storage Options : Size supercapacitors and batteries appropriately
After configuring your harvester, proceed to:
What’s Next
Continue to the Energy Harvesting Analysis chapter to see detailed power calculations, self-sufficiency analysis, and pre-configured application scenarios.