added simulate stages. Changed GSN_PREDICTOR_GRIB_TTL to 48h

This commit is contained in:
afanasyev.aa 2025-12-09 18:25:16 +09:00
parent c4f355a32e
commit fe207f3fab
21 changed files with 978 additions and 137 deletions

View file

@ -23,6 +23,22 @@ type Stage struct {
EndTime time.Time
}
// shouldSimulateStage checks if a given stage should be simulated based on the SimulateStages filter
func shouldSimulateStage(params ds.PredictionParameters, stage string) bool {
// If no filter is specified, simulate all stages
if len(params.SimulateStages) == 0 {
return true
}
// Check if the stage is in the filter list
for _, s := range params.SimulateStages {
if s == stage {
return true
}
}
return false
}
// CustomCurve represents a custom ascent/descent curve
type CustomCurve struct {
Altitude []float64 `json:"altitude"`
@ -103,16 +119,27 @@ func (s *Service) PerformPrediction(ctx context.Context, params ds.PredictionPar
func (s *Service) standardProfile(ctx context.Context, params ds.PredictionParameters, ascentRate, burstAltitude, descentRate float64, ascentCurve, descentCurve *CustomCurve) []ds.PredicitonResult {
var results []ds.PredicitonResult
var lastResult ds.PredicitonResult
// Stage 1: Ascent
ascentResults := s.simulateAscent(ctx, params, ascentRate, burstAltitude, ascentCurve)
results = append(results, ascentResults...)
if shouldSimulateStage(params, "ascent") {
ascentResults := s.simulateAscent(ctx, params, ascentRate, burstAltitude, ascentCurve)
results = append(results, ascentResults...)
if len(ascentResults) > 0 {
lastResult = ascentResults[len(ascentResults)-1]
}
} else {
// If ascent is skipped, use initial position as starting point
lastResult = ds.PredicitonResult{
Latitude: params.LaunchLatitude,
Longitude: params.LaunchLongitude,
Altitude: &burstAltitude,
Timestamp: params.LaunchDatetime,
}
}
if len(ascentResults) > 0 {
// Get final position from ascent
lastResult := ascentResults[len(ascentResults)-1]
// Stage 2: Descent
// Stage 2: Descent
if shouldSimulateStage(params, "descent") && lastResult.Latitude != nil {
descentParams := ds.PredictionParameters{
LaunchLatitude: lastResult.Latitude,
LaunchLongitude: lastResult.Longitude,
@ -129,45 +156,36 @@ func (s *Service) standardProfile(ctx context.Context, params ds.PredictionParam
func (s *Service) floatProfile(ctx context.Context, params ds.PredictionParameters, ascentRate, burstAltitude, floatAltitude, descentRate float64, ascentCurve, descentCurve *CustomCurve) []ds.PredicitonResult {
var results []ds.PredicitonResult
var lastResult ds.PredicitonResult
// Stage 1: Ascent to float altitude
ascentResults := s.simulateAscent(ctx, params, ascentRate, floatAltitude, ascentCurve)
results = append(results, ascentResults...)
if len(ascentResults) > 0 {
// Stage 2: Float (simulate for some time)
lastResult := ascentResults[len(ascentResults)-1]
floatResults := s.simulateFloat(ctx, lastResult, 30*time.Minute) // Float for 30 minutes
results = append(results, floatResults...)
if len(floatResults) > 0 {
// Stage 3: Descent
finalFloat := floatResults[len(floatResults)-1]
descentParams := ds.PredictionParameters{
LaunchLatitude: finalFloat.Latitude,
LaunchLongitude: finalFloat.Longitude,
LaunchAltitude: finalFloat.Altitude,
LaunchDatetime: finalFloat.Timestamp,
}
descentResults := s.simulateDescent(ctx, descentParams, descentRate, 0, descentCurve)
results = append(results, descentResults...)
if shouldSimulateStage(params, "ascent") {
ascentResults := s.simulateAscent(ctx, params, ascentRate, floatAltitude, ascentCurve)
results = append(results, ascentResults...)
if len(ascentResults) > 0 {
lastResult = ascentResults[len(ascentResults)-1]
}
} else {
// If ascent is skipped, use initial position at float altitude as starting point
lastResult = ds.PredicitonResult{
Latitude: params.LaunchLatitude,
Longitude: params.LaunchLongitude,
Altitude: &floatAltitude,
Timestamp: params.LaunchDatetime,
}
}
return results
}
// Stage 2: Float (simulate for some time)
if shouldSimulateStage(params, "float") && lastResult.Latitude != nil {
floatResults := s.simulateFloat(ctx, lastResult, 30*time.Minute) // Float for 30 minutes
results = append(results, floatResults...)
if len(floatResults) > 0 {
lastResult = floatResults[len(floatResults)-1]
}
}
func (s *Service) reverseProfile(ctx context.Context, params ds.PredictionParameters, ascentRate, burstAltitude, descentRate float64, ascentCurve, descentCurve *CustomCurve) []ds.PredicitonResult {
var results []ds.PredicitonResult
// Stage 1: Ascent
ascentResults := s.simulateAscent(ctx, params, ascentRate, burstAltitude, ascentCurve)
results = append(results, ascentResults...)
if len(ascentResults) > 0 {
// Stage 2: Descent to float altitude
lastResult := ascentResults[len(ascentResults)-1]
// Stage 3: Descent
if shouldSimulateStage(params, "descent") && lastResult.Latitude != nil {
descentParams := ds.PredictionParameters{
LaunchLatitude: lastResult.Latitude,
LaunchLongitude: lastResult.Longitude,
@ -175,21 +193,67 @@ func (s *Service) reverseProfile(ctx context.Context, params ds.PredictionParame
LaunchDatetime: lastResult.Timestamp,
}
// Descent to float altitude (if specified)
floatAlt := 0.0
if params.FloatAltitude != nil {
floatAlt = *params.FloatAltitude
descentResults := s.simulateDescent(ctx, descentParams, descentRate, 0, descentCurve)
results = append(results, descentResults...)
}
return results
}
func (s *Service) reverseProfile(ctx context.Context, params ds.PredictionParameters, ascentRate, burstAltitude, descentRate float64, ascentCurve, descentCurve *CustomCurve) []ds.PredicitonResult {
var results []ds.PredicitonResult
var lastResult ds.PredicitonResult
// Stage 1: Ascent
if shouldSimulateStage(params, "ascent") {
ascentResults := s.simulateAscent(ctx, params, ascentRate, burstAltitude, ascentCurve)
results = append(results, ascentResults...)
if len(ascentResults) > 0 {
lastResult = ascentResults[len(ascentResults)-1]
}
} else {
// If ascent is skipped, use initial position at burst altitude as starting point
lastResult = ds.PredicitonResult{
Latitude: params.LaunchLatitude,
Longitude: params.LaunchLongitude,
Altitude: &burstAltitude,
Timestamp: params.LaunchDatetime,
}
}
// Stage 2: Descent to float altitude
floatAlt := 0.0
if params.FloatAltitude != nil {
floatAlt = *params.FloatAltitude
}
if shouldSimulateStage(params, "descent") && lastResult.Latitude != nil {
descentParams := ds.PredictionParameters{
LaunchLatitude: lastResult.Latitude,
LaunchLongitude: lastResult.Longitude,
LaunchAltitude: lastResult.Altitude,
LaunchDatetime: lastResult.Timestamp,
}
descentResults := s.simulateDescent(ctx, descentParams, descentRate, floatAlt, descentCurve)
results = append(results, descentResults...)
if floatAlt > 0 && len(descentResults) > 0 {
// Stage 3: Float
finalDescent := descentResults[len(descentResults)-1]
floatResults := s.simulateFloat(ctx, finalDescent, 30*time.Minute)
results = append(results, floatResults...)
if len(descentResults) > 0 {
lastResult = descentResults[len(descentResults)-1]
}
} else if floatAlt > 0 {
// If descent is skipped but we need to float, position at float altitude
lastResult = ds.PredicitonResult{
Latitude: lastResult.Latitude,
Longitude: lastResult.Longitude,
Altitude: &floatAlt,
Timestamp: lastResult.Timestamp,
}
}
// Stage 3: Float
if shouldSimulateStage(params, "float") && floatAlt > 0 && lastResult.Latitude != nil {
floatResults := s.simulateFloat(ctx, lastResult, 30*time.Minute)
results = append(results, floatResults...)
}
return results
@ -197,14 +261,27 @@ func (s *Service) reverseProfile(ctx context.Context, params ds.PredictionParame
func (s *Service) customProfile(ctx context.Context, params ds.PredictionParameters, ascentCurve, descentCurve *CustomCurve) []ds.PredicitonResult {
var results []ds.PredicitonResult
var lastResult ds.PredicitonResult
if ascentCurve != nil {
// Custom ascent
if shouldSimulateStage(params, "ascent") && ascentCurve != nil {
ascentResults := s.simulateCustomAscent(ctx, params, ascentCurve)
results = append(results, ascentResults...)
if len(ascentResults) > 0 {
lastResult = ascentResults[len(ascentResults)-1]
}
} else if len(results) == 0 {
// If ascent is skipped, use initial position
lastResult = ds.PredicitonResult{
Latitude: params.LaunchLatitude,
Longitude: params.LaunchLongitude,
Altitude: params.LaunchAltitude,
Timestamp: params.LaunchDatetime,
}
}
if descentCurve != nil && len(results) > 0 {
lastResult := results[len(results)-1]
// Custom descent
if shouldSimulateStage(params, "descent") && descentCurve != nil && lastResult.Latitude != nil {
descentParams := ds.PredictionParameters{
LaunchLatitude: lastResult.Latitude,
LaunchLongitude: lastResult.Longitude,