25 enum MotorControlType {
44 Output(
const double annualEnergyBaseline,
const double annualEnergyNew,
const double annualCostSavings)
45 : annualEnergyBaseline(annualEnergyBaseline), annualEnergyNew(annualEnergyNew), annualCostSavings(annualCostSavings) {}
47 const double annualEnergyBaseline, annualEnergyNew, annualCostSavings;
68 double electricityCost;
69 double driveEfficiency, motorEfficiency, flowPercentBaseline;
70 double operatingHours, motorPower, ratedFlow;
71 MotorControlType motorControlTypeCurrent, motorControlTypeNew;
73 double desiredFlowRate;
81 input.operatingHours, input.motorPower, input.ratedFlow,
82 input.motorControlTypeCurrent, input.motorControlTypeNew,
83 input.flowMode, input.desiredFlowRate) {}
102 const double driveEfficiency,
const double motorEfficiency,
const double flowPercentBaseline,
103 const double operatingHours,
const double motorPower,
const double ratedFlow,
104 const MotorControlType motorControlTypeCurrent,
const MotorControlType motorControlTypeNew,
105 const FlowMode flowMode,
const double desiredFlowRate) : electricityCost(electricityCost),
106 driveEfficiency(driveEfficiency/100), motorEfficiency(motorEfficiency/100), flowPercentBaseline(flowPercentBaseline/100),
107 operatingHours(operatingHours), motorPower(motorPower), ratedFlow(ratedFlow),
108 motorControlTypeCurrent(motorControlTypeCurrent), motorControlTypeNew(motorControlTypeNew) {
109 if (electricityCost <= 0) {
110 throw std::invalid_argument(
"Electricity cost must be greater than 0.");
112 if (driveEfficiency <= 0 || driveEfficiency > 100) {
113 throw std::invalid_argument(
"Drive efficiency must be between 0 and 100.");
115 if (motorEfficiency <= 0 || motorEfficiency > 100) {
116 throw std::invalid_argument(
"Motor efficiency must be between 0 and 100.");
118 if (flowPercentBaseline < 0 || flowPercentBaseline > 100) {
119 throw std::invalid_argument(
"Flow percent baseline must be between 0 and 100.");
121 if (operatingHours <= 0 || operatingHours > 8760) {
122 throw std::invalid_argument(
"Operating hours must be between 1 and 8760.");
124 if (motorPower <= 0) {
125 throw std::invalid_argument(
"Motor power must be greater than 0.");
127 if (ratedFlow <= 0) {
128 throw std::invalid_argument(
"Rated flow must be greater than 0.");
131 if (flowMode == Percent) {
132 if (desiredFlowRate < 0 || desiredFlowRate > 100) {
133 throw std::invalid_argument(
"Desired flow rate percentage must be between 0 and 100.");
135 desiredFlowPercent = desiredFlowRate / 100.0;
136 desiredFlowVolume = desiredFlowRate * ratedFlow / 100.0;
137 }
else if (flowMode == Volume) {
138 if (desiredFlowRate < 0) {
139 throw std::invalid_argument(
"Desired flow rate volume must be greater than or equal to 0.");
141 desiredFlowVolume = desiredFlowRate;
142 desiredFlowPercent = desiredFlowRate / ratedFlow;
161 if (fanDiameterCurrent <= 0 || fanDiameter <= 0) {
162 throw std::invalid_argument(
"Fan diameters must be greater than 0.");
165 return compute(fanDiameter / fanDiameterCurrent);
169 const double electricityCost;
170 const double driveEfficiency, motorEfficiency, flowPercentBaseline;
171 const double operatingHours, motorPower, ratedFlow;
172 const MotorControlType motorControlTypeCurrent, motorControlTypeNew;
173 double desiredFlowPercent = 0, desiredFlowVolume = 0;
175 Output compute(
const double fanDiameterRatio)
const {
176 const double powerBaseline = motorPower / motorEfficiency / driveEfficiency;
178 double powerCurrent = powerBaseline;
179 if (motorControlTypeCurrent == VSD) {
180 powerCurrent *= std::pow(flowPercentBaseline, 3);
182 else if (motorControlTypeCurrent == TwoSpeed) {
183 powerCurrent = powerBaseline * get50PercentTimeFactor(flowPercentBaseline);
186 double powerNew = powerBaseline;
187 if (motorControlTypeNew == TwoSpeed) {
188 powerNew = powerBaseline * get50PercentTimeFactor(desiredFlowPercent);
191 if (fanDiameterRatio != 0) {
192 if (motorControlTypeNew == VSD) {
193 const auto fanRatedFlow = ratedFlow * std::pow(fanDiameterRatio, 3);
194 const auto newFlowPercent = desiredFlowVolume / fanRatedFlow;
195 powerNew = powerBaseline * std::pow(newFlowPercent, 3) * std::pow(fanDiameterRatio, 5);
197 else if (motorControlTypeNew == TwoSpeed) {
198 powerNew *= std::pow(fanDiameterRatio, 5);
201 powerNew = powerBaseline * std::pow(fanDiameterRatio, 5);
204 else if (motorControlTypeNew == VSD) {
205 powerNew = powerBaseline * std::pow(desiredFlowPercent, 3);
208 return {powerCurrent * operatingHours, powerNew * operatingHours,
209 (powerCurrent - powerNew) * operatingHours * electricityCost};
212 static double get50PercentTimeFactor(
const double flowPercent) {
213 const double timeAbove50Percent = (flowPercent - 0.5) / 0.5 < 0 ? 0 : (flowPercent - 0.5) / 0.5;
214 const double timeAt0Percent = (0.5 - flowPercent) / 0.5 < 0 ? 0 : (0.5 - flowPercent) / 0.5;
215 const double timeAt50Percent = 1 - timeAbove50Percent - timeAt0Percent;
217 return timeAbove50Percent + timeAt50Percent * 0.125;
FanAffinityLaws(const double electricityCost, const double driveEfficiency, const double motorEfficiency, const double flowPercentBaseline, const double operatingHours, const double motorPower, const double ratedFlow, const MotorControlType motorControlTypeCurrent, const MotorControlType motorControlTypeNew, const FlowMode flowMode, const double desiredFlowRate)