fix speed and ETA
This commit is contained in:
10
README.md
10
README.md
@ -23,7 +23,7 @@ This tool implements cell matching algorithms based on research findings about l
|
|||||||
|
|
||||||
> **Internal resistance matching for parallel-connected lithium-ion cells and impacts on battery pack cycle life**
|
> **Internal resistance matching for parallel-connected lithium-ion cells and impacts on battery pack cycle life**
|
||||||
>
|
>
|
||||||
> Shi et al., Journal of Power Sources (2013)
|
> Wang et al., Journal of Power Sources (2013)
|
||||||
> DOI: [10.1016/j.jpowsour.2013.11.064](https://doi.org/10.1016/j.jpowsour.2013.11.064)
|
> DOI: [10.1016/j.jpowsour.2013.11.064](https://doi.org/10.1016/j.jpowsour.2013.11.064)
|
||||||
|
|
||||||
Key findings:
|
Key findings:
|
||||||
@ -60,14 +60,6 @@ Each cell requires:
|
|||||||
- **Capacity**: Measured capacity in mAh
|
- **Capacity**: Measured capacity in mAh
|
||||||
- **Internal Resistance** (optional): Measured IR in mΩ
|
- **Internal Resistance** (optional): Measured IR in mΩ
|
||||||
|
|
||||||
### Algorithm Selection
|
|
||||||
|
|
||||||
| Algorithm | Best For | Speed |
|
|
||||||
|-----------|----------|-------|
|
|
||||||
| Genetic Algorithm | Most cases, large pools | Fast |
|
|
||||||
| Simulated Annealing | Avoiding local optima | Medium |
|
|
||||||
| Exhaustive | Small configs (<8 cells) | Slow |
|
|
||||||
|
|
||||||
### Matching Weights
|
### Matching Weights
|
||||||
|
|
||||||
- **Capacity Weight**: Importance of matching parallel group capacities
|
- **Capacity Weight**: Importance of matching parallel group capacities
|
||||||
|
|||||||
@ -368,11 +368,7 @@ function updateProgress(progress) {
|
|||||||
DOM.progressSpeed.textContent = `${formatNumber(Math.round(progress.iterationsPerSecond))}/s`;
|
DOM.progressSpeed.textContent = `${formatNumber(Math.round(progress.iterationsPerSecond))}/s`;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (progress.eta > 0 && progress.eta < Infinity) {
|
|
||||||
DOM.progressEta.textContent = formatDuration(progress.eta);
|
DOM.progressEta.textContent = formatDuration(progress.eta);
|
||||||
} else if (progress.iteration >= progress.maxIterations * 0.9) {
|
|
||||||
DOM.progressEta.textContent = 'Almost done...';
|
|
||||||
}
|
|
||||||
|
|
||||||
if (progress.currentBest && progress.currentBest.config) {
|
if (progress.currentBest && progress.currentBest.config) {
|
||||||
renderLivePreview(progress.currentBest.config);
|
renderLivePreview(progress.currentBest.config);
|
||||||
|
|||||||
@ -102,36 +102,51 @@ function calculateScore(configuration, capacityWeight = 0.7, irWeight = 0.3) {
|
|||||||
class StatsTracker {
|
class StatsTracker {
|
||||||
constructor() {
|
constructor() {
|
||||||
this.startTime = Date.now();
|
this.startTime = Date.now();
|
||||||
this.iterationTimes = [];
|
this.lastProgressTime = this.startTime;
|
||||||
this.lastIterationTime = this.startTime;
|
this.lastProgressIteration = 0;
|
||||||
this.windowSize = 100; // Rolling window for time estimates
|
this.speedHistory = [];
|
||||||
}
|
this.windowSize = 5; // Rolling window for speed averaging
|
||||||
|
this.lastEta = null;
|
||||||
recordIteration() {
|
this.lastEtaUpdate = 0;
|
||||||
const now = Date.now();
|
|
||||||
const iterTime = now - this.lastIterationTime;
|
|
||||||
this.lastIterationTime = now;
|
|
||||||
|
|
||||||
this.iterationTimes.push(iterTime);
|
|
||||||
if (this.iterationTimes.length > this.windowSize) {
|
|
||||||
this.iterationTimes.shift();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
getStats(currentIteration, maxIterations) {
|
getStats(currentIteration, maxIterations) {
|
||||||
const elapsedTime = Date.now() - this.startTime;
|
const now = Date.now();
|
||||||
const avgIterTime = this.iterationTimes.length > 0
|
const elapsedTime = now - this.startTime;
|
||||||
? this.iterationTimes.reduce((a, b) => a + b, 0) / this.iterationTimes.length
|
|
||||||
|
// Calculate speed based on iterations since last progress update
|
||||||
|
const iterationsDelta = currentIteration - this.lastProgressIteration;
|
||||||
|
const timeDelta = now - this.lastProgressTime;
|
||||||
|
|
||||||
|
if (timeDelta > 0 && iterationsDelta > 0) {
|
||||||
|
const currentSpeed = (iterationsDelta / timeDelta) * 1000; // iterations per second
|
||||||
|
this.speedHistory.push(currentSpeed);
|
||||||
|
if (this.speedHistory.length > this.windowSize) {
|
||||||
|
this.speedHistory.shift();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.lastProgressTime = now;
|
||||||
|
this.lastProgressIteration = currentIteration;
|
||||||
|
|
||||||
|
// Average speed from history
|
||||||
|
const avgSpeed = this.speedHistory.length > 0
|
||||||
|
? this.speedHistory.reduce((a, b) => a + b, 0) / this.speedHistory.length
|
||||||
: 0;
|
: 0;
|
||||||
|
|
||||||
const remainingIterations = maxIterations - currentIteration;
|
const remainingIterations = maxIterations - currentIteration;
|
||||||
const eta = avgIterTime * remainingIterations;
|
const eta = avgSpeed > 0 ? (remainingIterations / avgSpeed) * 1000 : 0;
|
||||||
|
|
||||||
|
// Only update ETA every 500ms to avoid flickering
|
||||||
|
if (now - this.lastEtaUpdate > 500 || this.lastEta === null) {
|
||||||
|
this.lastEta = eta;
|
||||||
|
this.lastEtaUpdate = now;
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
elapsedTime,
|
elapsedTime,
|
||||||
avgIterTime,
|
eta: this.lastEta,
|
||||||
eta,
|
iterationsPerSecond: avgSpeed
|
||||||
iterationsPerSecond: avgIterTime > 0 ? 1000 / avgIterTime : 0
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -249,10 +264,13 @@ class ExhaustiveSearch {
|
|||||||
}
|
}
|
||||||
|
|
||||||
iteration++;
|
iteration++;
|
||||||
this.stats.recordIteration();
|
|
||||||
|
|
||||||
// Check frequently for stop and send progress updates every 100 iterations
|
// Check for stop every 100 iterations, but only send progress updates every 200ms
|
||||||
if (iteration % 100 === 0) {
|
if (iteration % 100 === 0) {
|
||||||
|
const now = Date.now();
|
||||||
|
const timeSinceLastProgress = now - this.stats.lastProgressTime;
|
||||||
|
|
||||||
|
if (timeSinceLastProgress >= 200) {
|
||||||
const stats = this.stats.getStats(iteration, Math.min(totalCombinations, this.maxIterations));
|
const stats = this.stats.getStats(iteration, Math.min(totalCombinations, this.maxIterations));
|
||||||
|
|
||||||
self.postMessage({
|
self.postMessage({
|
||||||
@ -268,6 +286,7 @@ class ExhaustiveSearch {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (iteration >= this.maxIterations) {
|
if (iteration >= this.maxIterations) {
|
||||||
return this.returnBestResult(iteration, totalCombinations);
|
return this.returnBestResult(iteration, totalCombinations);
|
||||||
|
|||||||
Reference in New Issue
Block a user