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**
|
||||
>
|
||||
> 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)
|
||||
|
||||
Key findings:
|
||||
@ -60,14 +60,6 @@ Each cell requires:
|
||||
- **Capacity**: Measured capacity in mAh
|
||||
- **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
|
||||
|
||||
- **Capacity Weight**: Importance of matching parallel group capacities
|
||||
|
||||
@ -368,11 +368,7 @@ function updateProgress(progress) {
|
||||
DOM.progressSpeed.textContent = `${formatNumber(Math.round(progress.iterationsPerSecond))}/s`;
|
||||
}
|
||||
|
||||
if (progress.eta > 0 && progress.eta < Infinity) {
|
||||
DOM.progressEta.textContent = formatDuration(progress.eta);
|
||||
} else if (progress.iteration >= progress.maxIterations * 0.9) {
|
||||
DOM.progressEta.textContent = 'Almost done...';
|
||||
}
|
||||
DOM.progressEta.textContent = formatDuration(progress.eta);
|
||||
|
||||
if (progress.currentBest && progress.currentBest.config) {
|
||||
renderLivePreview(progress.currentBest.config);
|
||||
|
||||
@ -102,36 +102,51 @@ function calculateScore(configuration, capacityWeight = 0.7, irWeight = 0.3) {
|
||||
class StatsTracker {
|
||||
constructor() {
|
||||
this.startTime = Date.now();
|
||||
this.iterationTimes = [];
|
||||
this.lastIterationTime = this.startTime;
|
||||
this.windowSize = 100; // Rolling window for time estimates
|
||||
}
|
||||
|
||||
recordIteration() {
|
||||
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();
|
||||
}
|
||||
this.lastProgressTime = this.startTime;
|
||||
this.lastProgressIteration = 0;
|
||||
this.speedHistory = [];
|
||||
this.windowSize = 5; // Rolling window for speed averaging
|
||||
this.lastEta = null;
|
||||
this.lastEtaUpdate = 0;
|
||||
}
|
||||
|
||||
getStats(currentIteration, maxIterations) {
|
||||
const elapsedTime = Date.now() - this.startTime;
|
||||
const avgIterTime = this.iterationTimes.length > 0
|
||||
? this.iterationTimes.reduce((a, b) => a + b, 0) / this.iterationTimes.length
|
||||
const now = Date.now();
|
||||
const elapsedTime = now - this.startTime;
|
||||
|
||||
// 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;
|
||||
|
||||
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 {
|
||||
elapsedTime,
|
||||
avgIterTime,
|
||||
eta,
|
||||
iterationsPerSecond: avgIterTime > 0 ? 1000 / avgIterTime : 0
|
||||
eta: this.lastEta,
|
||||
iterationsPerSecond: avgSpeed
|
||||
};
|
||||
}
|
||||
}
|
||||
@ -249,24 +264,28 @@ class ExhaustiveSearch {
|
||||
}
|
||||
|
||||
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) {
|
||||
const stats = this.stats.getStats(iteration, Math.min(totalCombinations, this.maxIterations));
|
||||
const now = Date.now();
|
||||
const timeSinceLastProgress = now - this.stats.lastProgressTime;
|
||||
|
||||
self.postMessage({
|
||||
type: 'progress',
|
||||
data: {
|
||||
iteration,
|
||||
maxIterations: Math.min(totalCombinations, this.maxIterations),
|
||||
bestScore: this.bestScore,
|
||||
currentBest: this.bestSolution,
|
||||
totalCombinations,
|
||||
evaluatedCombinations: iteration,
|
||||
...stats
|
||||
}
|
||||
});
|
||||
if (timeSinceLastProgress >= 200) {
|
||||
const stats = this.stats.getStats(iteration, Math.min(totalCombinations, this.maxIterations));
|
||||
|
||||
self.postMessage({
|
||||
type: 'progress',
|
||||
data: {
|
||||
iteration,
|
||||
maxIterations: Math.min(totalCombinations, this.maxIterations),
|
||||
bestScore: this.bestScore,
|
||||
currentBest: this.bestSolution,
|
||||
totalCombinations,
|
||||
evaluatedCombinations: iteration,
|
||||
...stats
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if (iteration >= this.maxIterations) {
|
||||
|
||||
Reference in New Issue
Block a user