forked from RnD/machineGroupControl
138 lines
4.9 KiB
JavaScript
138 lines
4.9 KiB
JavaScript
/**
|
|
* This file implements a pump optimization algorithm that:
|
|
* 1. Models different pumps with efficiency characteristics
|
|
* 2. Determines all possible pump combinations that can meet a demand flow
|
|
* 3. Finds the optimal combination that minimizes power consumption
|
|
* 4. Tests the algorithm with different demand levels
|
|
*/
|
|
|
|
/**
|
|
* Pump Class
|
|
* Represents a pump with specific operating characteristics including:
|
|
* - Maximum flow capacity
|
|
* - Center of Gravity (CoG) for efficiency
|
|
* - Efficiency curve mapping flow percentages to power consumption
|
|
*/
|
|
class Pump {
|
|
constructor(name, maxFlow, cog, efficiencyCurve) {
|
|
this.name = name;
|
|
this.maxFlow = maxFlow; // Maximum flow at a given pressure
|
|
this.CoG = cog; // Efficiency center of gravity percentage
|
|
this.efficiencyCurve = efficiencyCurve; // Flow % -> Power usage mapping
|
|
}
|
|
|
|
/**
|
|
* Returns pump flow at a given pressure
|
|
* Currently assumes constant flow regardless of pressure
|
|
*/
|
|
getFlow(pressure) {
|
|
return this.maxFlow; // Assume constant flow at a given pressure
|
|
}
|
|
|
|
/**
|
|
* Calculates power consumption based on flow and pressure
|
|
* Uses the efficiency curve when available, otherwise uses linear approximation
|
|
*/
|
|
getPowerConsumption(flow, pressure) {
|
|
let flowPercent = flow / this.maxFlow;
|
|
return this.efficiencyCurve[flowPercent] || (1.2 * flow); // Default linear approximation
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Test pump definitions
|
|
* Three pump models with different flow capacities and efficiency characteristics
|
|
*/
|
|
const pumps = [
|
|
new Pump("Pump A", 100, 0.6, {0.6: 50, 0.8: 70, 1.0: 100}),
|
|
new Pump("Pump B", 120, 0.7, {0.6: 55, 0.8: 75, 1.0: 110}),
|
|
new Pump("Pump C", 90, 0.5, {0.5: 40, 0.7: 60, 1.0: 90}),
|
|
];
|
|
|
|
const pressure = 1.0; // Assume constant pressure
|
|
|
|
/**
|
|
* Get all valid pump combinations that meet the required demand flow (Qd)
|
|
*
|
|
* @param {Array} pumps - Available pump array
|
|
* @param {Number} Qd - Required demand flow
|
|
* @param {Number} pressure - System pressure
|
|
* @returns {Array} Array of valid pump combinations that can meet or exceed the demand
|
|
*
|
|
* This function:
|
|
* 1. Generates all possible subsets of pumps (power set)
|
|
* 2. Filters for non-empty subsets that can meet or exceed demand flow
|
|
*/
|
|
function getValidPumpCombinations(pumps, Qd, pressure) {
|
|
let subsets = [[]];
|
|
for (let pump of pumps) {
|
|
let newSubsets = subsets.map(set => [...set, pump]);
|
|
subsets = subsets.concat(newSubsets);
|
|
}
|
|
return subsets.filter(subset => subset.length > 0 &&
|
|
subset.reduce((sum, p) => sum + p.getFlow(pressure), 0) >= Qd);
|
|
}
|
|
|
|
/**
|
|
* Find the optimal pump combination that minimizes power consumption
|
|
*
|
|
* @param {Array} pumps - Available pump array
|
|
* @param {Number} Qd - Required demand flow
|
|
* @param {Number} pressure - System pressure
|
|
* @returns {Object} Object containing the best pump combination and its power consumption
|
|
*
|
|
* This function:
|
|
* 1. Gets all valid pump combinations that meet demand
|
|
* 2. For each combination, distributes flow based on CoG proportions
|
|
* 3. Calculates total power consumption for each distribution
|
|
* 4. Returns the combination with minimum power consumption
|
|
*/
|
|
function optimizePumpSelection(pumps, Qd, pressure) {
|
|
let validCombinations = getValidPumpCombinations(pumps, Qd, pressure);
|
|
let bestCombination = null;
|
|
let minPower = Infinity;
|
|
|
|
validCombinations.forEach(combination => {
|
|
let totalFlow = combination.reduce((sum, pump) => sum + pump.getFlow(pressure), 0);
|
|
let totalCoG = combination.reduce((sum, pump) => sum + pump.CoG, 0);
|
|
|
|
// Distribute flow based on CoG proportions
|
|
let flowDistribution = combination.map(pump => ({
|
|
pump,
|
|
flow: (pump.CoG / totalCoG) * Qd
|
|
}));
|
|
|
|
let totalPower = flowDistribution.reduce((sum, { pump, flow }) =>
|
|
sum + pump.getPowerConsumption(flow, pressure), 0);
|
|
|
|
if (totalPower < minPower) {
|
|
minPower = totalPower;
|
|
bestCombination = flowDistribution;
|
|
}
|
|
});
|
|
|
|
return { bestCombination, minPower };
|
|
}
|
|
|
|
/**
|
|
* Test function that runs optimization for different demand levels
|
|
* Tests from 0% to 100% of total available flow in 10% increments
|
|
* Outputs the selected pumps, flow allocation, and power consumption for each scenario
|
|
*/
|
|
console.log("Pump Optimization Results:");
|
|
const totalAvailableFlow = pumps.reduce((sum, pump) => sum + pump.getFlow(pressure), 0);
|
|
|
|
for (let i = 0; i <= 10; i++) {
|
|
let Qd = (i / 10) * totalAvailableFlow; // Incremental flow demand
|
|
let { bestCombination, minPower } = optimizePumpSelection(pumps, Qd, pressure);
|
|
|
|
console.log(`\nTotal Demand Flow: ${Qd.toFixed(2)}`);
|
|
console.log("Selected Pumps and Allocated Flow:");
|
|
|
|
bestCombination.forEach(({ pump, flow }) => {
|
|
console.log(` ${pump.name}: ${flow.toFixed(2)} units`);
|
|
});
|
|
|
|
console.log(`Total Power Consumption: ${minPower.toFixed(2)} kW`);
|
|
}
|