public void SimulateAeroProperties(out Vector3 aeroForce, out Vector3 aeroTorque, Vector3 velocityWorldVector, double altitude) { // Rodhern: It seems that this method, 'SimulateAeroProperties', is only used in FARAPI, which in turn can be used by say KSPTrajectories. // The parameter 'FARCenterQuery dummy' is from a code fix by Benjamin Chung (commit 18fbb9d29431679a4de9dfc22a443f400d2d4f8b). FARCenterQuery center = new FARCenterQuery(); FARCenterQuery dummy = new FARCenterQuery(); float pressure; float density; float temperature; float speedOfSound; CelestialBody body = vessel.mainBody; //Calculate main gas properties pressure = (float)body.GetPressure(altitude); temperature = (float)body.GetTemperature(altitude); density = (float)body.GetDensity(pressure, temperature); speedOfSound = (float)body.GetSpeedOfSound(pressure, density); if (pressure <= 0 || temperature <= 0 || density <= 0 || speedOfSound <= 0) { aeroForce = Vector3.zero; aeroTorque = Vector3.zero; return; } float velocityMag = velocityWorldVector.magnitude; float machNumber = velocityMag / speedOfSound; float reynoldsNumber = (float)FARAeroUtil.CalculateReynoldsNumber(density, Length, velocityMag, machNumber, temperature, body.atmosphereAdiabaticIndex); float reynoldsPerLength = reynoldsNumber / (float)Length; float pseudoKnudsenNumber = machNumber / (reynoldsNumber + machNumber); float skinFriction = (float)FARAeroUtil.SkinFrictionDrag(reynoldsNumber, machNumber); FlightEnv fenv = FlightEnv.NewPredicted(vessel.mainBody, altitude, machNumber); if (_currentAeroSections != null) { for (int i = 0; i < _currentAeroSections.Count; i++) { FARAeroSection curSection = _currentAeroSections[i]; if (curSection != null) { curSection.PredictionCalculateAeroForces(density, machNumber, reynoldsPerLength, pseudoKnudsenNumber, skinFriction, velocityWorldVector, center); } } for (int i = 0; i < _legacyWingModels.Count; i++) { FARWingAerodynamicModel curWing = _legacyWingModels[i]; if ((object)curWing != null) { Vector3d force = curWing.PrecomputeCenterOfLift(velocityWorldVector, fenv, dummy); center.AddForce(curWing.transform.position, force); } } } aeroForce = center.force; aeroTorque = center.TorqueAt(vessel.CoM); }
public void SimulateAeroProperties(out Vector3 aeroForce, out Vector3 aeroTorque, Vector3 velocityWorldVector, double altitude) { FARCenterQuery center = new FARCenterQuery(); float pressure; float density; float temperature; float speedOfSound; CelestialBody body = vessel.mainBody; //Calculate main gas properties pressure = (float)body.GetPressure(altitude); temperature = (float)body.GetTemperature(altitude); density = (float)body.GetDensity(pressure, temperature); speedOfSound = (float)body.GetSpeedOfSound(pressure, density); if (pressure <= 0 || temperature <= 0 || density <= 0 || speedOfSound <= 0) { aeroForce = Vector3.zero; aeroTorque = Vector3.zero; return; } float velocityMag = velocityWorldVector.magnitude; float machNumber = velocityMag / speedOfSound; float reynoldsNumber = (float)FARAeroUtil.CalculateReynoldsNumber(density, Length, velocityMag, machNumber, temperature, body.atmosphereAdiabaticIndex); float reynoldsPerLength = reynoldsNumber / (float)Length; float skinFriction = (float)FARAeroUtil.SkinFrictionDrag(reynoldsNumber, machNumber); float pseudoKnudsenNumber = machNumber / (reynoldsNumber + machNumber); if (_currentAeroSections != null) { for (int i = 0; i < _currentAeroSections.Count; i++) { FARAeroSection curSection = _currentAeroSections[i]; if (curSection != null) { curSection.PredictionCalculateAeroForces(density, machNumber, reynoldsPerLength, pseudoKnudsenNumber, skinFriction, velocityWorldVector, center); } } for (int i = 0; i < _legacyWingModels.Count; i++) { FARWingAerodynamicModel curWing = _legacyWingModels[i]; if ((object)curWing != null) { curWing.PrecomputeCenterOfLift(velocityWorldVector, machNumber, density, center); } } } aeroForce = center.force; aeroTorque = center.TorqueAt(vessel.CoM); }
private void CalculateAndApplyVesselAeroProperties() { float atmDensity = (float)vessel.atmDensity; if (atmDensity <= 0) { MachNumber = 0; ReynoldsNumber = 0; return; } MachNumber = vessel.mach; ReynoldsNumber = FARAeroUtil.CalculateReynoldsNumber(vessel.atmDensity, Length, vessel.srfSpeed, MachNumber, FlightGlobals.getExternalTemperature((float)vessel .altitude, vessel.mainBody), vessel.mainBody.atmosphereAdiabaticIndex); float skinFrictionDragCoefficient = (float)FARAeroUtil.SkinFrictionDrag(ReynoldsNumber, MachNumber); float pseudoKnudsenNumber = (float)(MachNumber / (ReynoldsNumber + MachNumber)); Vector3 frameVel = Krakensbane.GetFrameVelocityV3f(); //start from the top and come down to improve performance if it needs to remove anything for (int i = _currentAeroModules.Count - 1; i >= 0; i--) { FARAeroPartModule m = _currentAeroModules[i]; if (m != null && m.part != null && m.part.partTransform != null) { m.UpdateVelocityAndAngVelocity(frameVel); } else { _currentAeroModules.RemoveAt(i); } } foreach (FARAeroSection aeroSection in _currentAeroSections) { aeroSection.FlightCalculateAeroForces((float)MachNumber, (float)(ReynoldsNumber / Length), pseudoKnudsenNumber, skinFrictionDragCoefficient); } _vesselIntakeRamDrag.ApplyIntakeRamDrag((float)MachNumber, vessel.srf_velocity.normalized); foreach (FARAeroPartModule m in _currentAeroModules) { m.ApplyForces(); } }
private void CalculateAndApplyVesselAeroProperties() { float atmDensity = (float)_vessel.atmDensity; if (atmDensity <= 0) { machNumber = 0; reynoldsNumber = 0; return; } machNumber = _vessel.mach; reynoldsNumber = FARAeroUtil.CalculateReynoldsNumber(_vessel.atmDensity, Length, _vessel.srfSpeed, machNumber, FlightGlobals.getExternalTemperature((float)_vessel.altitude, _vessel.mainBody), _vessel.mainBody.atmosphereAdiabaticIndex); float skinFrictionDragCoefficient = (float)FARAeroUtil.SkinFrictionDrag(reynoldsNumber, machNumber); Vector3 frameVel = Krakensbane.GetFrameVelocityV3f(); if (_updateQueued) //only happens if we have an voxelization scheduled, then we need to check for null { for (int i = _currentAeroModules.Count - 1; i >= 0; i--) //start from the top and come down to improve performance if it needs to remove anything { FARAeroPartModule m = _currentAeroModules[i]; if (m != null) { m.UpdateVelocityAndAngVelocity(frameVel); } else { _currentAeroModules.RemoveAt(i); i++; } } } else //otherwise, we don't need to do Unity's expensive "is this part dead" null-check { for (int i = _currentAeroModules.Count - 1; i >= 0; i--) //start from the top and come down to improve performance if it needs to remove anything { FARAeroPartModule m = _currentAeroModules[i]; m.UpdateVelocityAndAngVelocity(frameVel); } } for (int i = 0; i < _currentAeroSections.Count; i++) { _currentAeroSections[i].FlightCalculateAeroForces(atmDensity, (float)machNumber, (float)(reynoldsNumber / Length), skinFrictionDragCoefficient); } _vesselIntakeRamDrag.ApplyIntakeRamDrag((float)machNumber, _vessel.srf_velocity.normalized, (float)_vessel.dynamicPressurekPa); for (int i = 0; i < _currentAeroModules.Count; i++) { FARAeroPartModule m = _currentAeroModules[i]; m.ApplyForces(); } }
private void CalculateAndApplyVesselAeroProperties() { float atmDensity = (float)_vessel.atmDensity; if (atmDensity <= 0) { machNumber = 0; reynoldsNumber = 0; return; } machNumber = _vessel.mach; reynoldsNumber = FARAeroUtil.CalculateReynoldsNumber(_vessel.atmDensity, Length, _vessel.srfSpeed, machNumber, FlightGlobals.getExternalTemperature((float)_vessel.altitude, _vessel.mainBody), _vessel.mainBody.atmosphereAdiabaticIndex); float skinFrictionDragCoefficient = (float)FARAeroUtil.SkinFrictionDrag(reynoldsNumber, machNumber); Vector3 frameVel = Krakensbane.GetFrameVelocityV3f(); for (int i = 0; i < _currentAeroModules.Count; i++) { FARAeroPartModule m = _currentAeroModules[i]; if (m != null) { m.UpdateVelocityAndAngVelocity(frameVel); } else { _currentAeroModules.RemoveAt(i); i--; } } for (int i = 0; i < _currentAeroSections.Count; i++) { _currentAeroSections[i].FlightCalculateAeroForces(atmDensity, (float)machNumber, (float)(reynoldsNumber / Length), skinFrictionDragCoefficient); } _vesselIntakeRamDrag.ApplyIntakeRamDrag((float)machNumber, _vessel.srf_velocity.normalized, (float)_vessel.dynamicPressurekPa); for (int i = 0; i < _currentAeroModules.Count; i++) { FARAeroPartModule m = _currentAeroModules[i]; if ((object)m != null) { m.ApplyForces(); } } }
public void SimulateAeroProperties(out Vector3 aeroForce, out Vector3 aeroTorque, Vector3 velocityWorldVector, double altitude) { FARCenterQuery center = new FARCenterQuery(); float pressure; float density; float temperature; float speedOfSound; CelestialBody body = _vessel.mainBody; //Calculate main gas properties pressure = (float)body.GetPressure(altitude); temperature = (float)body.GetTemperature(altitude); density = (float)body.GetDensity(pressure, temperature); speedOfSound = (float)body.GetSpeedOfSound(pressure, density); float velocityMag = velocityWorldVector.magnitude; float machNumber = velocityMag / speedOfSound; float reynoldsNumber = (float)FARAeroUtil.CalculateReynoldsNumber(density, Length, velocityMag, machNumber, temperature, body.atmosphereAdiabaticIndex); float reynoldsPerLength = reynoldsNumber / (float)Length; float skinFriction = (float)FARAeroUtil.SkinFrictionDrag(reynoldsNumber, machNumber); float pseudoLanchesterNumber = machNumber / (reynoldsNumber + machNumber); for (int i = 0; i < _currentAeroSections.Count; i++) { _currentAeroSections[i].PredictionCalculateAeroForces(density, machNumber, reynoldsPerLength, pseudoLanchesterNumber, skinFriction, velocityWorldVector, center); } for (int i = 0; i < _legacyWingModels.Count; i++) { _legacyWingModels[i].PrecomputeCenterOfLift(velocityWorldVector, machNumber, density, center); } aeroForce = center.force; aeroTorque = center.TorqueAt(_vessel.CoM); }
/// <summary> /// These are just a few different attempts to figure drag for various blunt bodies /// </summary> private void DragModel(Vector3d local_velocity, double M, double rho) { // Has the same x/y/z as the vertices in PartMaxBoundaries etc Vector3d model_velocity = to_model_rotation * local_velocity; double viscousLift, potentialLift, newtonianLift; viscousLift = potentialLift = newtonianLift = 0; double CdAdd = 0; //float AxialProportion = Vector3.Dot(localUpVector, local_velocity); double AxialProportion = model_velocity.y; float AxialProportion_flt = (float)model_velocity.y; double AxialProportion_2 = AxialProportion * AxialProportion; double OneMinusAxial_2 = Math.Abs(1 - AxialProportion_2); double M_2 = M * M; double M_2_recip = 1 / M_2; double maxPressureCoeff; if (FARDebugValues.useSplinesForSupersonicMath) { maxPressureCoeff = FARAeroUtil.MaxPressureCoefficient.Evaluate((float)M); } else { maxPressureCoeff = FARAeroUtil.MaxPressureCoefficientCalc(M); } double sepFlowCd = SeparatedFlowDrag(M, M_2, M_2_recip); //This handles elliptical and other non-circular cross sections //float crossflowParameter = Vector3.Dot(localForwardVector, Vector3.Exclude(localUpVector, local_velocity).normalized); //crossflowParameter *= crossflowParameter; double crossflowParameter = model_velocity.z * model_velocity.z; double crossflow = model_velocity.x * model_velocity.x + crossflowParameter; if (crossflow != 0) { crossflowParameter /= crossflow; } crossflowParameter = crossflowParameter * majorMinorAxisRatio + (1 - crossflowParameter) / majorMinorAxisRatio; if (AxialProportion_2 > 0.98) { crossflowParameter *= 50 * OneMinusAxial_2; } Cd += CdCurve.Evaluate(AxialProportion_flt); viscousLift = ClViscousCurve.Evaluate(AxialProportion_flt); double axialDirectionFactor = cosAngleCutoff * AxialProportion; if (axialDirectionFactor > 0) { Cd = Math.Min(Cd, sepFlowCd * taperCrossSectionAreaRatio) * AxialProportion_2 + Cd * OneMinusAxial_2; } else { Cd = Math.Min(Cd, maxPressureCoeff * taperCrossSectionAreaRatio) * AxialProportion_2 + Cd * OneMinusAxial_2; } if (M_2 > 1) { potentialLift = ClPotentialCurve.Evaluate(AxialProportion_flt) * M_2_recip; } else { potentialLift = ClPotentialCurve.Evaluate(AxialProportion_flt); } Cm = CmCurve.Evaluate(AxialProportion_flt) * 0.1; CoDshift = CenterOfDrag; double MachMultiplier = MachDragEffect(M); Cd *= MachMultiplier; if (HighLogic.LoadedSceneIsFlight) { Cd += FARAeroUtil.SkinFrictionDrag(rho, lengthScale, local_velocity.magnitude, M, FlightGlobals.getExternalTemperature(part.transform.position) + FARAeroUtil.currentBodyTemp); //Skin friction drag } else { Cd += 0.005; } for (int i = 0; i < attachNodeDragList.Count; i++) { attachNodeData node = attachNodeDragList[i]; double dotProd = Vector3d.Dot(node.location.normalized, local_velocity); double tmp = 0; double Cltmp = 0; if (dotProd < 0) { dotProd *= dotProd; tmp = sepFlowCd; // Cltmp = tmp * (dotProd - 1); // Cltmp *= pair.Value; tmp *= node.areaValue * dotProd; // Vector3 CoDshiftOffset = -Vector3.Exclude(pair.Key, part.transform.worldToLocalMatrix.MultiplyVector(velocity.normalized)).normalized; // CoDshiftOffset *= Mathf.Sqrt(Mathf.Clamp01(1 - dotProd)); // CoDshiftOffset *= Mathf.Sqrt(1.5f * pair.Value); CoDshift += node.location * (tmp / (tmp + Cd)); } else { Vector3d worldPairVec = part_transform.TransformDirection(node.location.normalized); double dotProd_2 = dotProd * dotProd; double liftProd_2 = 1 - dotProd_2; double liftProd = Vector3d.Dot(worldPairVec, liftDir); double forceCoefficient = dotProd_2 * bluntBodyCosForceParameter; forceCoefficient += liftProd_2 * bluntBodySinForceParameter; forceCoefficient *= maxPressureCoeff * node.areaValue; //force applied perependicular to the flat end of the node tmp = forceCoefficient * dotProd; Cltmp = -forceCoefficient * liftProd; //negative because lift is in opposite direction of projection of velocity vector onto node direction double Cmtmp = dotProd * liftProd * bluntBodyMomentParameter; Cmtmp *= node.areaValue * node.recipDiameter; if (!node.pitchesAwayFromUpVec) { Cmtmp *= -1; } Cm += Cmtmp; double tmpCdCl = Math.Sqrt(tmp * tmp + Cltmp * Cltmp); CoDshift += node.location * (tmpCdCl / (tmpCdCl + Math.Sqrt(Cd * Cd + Cl * Cl))); /*double liftProd = Vector3d.Dot(worldPairVec, liftDir); * * tmp = maxPressureCoeff * dotProd_2 * dotProd; * tmp *= node.areaValue; * * Cltmp = maxPressureCoeff * dotProd_2 * liftProd; * Cltmp *= -node.areaValue; * * double radius = Math.Sqrt(node.areaValue / Math.PI); * Vector3 CoDshiftOffset = Vector3.Exclude(node.location, local_velocity).normalized; * CoDshiftOffset *= (float)(Math.Abs(liftProd) * radius * 0.4); * * double Cmtmp; * if (node.pitchesAwayFromUpVec) * Cmtmp = -0.325 * radius * node.areaValue / S * Math.Abs(liftProd); * else * Cmtmp = 0.325 * radius * node.areaValue / S * Math.Abs(liftProd); * * double tmpCdCl = Math.Sqrt(tmp * tmp + Cltmp * Cltmp); * * CoDshift += node.location * (tmpCdCl / (tmpCdCl + Math.Sqrt(Cd * Cd + Cl * Cl))) + CoDshiftOffset; * * Cm += Cmtmp;*/ } CdAdd += tmp; newtonianLift += Cltmp; } viscousLift *= MachMultiplier; Cd += CdAdd; Cl = viscousLift + potentialLift; Cl *= crossflowParameter; Cm *= crossflowParameter; Cl += newtonianLift; // Debug.Log("Cd = " + Cd + " Cl = " + Cl + " Cm = " + Cm + "\nPot Lift = " + potentialLift + " Visc Lift = " + viscousLift + " Newt Lift = " + newtonianLift + "\nCdAdd = " + CdAdd + " sepFlowCd = " + sepFlowCd + " maxPressureCoeff = " + maxPressureCoeff + "\ntaperCrossSectionAreaRatio = " + taperCrossSectionAreaRatio + " crossflowParameter = " + crossflowParameter); }
public void SimulateAeroProperties( out Vector3 aeroForce, out Vector3 aeroTorque, Vector3 velocityWorldVector, double altitude ) { Vector3d position = vessel.CurrentPosition(altitude); if (velocityWorldVector.NearlyEqual(lastSimResults.VelocityVector) && (FARAtmosphere.IsCustom // Custom atmospheres are not guaranteed to be independent of latitude and longitude ? position.NearlyEqual(lastSimResults.Position) : altitude.NearlyEqual(lastSimResults.Position.z))) { aeroForce = lastSimResults.Force; aeroTorque = lastSimResults.Torque; return; } var center = new FARCenterQuery(); var dummy = new FARCenterQuery(); //Calculate main gas properties GasProperties properties = FARAtmosphere.GetGasProperties(vessel.mainBody, position, Planetarium.GetUniversalTime()); if (properties.Pressure <= 0 || properties.Temperature <= 0) { aeroForce = Vector3.zero; aeroTorque = Vector3.zero; return; } float velocityMag = velocityWorldVector.magnitude; float machNumber = (float)(velocityMag / properties.SpeedOfSound); float reynoldsNumber = (float)FARAeroUtil.CalculateReynoldsNumber(properties.Density, Length, velocityMag, machNumber, properties.Temperature, properties.AdiabaticIndex); float reynoldsPerLength = reynoldsNumber / (float)Length; float skinFriction = (float)FARAeroUtil.SkinFrictionDrag(reynoldsNumber, machNumber); float pseudoKnudsenNumber = machNumber / (reynoldsNumber + machNumber); if (_currentAeroSections != null) { foreach (FARAeroSection curSection in _currentAeroSections) { curSection?.PredictionCalculateAeroForces((float)properties.Density, machNumber, reynoldsPerLength, pseudoKnudsenNumber, skinFriction, velocityWorldVector, center); } foreach (FARWingAerodynamicModel curWing in _legacyWingModels) { if (curWing != null) { center.AddForce(curWing.transform.position, curWing.PrecomputeCenterOfLift(velocityWorldVector, machNumber, properties.Density, dummy)); } } } aeroForce = center.force; aeroTorque = center.TorqueAt(vessel.CoM); lastSimResults = new CachedSimResults(velocityWorldVector, position, aeroForce, aeroTorque); }
public void SimulateAeroProperties( out Vector3 aeroForce, out Vector3 aeroTorque, Vector3 velocityWorldVector, double altitude ) { var center = new FARCenterQuery(); var dummy = new FARCenterQuery(); //Calculate main gas properties GasProperties properties = FARAtmosphere.GetGasProperties(vessel, altitude, Planetarium.GetUniversalTime()); if (properties.Pressure <= 0 || properties.Temperature <= 0) { aeroForce = Vector3.zero; aeroTorque = Vector3.zero; return; } float velocityMag = velocityWorldVector.magnitude; float machNumber = (float)(velocityMag / properties.SpeedOfSound); float reynoldsNumber = (float)FARAeroUtil.CalculateReynoldsNumber(properties.Density, Length, velocityMag, machNumber, properties.Temperature, properties.AdiabaticIndex); float reynoldsPerLength = reynoldsNumber / (float)Length; float skinFriction = (float)FARAeroUtil.SkinFrictionDrag(reynoldsNumber, machNumber); float pseudoKnudsenNumber = machNumber / (reynoldsNumber + machNumber); if (_currentAeroSections != null) { foreach (FARAeroSection curSection in _currentAeroSections) { curSection?.PredictionCalculateAeroForces((float)properties.Density, machNumber, reynoldsPerLength, pseudoKnudsenNumber, skinFriction, velocityWorldVector, center); } foreach (FARWingAerodynamicModel curWing in _legacyWingModels) { if (curWing != null) { center.AddForce(curWing.transform.position, curWing.PrecomputeCenterOfLift(velocityWorldVector, machNumber, properties.Density, dummy)); } } } aeroForce = center.force; aeroTorque = center.TorqueAt(vessel.CoM); }