### Radar Visibility Calculator # Jettoo (glazmax) and xiii (Alexis) # my_maxrange(myaircraft): finds our own aircraft max radar range in a table. # Returns my_radarcorr in kilometers, should be called from your own aircraft # radar stuff. # radis(i, my_radarcorr): find multiplayer[i], its Radar Cross Section (RCS), # applies factor upon our altitude, shorter radar detection distance (due to air # turbulence), then factor upon its altitude above ground, and finaly computes if # it is detectable given our radar range. # Returns 1 if detectable, 0 if not. Should be called from your own aircraft # radar stuff too. var data_path = getprop("/sim/fg-root") ~ "/Aircraft/Generic/radardist.xml"; var aircraftData = {}; var radarData = []; mpnode_string = nil; var cutname = nil; var mpnode = nil; var mpname_node_string = nil; var mpname_node = nil; var mpname = nil; var splitname = nil; var acname = nil; var rcs_4r = nil; var radartype = nil; var alt_corr = nil; var alt_ac = nil; var agl_corr = nil; var mp_lon = nil; var mp_lat = nil; var pos_elev = nil; var mp_agl = nil; var det_range = nil; var act_range = nil; var max_range = nil; var radar_range = nil; var radar_area = nil; var have_radar = nil; var FT2M = 0.3048; var NM2KM = 1.852; var my_maxrange = func(a) { max_range = 0; radar_range = 0; radar_area = 0; acname = aircraftData[a] or 0; if ( acname ) { have_radar = radarData[acname][4]; if ( have_radar != "none" and have_radar != "unknown") { radar_area = radarData[acname][7]; radar_range = radarData[acname][5]; if ( radar_area > 0 ) { max_range = radar_range / radar_area } } } #var plane = radarData[acname][2]; #print ("aircraft = " ~ plane); #print ("range = " ~ radar_range); #print ("aera = " ~ radar_area); return( max_range ); } var get_aircraft_name = func( t ) { # Get the multiplayer aircraft name. mpnode_string = t; mpnode = props.globals.getNode(mpnode_string); if ( find("tanker", mpnode_string) > 0 ) { #print("tanker"); cutname = "KC135"; } else { mpname_node_string = mpnode_string ~ "/sim/model/path"; mpname_node = props.globals.getNode(mpname_node_string); if (mpname_node == nil) { return(0) } var mpname = mpname_node.getValue(); if (mpname == nil) { return(0) } splitname = split("/", mpname); cutname = splitname[1]; #print( mpname_node_string ~ " " ~ cutname ); } return( cutname ); } var radis = func(t, my_radarcorr) { cutname = get_aircraft_name(t); # Calculate the rcs detection range, # if aircraft is not found in list, 0 (generic) will be used. acname = aircraftData[cutname]; if ( acname == nil ) { acname = 0 } rcs_4r = radarData[acname][3]; #radartype = radarData[acname][1]; # Add a correction factor for altitude, as lower alt means # shorter radar distance (due to air turbulence). alt_corr = 1; alt_ac = mpnode.getNode("position/altitude-ft").getValue(); if (alt_ac <= 1000) { alt_corr = 0.6; } elsif ((alt_ac > 1000) and (alt_ac <= 5000)) { alt_corr = 0.8; } # Add a correction factor for altitude AGL. agl_corr = 1; mp_lon = mpnode.getNode("position/longitude-deg").getValue(); mp_lat = mpnode.getNode("position/latitude-deg").getValue(); pos_elev = geo.elevation(mp_lat, mp_lon); if (pos_elev != nil) { #print("pos_elev: " ~ pos_elev); mp_agl = alt_ac - ( pos_elev / FT2M ); if (mp_agl <= 20) { agl_corr = 0.03; } elsif ((mp_agl > 20) and (mp_agl <= 50)) { agl_corr = 0.08; } elsif ((mp_agl > 50) and (mp_agl <= 120)) { agl_corr = 0.25; } elsif ((mp_agl > 120) and (mp_agl <= 300)) { agl_corr = 0.4; } elsif ((mp_agl > 300) and (mp_agl <= 600)) { agl_corr = 0.7; } elsif ((mp_agl > 600) and (mp_agl <= 1000)) { agl_corr = 0.85; } } # Calculate the detection distance for this multiplayer. det_range = my_radarcorr * rcs_4r * alt_corr * agl_corr / NM2KM; #print (radartype); #print (rcs_4r); ### Compare if aircraft is in detection range and return. act_range = mpnode.getNode("radar/range-nm").getValue() or 500; #print (det_range ~ " " ~ act_range); if (det_range >= act_range) { #print("paint it"); return(1); } return(0); } var radar_horizon = func(our_alt_ft, target_alt_ft) { if (our_alt_ft < 0) { our_alt_ft = 0 } if (target_alt_ft < 0) { target_alt_ft = 0 } return( 2.2 * ( math.sqrt(our_alt_ft * FT2M) + math.sqrt(target_alt_ft * FT2M) ) ); } var load_data = func { # a) converts aircraft model name to lookup (index) number in aircraftData{}. # b) appends ordered list of data into radarData[], # data is: # - acname (the index number) # - the first (if several) aircraft model name corresponding to this type, # - RCS(m2), # - 4th root of RCS, # - radar type, # - max. radar range(km), # - max. radar range target seize(RCS)m2, # - 4th root of radar RCS. var data_node = props.globals.getNode("instrumentation/radar-performance/data"); var aircraft_types = data_node.getChildren(); foreach( var t; aircraft_types ) { var index = t.getIndex(); var aircraft_names = t.getChildren(); foreach( var n; aircraft_names) { if ( n.getName() == "name") { aircraftData[n.getValue()] = index; #print(n.getValue() ~ " : " ~ index); } } var t_list = [ index, t.getNode("name[0]").getValue(), t.getNode("rcs-sq-meter").getValue(), t.getNode("rcs-4th-root").getValue(), t.getNode("radar-type").getValue(), t.getNode("max-radar-rng-km").getValue(), t.getNode("max-target-sq-meter").getValue(), t.getNode("max-target-4th-root").getValue() ]; append(radarData, t_list); } } var init = func { print("Initializing Radar Data"); io.read_properties(data_path, props.globals); load_data(); }