File size: 3,719 Bytes
1ce499f
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
from app.utils import safe_float, safe_int
FEATURE_COLUMNS=["delta_mean_motion","delta_inclination","delta_eccentricity","delta_raan","delta_bstar","launch_year_gap","same_object_type","same_shell","shell_density_proxy","close_approach_proxy","persistence_proxy","recurrence_count","trend_delta_score","score_volatility_proxy","graph_degree_sum","graph_common_neighbors","graph_jaccard","graph_local_density"]
FEATURE_LABELS={"delta_mean_motion":"Mean motion difference","delta_inclination":"Inclination difference","delta_eccentricity":"Eccentricity difference","delta_raan":"RAAN difference","delta_bstar":"BSTAR difference","launch_year_gap":"Launch year gap","same_object_type":"Same object type","same_shell":"Same orbital shell","shell_density_proxy":"Shell density proxy","close_approach_proxy":"Close approach proxy","persistence_proxy":"Persistence proxy","recurrence_count":"Recurrence count","trend_delta_score":"Trend delta","score_volatility_proxy":"Score volatility","graph_degree_sum":"Graph degree sum","graph_common_neighbors":"Common neighbors","graph_jaccard":"Graph jaccard","graph_local_density":"Graph local density"}
def normalize_object(raw):
    name=raw.get("OBJECT_NAME") or raw.get("object_name") or "UNKNOWN"
    norad=raw.get("NORAD_CAT_ID") or raw.get("norad_cat_id")
    intl=raw.get("OBJECT_ID") or raw.get("object_id") or ""
    launch_year=int(intl[:4]) if len(intl)>=4 and intl[:4].isdigit() else None
    return {"object_id":str(norad or name),"norad_cat_id":safe_int(norad,0) or None,"object_name":name,"object_type":raw.get("OBJECT_TYPE") or raw.get("object_type"),"mean_motion":safe_float(raw.get("MEAN_MOTION") or raw.get("mean_motion")),"inclination":safe_float(raw.get("INCLINATION") or raw.get("inclination")),"eccentricity":safe_float(raw.get("ECCENTRICITY") or raw.get("eccentricity")),"raan":safe_float(raw.get("RA_OF_ASC_NODE") or raw.get("raan")),"bstar":safe_float(raw.get("BSTAR") or raw.get("bstar")),"launch_year":launch_year}
def orbital_shell_key(obj):
    mm=safe_float(obj.get("mean_motion")); inc=safe_float(obj.get("inclination")); ecc=safe_float(obj.get("eccentricity"))
    return f"mm:{int(mm)}|inc:{int(inc//5)*5}|ecc:{int(ecc*1000)//10}"
def base_pair_features(a,b):
    mm1,mm2=safe_float(a.get("mean_motion")),safe_float(b.get("mean_motion"))
    inc1,inc2=safe_float(a.get("inclination")),safe_float(b.get("inclination"))
    ecc1,ecc2=safe_float(a.get("eccentricity")),safe_float(b.get("eccentricity"))
    raan1,raan2=safe_float(a.get("raan")),safe_float(b.get("raan"))
    b1,b2=safe_float(a.get("bstar")),safe_float(b.get("bstar"))
    ly1,ly2=safe_int(a.get("launch_year")),safe_int(b.get("launch_year"))
    same_type=1 if (a.get("object_type") or "")==(b.get("object_type") or "") else 0
    same_shell=1 if orbital_shell_key(a)==orbital_shell_key(b) else 0
    delta_mm=abs(mm1-mm2); delta_inc=abs(inc1-inc2); delta_ecc=abs(ecc1-ecc2); delta_raan=abs(raan1-raan2); delta_bstar=abs(b1-b2)
    launch_gap=abs(ly1-ly2) if ly1 and ly2 else 25
    shell_density_proxy=max(0.0,10.0-delta_mm)+max(0.0,8.0-delta_inc/2.0)
    close_approach_proxy=1.0/(1.0+delta_mm+delta_inc/10.0+delta_ecc*50.0+delta_raan/60.0)
    persistence_proxy=1.0 if same_shell else 0.25
    return {"delta_mean_motion":delta_mm,"delta_inclination":delta_inc,"delta_eccentricity":delta_ecc,"delta_raan":delta_raan,"delta_bstar":delta_bstar,"launch_year_gap":float(launch_gap),"same_object_type":float(same_type),"same_shell":float(same_shell),"shell_density_proxy":float(shell_density_proxy),"close_approach_proxy":float(close_approach_proxy),"persistence_proxy":float(persistence_proxy)}
def combine_features(a,b,trend,graph): return {**base_pair_features(a,b),**trend,**graph}