Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix aerodynamic torque simulations #22

Merged
merged 25 commits into from May 15, 2019
Merged
Changes from 1 commit
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
1f60027
Added a new AerodynamicForce API endpoint
Oct 1, 2018
c82b439
Recompute simulated force for each part, not just the last one
Oct 2, 2018
1827b23
Refactored *CalculateAeroForces and fixed transforms in PredictionCal…
Jan 20, 2019
753115f
Add total vessel torque tracking
Jan 20, 2019
32f0dfb
Fixed CenterQuery's torque calculation and removed dead code
Jan 20, 2019
63efe75
Add torque tracking in flight info
Jan 20, 2019
790a1e8
Add new API endpoint to fetch torque on vehicle
Jan 20, 2019
e695362
Merge branch 'master' into fixed-simulation-base
BenChung Jan 20, 2019
985caee
CenterQuery was actually working correctly.
Apr 2, 2019
18fbb9d
Apply legacy wing model force in the right position.
Apr 8, 2019
a7852c6
Apply force scalars (based on MFI code & code in AeroPartModule) to s…
Apr 8, 2019
716f032
Use a CenterQuery to accumulate forces
May 1, 2019
0bba13a
Merge with upstream
May 1, 2019
03c4cf7
Fix use of FARCenterQuery to determine in-flight aerodynamic forces
May 4, 2019
405b517
Fix usage of dynamicPressurekPA for situations other than correctness…
May 4, 2019
d5d01ac
Make new FARAPI calls null VesselFlightInfo tolerant
May 4, 2019
f790f0c
Whoops, got the nullable monad use wrong
May 4, 2019
3459b30
Interfaceified the lambdas in FARAeroSection to reduce garbage
May 4, 2019
ec14134
Added active vessel aerodynamic force call sites
May 9, 2019
5e5d71e
used inline initalizer for center query
May 9, 2019
82c6f3d
Whoops, eliminated needless argument
May 10, 2019
7c52df1
Inline initalizers for force contexts
May 10, 2019
593cf15
Added null checks, cached local velocity
May 11, 2019
3163f0e
Prevent NREs from crashes
May 15, 2019
75368f6
Remove redundant null check
May 15, 2019
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
133 changes: 104 additions & 29 deletions FerramAerospaceResearch/FARAeroComponents/FARAeroSection.cs
Expand Up @@ -49,6 +49,7 @@
using UnityEngine;
using FerramAerospaceResearch.FARPartGeometry;
using FerramAerospaceResearch.FARUtils;
using ferram4;

namespace FerramAerospaceResearch.FARAeroComponents
{
Expand Down Expand Up @@ -284,10 +285,98 @@ public void ClearAeroSection()
partData.Clear();
handledAeroModulesIndexDict.Clear();
}


#region Force application contexts
private interface IForceContext
{
/// <summary>
/// The part-relative velocity of the part whose force is being computed
/// </summary>
/// <param name="pd">The part data for which to compute the local velocity</param>
Vector3 LocalVelocity(PartData pd);
/// <summary>
/// Apply a calculated force to a part.
/// </summary>
/// <param name="pd">The part data of the part that the force should be applied to</param>
/// <param name="forceVector">The calculated force vector to be applied to the part</param>
/// <param name="torqueVector">The calculated torque vector to be applied to the part</param>
void ApplyForce(PartData pd, Vector3 forceVector, Vector3 torqueVector);
}

private class SimulatedForceContext : IForceContext
{
/// <summary>
/// The world-space velocity of the part whose force is being simulated
/// </summary>
private Vector3 worldVel;

/// <summary>
/// The center with which force should be accumulated
/// </summary>
private ferram4.FARCenterQuery center;

/// <summary>
/// The atmospheric density that the force is being simulated at
/// </summary>
private float atmDensity;

public SimulatedForceContext(Vector3 worldVel, FARCenterQuery center, float atmDensity)
{
this.worldVel = worldVel;
this.center = center;
this.atmDensity = atmDensity;
}

public void UpdateSimulationContext(Vector4 worldVel, FARCenterQuery center, float atmDensity)
{
this.worldVel = worldVel;
this.center = center;
this.atmDensity = atmDensity;
}

public Vector3 LocalVelocity(PartData pd)
{
return pd.aeroModule.part.partTransform.InverseTransformVector(worldVel);
BenChung marked this conversation as resolved.
Show resolved Hide resolved
}

public void ApplyForce(PartData pd, Vector3 forceVector, Vector3 torqueVector)
{
var localVel = pd.aeroModule.part.partTransform.InverseTransformVector(worldVel);
var tmp = 0.0005 * Vector3.SqrMagnitude(localVel);
var dynamicPressurekPa = tmp * atmDensity;
var dragFactor = dynamicPressurekPa * Mathf.Max(PhysicsGlobals.DragCurvePseudoReynolds.Evaluate(atmDensity * Vector3.Magnitude(localVel)), 1.0f);
var liftFactor = dynamicPressurekPa;

var localVelNorm = Vector3.Normalize(localVel);
Vector3 localForceTemp = Vector3.Dot(localVelNorm, forceVector) * localVelNorm;
var partLocalForce = (localForceTemp * (float)dragFactor + (forceVector - localForceTemp) * (float)liftFactor);
forceVector = pd.aeroModule.part.transform.TransformDirection(partLocalForce);
torqueVector = pd.aeroModule.part.transform.TransformDirection(torqueVector * (float)dynamicPressurekPa);
if (!float.IsNaN(forceVector.x) && !float.IsNaN(torqueVector.x))
{
Vector3 centroid = pd.aeroModule.part.transform.TransformPoint(pd.centroidPartSpace - pd.aeroModule.part.CoMOffset);
center.AddForce(centroid, forceVector);
center.AddTorque(torqueVector);
}
}
}

private class FlightForceContext : IForceContext
{
public Vector3 LocalVelocity(PartData pd)
{
return pd.aeroModule.partLocalVel;
}

public void ApplyForce(PartData pd, Vector3 forceVector, Vector3 torqueVector)
{
pd.aeroModule.AddLocalForceAndTorque(forceVector, torqueVector, pd.centroidPartSpace);
}
}
#endregion

private void CalculateAeroForces(float atmDensity, float machNumber, float reynoldsPerUnitLength, float pseudoKnudsenNumber, float skinFrictionDrag,
Func<PartData,Vector3> localVel,
Action<PartData, Vector3,Vector3,Vector3> applyLocalForce)
IForceContext forceContext)
{
double skinFrictionForce = skinFrictionDrag * xForceSkinFriction.Evaluate(machNumber); //this will be the same for each part, so why recalc it multiple times?
double xForceAoA0 = xForcePressureAoA0.Evaluate(machNumber);
Expand All @@ -305,7 +394,7 @@ public void ClearAeroSection()
Vector3 xRefVector = data.xRefVectorPartSpace;
Vector3 nRefVector = data.nRefVectorPartSpace;

Vector3 velLocal = localVel(data);
Vector3 velLocal = forceContext.LocalVelocity(data);

Vector3 angVelLocal = aeroModule.partLocalAngVel;

Expand Down Expand Up @@ -418,40 +507,26 @@ public void ClearAeroSection()
forceVector *= data.dragFactor;
torqueVector *= data.dragFactor;

applyLocalForce(data, forceVector, torqueVector, data.centroidPartSpace);
forceContext.ApplyForce(data, forceVector, torqueVector);
}
}

private SimulatedForceContext simContext;
public void PredictionCalculateAeroForces(float atmDensity, float machNumber, float reynoldsPerUnitLength, float pseudoKnudsenNumber, float skinFrictionDrag, Vector3 vel, ferram4.FARCenterQuery center)
{
CalculateAeroForces(atmDensity, machNumber, reynoldsPerUnitLength, pseudoKnudsenNumber, skinFrictionDrag,
pd => pd.aeroModule.part.partTransform.InverseTransformVector(vel),
(pd, forceVector, torqueVector, pcentroid) => {
var localVel = pd.aeroModule.part.partTransform.InverseTransformVector(vel);
var tmp = 0.0005 * Vector3.SqrMagnitude(localVel);
var dynamicPressurekPa = tmp * atmDensity;
var dragFactor = dynamicPressurekPa*Mathf.Max(PhysicsGlobals.DragCurvePseudoReynolds.Evaluate(atmDensity * Vector3.Magnitude(localVel)), 1.0f);
var liftFactor = dynamicPressurekPa;

var localVelNorm = Vector3.Normalize(localVel);
Vector3 localForceTemp = Vector3.Dot(localVelNorm, forceVector) * localVelNorm;
var partLocalForce = (localForceTemp * (float)dragFactor + (forceVector - localForceTemp) * (float)liftFactor);
forceVector = pd.aeroModule.part.transform.TransformDirection(partLocalForce);
torqueVector = pd.aeroModule.part.transform.TransformDirection(torqueVector * (float)dynamicPressurekPa);
if (!float.IsNaN(forceVector.x) && !float.IsNaN(torqueVector.x))
{
Vector3 centroid = pd.aeroModule.part.transform.TransformPoint(pd.centroidPartSpace - pd.aeroModule.part.CoMOffset);
center.AddForce(centroid, forceVector);
center.AddTorque(torqueVector);
}
});
if (simContext == null)
simContext = new SimulatedForceContext(vel, center, atmDensity);
else
simContext.UpdateSimulationContext(vel, center, atmDensity);
BenChung marked this conversation as resolved.
Show resolved Hide resolved
CalculateAeroForces(atmDensity, machNumber, reynoldsPerUnitLength, pseudoKnudsenNumber, skinFrictionDrag, simContext);
}

private FlightForceContext flightContext;
public void FlightCalculateAeroForces(float atmDensity, float machNumber, float reynoldsPerUnitLength, float pseudoKnudsenNumber, float skinFrictionDrag)
{
CalculateAeroForces(atmDensity, machNumber, reynoldsPerUnitLength, pseudoKnudsenNumber, skinFrictionDrag,
pd => pd.aeroModule.partLocalVel,
(pd, forceVector, torqueVector, centroid) => pd.aeroModule.AddLocalForceAndTorque(forceVector, torqueVector, pd.centroidPartSpace));
if (flightContext == null)
flightContext = new FlightForceContext();
CalculateAeroForces(atmDensity, machNumber, reynoldsPerUnitLength, pseudoKnudsenNumber, skinFrictionDrag, flightContext);

}

Expand Down