MUM-T 항공우주 고속 전개 캡슐 콜드 가스 반작용 제어 시스템(RCS) 4축 자세 제어 500Hz 마이크로 펄스 서보 C# SIMD 엔진
1. 콜드 가스 스러스터 기체 동역학 및 펄스 폭 변조(PWM) 수식
이상 기체 단열 팽창에 기초한 콜드 가스 질소($N_2$) 노즐의 이론 추력 $F_{\text{thrust}}$ 및 특성 배기 속도 $c^*$는 다음과 같습니다:
$$F_{\text{thrust}} = \Gamma P_c A_t \sqrt{\frac{2\gamma}{\gamma-1} \left[ 1 - \left( \frac{P_e}{P_c} \right)^{\frac{\gamma-1}{\gamma}} \right]}, \quad c^* = \frac{\sqrt{\gamma R T_c}}{\Gamma}$$여기서 $\Gamma = \sqrt{\gamma} ( \frac{2}{\gamma+1} )^{\frac{\gamma+1}{2(\gamma-1)}}$이며, 솔레노이드 밸브의 개폐 지연 시간 $\tau_{\text{valve}} \approx 1.5\text{ ms}$를 고려한 유효 충격량(Total Impulse)은 500Hz PWM 듀티 사이클 $D_i \in [0, 1]$로 제어됩니다:
$$I_{\text{tot}} = \sum_{i=1}^4 \int_0^{T_{\text{pwm}}} F_i(t) dt \approx \sum_{i=1}^4 F_{\text{max}} (D_i T_{\text{pwm}} - \tau_{\text{dead}})$$3축 강체 회전 운동 오일러 방정식에 따른 각가속도 $\dot{\boldsymbol{\omega}}$는 관성 텐서 $\mathbf{J}$와 스러스터 배치 행렬 $\mathbf{L}$의 곱으로 산출됩니다:
$$\mathbf{J} \dot{\boldsymbol{\omega}} + \boldsymbol{\omega} \times (\mathbf{J} \boldsymbol{\omega}) = \sum_{i=1}^4 \mathbf{r}_i \times \mathbf{F}_i = \mathbf{L} \mathbf{u}_{\text{pwm}}$$2. 쿼터니언 기반 최단 오차 쿼터니언 PD 서보 기구학
목표 자세 쿼터니언 $\mathbf{q}_d$와 현재 추정 자세 $\mathbf{q}$ 사이의 오차 쿼터니언 $\mathbf{q}_e = \mathbf{q}^{-1} \otimes \mathbf{q}_d = [q_{e0}, \mathbf{q}_{ev}^T]^T$에 대해 제어 토크 $\boldsymbol{\tau}_c$를 계산합니다:
$$\boldsymbol{\tau}_c = -2 K_p \text{sgn}(q_{e0}) \mathbf{q}_{ev} - K_d \boldsymbol{\omega}$$3. C# .NET 9.0 Zero-Allocation SIMD 콜드 가스 RCS 서보
using System;
using System.Runtime.CompilerServices;
using System.Runtime.Intrinsics;
using System.Runtime.Intrinsics.X86;
namespace ZeliDesk.Defense.ReactionControl
{
public readonly record struct RcsServoTelemetry(
float EulerRollDeg,
float EulerPitchDeg,
float EulerYawDeg,
float AngularRateMagnitudeDegS,
float ValveDutyCycle1,
float ValveDutyCycle2,
float ValveDutyCycle3,
float ValveDutyCycle4,
bool AttitudeAligned
);
public unsafe ref struct CapsuleColdGasRcsServo
{
private const int ThrusterCount = 4;
private fixed float _thrustLevels[ThrusterCount];
private fixed float _pwmDuties[ThrusterCount];
private float _qw, _qx, _qy, _qz;
private float _wx, _wy, _wz;
private readonly float _kp;
private readonly float _kd;
private readonly float _maxThrustN;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public CapsuleColdGasRcsServo(
float kp = 45.0f,
float kd = 8.5f,
float maxThrustN = 25.0f)
{
_kp = kp;
_kd = kd;
_maxThrustN = maxThrustN;
_qw = 1.0f; _qx = 0f; _qy = 0f; _qz = 0f;
_wx = 0f; _wy = 0f; _wz = 0f;
fixed (float* pT = _thrustLevels, pP = _pwmDuties)
{
Unsafe.InitBlock(pT, 0, ThrusterCount * sizeof(float));
Unsafe.InitBlock(pP, 0, ThrusterCount * sizeof(float));
}
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public RcsServoTelemetry Step500HzLoop(
float estQw, float estQx, float estQy, float estQz,
float gyroWx, float gyroWy, float gyroWz,
float targetPitchDeg, float targetYawDeg)
{
_qw = estQw; _qx = estQx; _qy = estQy; _qz = estQz;
_wx = gyroWx; _wy = gyroWy; _wz = gyroWz;
// Target quaternion from Euler Pitch/Yaw
float halfP = targetPitchDeg * (MathF.PI / 360.0f);
float halfY = targetYawDeg * (MathF.PI / 360.0f);
float targetQw = MathF.Cos(halfP) * MathF.Cos(halfY);
float targetQx = 0f;
float targetQy = MathF.Sin(halfP) * MathF.Cos(halfY);
float targetQz = MathF.Cos(halfP) * MathF.Sin(halfY);
// Quaternion error: q_e = q_conj * q_target
float qew = _qw * targetQw + _qx * targetQx + _qy * targetQy + _qz * targetQz;
float qex = _qw * targetQx - _qx * targetQw - _qy * targetQz + _qz * targetQy;
float qey = _qw * targetQy + _qx * targetQz - _qy * targetQw - _qz * targetQx;
float qez = _qw * targetQz - _qx * targetQy + _qy * targetQx - _qz * targetQw;
float signW = qew >= 0f ? 1.0f : -1.0f;
// Control Torque Law: tau = -2 * Kp * sign(w) * q_v - Kd * omega
float tauPitch = -2.0f * _kp * signW * qey - _kd * _wy;
float tauYaw = -2.0f * _kp * signW * qez - _kd * _wz;
// Allocate torque to 4 orthogonal side nozzles (+Y, -Y, +Z, -Z)
float t1 = Math.Clamp(tauPitch / 0.15f, 0f, _maxThrustN); // +Pitch
float t2 = Math.Clamp(-tauPitch / 0.15f, 0f, _maxThrustN); // -Pitch
float t3 = Math.Clamp(tauYaw / 0.15f, 0f, _maxThrustN); // +Yaw
float t4 = Math.Clamp(-tauYaw / 0.15f, 0f, _maxThrustN); // -Yaw
fixed (float* pT = _thrustLevels, pP = _pwmDuties)
{
pT[0] = t1; pT[1] = t2; pT[2] = t3; pT[3] = t4;
// Duty cycle conversion with deadzone threshold (1.5ms / 2.0ms = 0.75)
for (int i = 0; i < ThrusterCount; i++)
{
float duty = pT[i] / _maxThrustN;
pP[i] = duty > 0.05f ? Math.Clamp(duty, 0.1f, 1.0f) : 0f;
}
}
float angRate = MathF.Sqrt(_wx * _wx + _wy * _wy + _wz * _wz) * (180.0f / MathF.PI);
float curPitch = MathF.Asin(Math.Clamp(2.0f * (_qw * _qy - _qz * _qx), -1f, 1f)) * (180.0f / MathF.PI);
float curYaw = MathF.Atan2(2.0f * (_qw * _qz + _qx * _qy), 1.0f - 2.0f * (_qy * _qy + _qz * _qz)) * (180.0f / MathF.PI);
float curRoll = MathF.Atan2(2.0f * (_qw * _qx + _qy * _qz), 1.0f - 2.0f * (_qx * _qx + _qy * _qy)) * (180.0f / MathF.PI);
bool aligned = MathF.Abs(curPitch - targetPitchDeg) < 2.5f && MathF.Abs(curYaw - targetYawDeg) < 2.5f;
return new RcsServoTelemetry(
EulerRollDeg: curRoll,
EulerPitchDeg: curPitch,
EulerYawDeg: curYaw,
AngularRateMagnitudeDegS: angRate,
ValveDutyCycle1: _pwmDuties[0],
ValveDutyCycle2: _pwmDuties[1],
ValveDutyCycle3: _pwmDuties[2],
ValveDutyCycle4: _pwmDuties[3],
AttitudeAligned: aligned
);
}
}
}
4. 교육 및 국방 실무 활용 가이드
- 초·중·고 과학교사 물리/지구과학 직무연수: 작용-반작용의 법칙과 우주선 쿼터니언 자세 제어 원리를 인터랙티브 시뮬레이션으로 교육.
- 국방 항공우주 및 유무인 복합체계 실무진: 무추력 고속 전개 캡슐의 0.2초 이내 자세 안정화를 위한 고성능 C# 솔레노이드 PWM 제어 아키텍처 제공.