import Foundation import Logging import OrderedCollections import Routes public extension Capacitor.Request { static let standardCapacitorSizes = OrderedSet([ 5, 7.5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 70, 80 ]) func respond(logger: Logger) async throws -> Capacitor.Response { switch self { case let .size(request): return try calculateSize(request, logger) case let .test(request): return try calculateCapcitance(request, logger) } } private func calculateCapcitance( _ request: Capacitor.Request.TestRequest, _ logger: Logger ) throws -> Capacitor.Response { try request.validate() let capacitance = (2653 * request.startWindingAmps) / request.runToCommonVoltage logger.debug("Test Capacitor calculated capacitance: \(capacitance)") var ratedComparison: Capacitor.RatedComparison? if let rating = request.ratedCapacitorSize { let rating = Double(rating) let deviation = ((capacitance - rating) / rating) * 100.0 logger.debug("Test Capacitor calculated deviation: \(deviation)") // let positiveDeviation = deviation.ensurePostive() ratedComparison = .init( value: Int(rating), isInRange: abs(deviation) <= 6, percentDeviation: deviation ) } return .test(result: .init( capacitance: capacitance, tolerance: .init(capacitance: capacitance), ratedComparison: ratedComparison )) } private func calculateSize( _ request: Capacitor.Request.SizeRequest, _ logger: Logger ) throws -> Capacitor.Response { try request.validate() let frequency = 60.0 let phaseAngle = acos(request.powerFactor) let reactiveComponent = request.runningAmps * sin(phaseAngle) let capacitance = (reactiveComponent * 1_000_000) / (2 * Double.pi * frequency * request.lineVoltage) logger.debug("Calculate capacitor size capacitance: \(capacitance)") let standardSize = Self.standardCapacitorSizes.first(where: { $0 >= capacitance }) ?? Self.standardCapacitorSizes.last! logger.debug("Calculate capacitor standard size: \(standardSize)") return .size(result: .init( capacitance: capacitance, standardSize: standardSize, tolerance: .init(capacitance: capacitance) )) } } private extension Capacitor.Tolerance { init(capacitance: Double) { // +- 6% tolerance self.init( minimum: capacitance * 0.96, maximum: capacitance * 1.06 ) } } private extension Capacitor.Request.TestRequest { func validate() throws { guard startWindingAmps > 0 else { throw ValidationError(message: "Start winding amps should be greater than 0.") } guard runToCommonVoltage > 0 else { throw ValidationError(message: "Run to common voltage should be greater than 0.") } if let ratedCapacitorSize { guard ratedCapacitorSize > 0 else { throw ValidationError(message: "Run to common voltage should be greater than 0.") } } } } private extension Capacitor.Request.SizeRequest { func validate() throws { guard runningAmps > 0 else { throw ValidationError(message: "Running amps should be greater than 0.") } guard lineVoltage > 0 else { throw ValidationError(message: "Line voltage should be greater than 0.") } guard powerFactor > 0, powerFactor < 1.01 else { throw ValidationError(message: "powerFactor should be greater than 0 and at max 1.") } } }