diff --git a/Aircraft/Instruments-3d/rwr/rwr.nas b/Aircraft/Instruments-3d/rwr/rwr.nas new file mode 100644 index 000000000..adbdfcf9b --- /dev/null +++ b/Aircraft/Instruments-3d/rwr/rwr.nas @@ -0,0 +1,220 @@ +# Radar2 and RWR routines. + +# Alexis Bory (xiii) + +# Every 0.05 seconde: +# [1] Scans /AI/models for (aircrafts), (carriers), multiplayers. Creates a list of +# these targets, whenever they are in radar overall range and are valid. +# [2] RWR (Radar Warning Receiver) signals are then computed. RWR signal values +# are writen under /instrumentation/radar2/targets for interoperabilty purposes. +# [3] At each loop the targets list is scanned and each target bearing is checked +# against the radar beam heading. If the target is within the radar beam, its +# display properties are updated. Two different displays are possible: +# B-scan like and PPI like. +# The target distance is then scored so the radar system can autotrack the +# nearest target. +# Every 0.1 seconde: +# [4] Computes HUD marker position for the nearest target. + +var OurAlt = props.globals.getNode("position/altitude-ft"); +var OurHdg = props.globals.getNode("orientation/heading-deg"); +var EcmOn = props.globals.getNode("instrumentation/ecm/on-off", 1); +var EcmAlert1 = props.globals.getNode("instrumentation/ecm/alert-type1", 1); +var EcmAlert2 = props.globals.getNode("instrumentation/ecm/alert-type2", 1); + +var our_alt = 0; +var Mp = props.globals.getNode("ai/models"); +var tgts_list = []; +var ecm_alert1 = 0; +var ecm_alert2 = 0; +var ecm_alert1_last = 0; +var ecm_alert2_last = 0; +var u_ecm_signal = 0; +var u_ecm_signal_norm = 0; +var u_radar_standby = 0; +var u_ecm_type_num = 0; + +init = func() { + radardist.init(); + settimer(rwr_loop, 0.5); +} + +# Main loop ############### +var rwr_loop = func() { + ecm_on = EcmOn.getBoolValue(); + if ( ecm_on) { + our_alt = OurAlt.getValue(); + tgts_list = []; + var raw_list = Mp.getChildren(); + foreach( var c; raw_list ) { + var type = c.getName(); + if (!c.getNode("valid", 1).getValue()) { + continue; + } + var HaveRadarNode = c.getNode("radar"); + if (type == "multiplayer" or type == "tanker" and HaveRadarNode != nil) { + var u = Threat.new(c); + u_ecm_signal = 0; + u_ecm_signal_norm = 0; + u_radar_standby = 0; + u_ecm_type_num = 0; + if ( u.Range != nil) { + # Test if target has a radar. Compute if we are illuminated. This propery used by ECM + # over MP, should be standardized, like "ai/models/multiplayer[0]/radar/radar-standby". + var u_name = radardist.get_aircraft_name(u.string); + var u_maxrange = radardist.my_maxrange(u_name); # in kilometer, 0 is unknown or no radar. + var horizon = u.get_horizon( our_alt ); + var u_rng = u.get_range(); + var u_carrier = u.check_carrier_type(); + if ( u.get_rdr_standby() == 0 and u_maxrange > 0 and u_rng < horizon ) { + # Test if we are in its radar field (hard coded 74°) or if we have a MPcarrier. + # Compute the signal strength. + var our_deviation_deg = deviation_normdeg(u.get_heading(), u.get_reciprocal_bearing()); + if ( our_deviation_deg < 0 ) { our_deviation_deg *= -1 } + if ( our_deviation_deg < 37 or u_carrier == 1 ) { + u_ecm_signal = (((-our_deviation_deg/20)+2.5)*(!u_carrier )) + (-u_rng/20) + 2.6 + (u_carrier*1.8); + u_ecm_type_num = radardist.get_ecm_type_num(u_name); + } + } else { + u_ecm_signal = 0; + } + # Compute global threat situation for undiscriminant warning lights + # and discrete (normalized) definition of threat strength. + if ( u_ecm_signal > 1 and u_ecm_signal < 3 ) { + EcmAlert1.setBoolValue(1); + ecm_alert1 = 1; + u_ecm_signal_norm = 2; + } elsif ( u_ecm_signal >= 3 ) { + EcmAlert2.setBoolValue(1); + ecm_alert2 = 1; + u_ecm_signal_norm = 1; + } + u.EcmSignal.setValue(u_ecm_signal); + u.EcmSignalNorm.setIntValue(u_ecm_signal_norm); + u.EcmTypeNum.setIntValue(u_ecm_type_num); + } + } + } + + # Summarize ECM alerts. + if ( ecm_alert1 == 0 and ecm_alert1_last == 0 ) { EcmAlert1.setBoolValue(0) } + if ( ecm_alert2 == 0 and ecm_alert1_last == 0 ) { EcmAlert2.setBoolValue(0) } + ecm_alert1_last = ecm_alert1; # And avoid alert blinking at each loop. + ecm_alert2_last = ecm_alert2; + ecm_alert1 = 0; + ecm_alert2 = 0; + } elsif ( size(tgts_list) > 0 ) { + foreach( u; tgts_list ) { + u.EcmSignal.setValue(0); + u.EcmSignalNorm.setIntValue(0); + u.EcmTypeNum.setIntValue(0); + } + } + settimer(rwr_loop, 0.05); +} + + + +# Utilities. +var deviation_normdeg = func(our_heading, target_bearing) { + var dev_norm = our_heading - target_bearing; + while (dev_norm < -180) dev_norm += 360; + while (dev_norm > 180) dev_norm -= 360; + return(dev_norm); +} + + +setlistener("sim/signals/fdm-initialized", init); + +# Target class +var Threat = { + new : func (c) { + var obj = { parents : [Threat]}; + obj.RdrProp = c.getNode("radar"); + obj.Heading = c.getNode("orientation/true-heading-deg"); + obj.Alt = c.getNode("position/altitude-ft"); + obj.AcType = c.getNode("sim/model/ac-type"); + obj.type = c.getName(); + obj.index = c.getIndex(); + obj.string = "ai/models/" ~ obj.type ~ "[" ~ obj.index ~ "]"; + obj.shortstring = obj.type ~ "[" ~ obj.index ~ "]"; + obj.InstrTgts = props.globals.getNode("instrumentation/radar2/targets", 1); + obj.TgtsFiles = obj.InstrTgts.getNode(obj.shortstring, 1); + + obj.Range = obj.RdrProp.getNode("range-nm"); + obj.Bearing = obj.RdrProp.getNode("bearing-deg"); + obj.Elevation = obj.RdrProp.getNode("elevation-deg"); + obj.BBearing = obj.TgtsFiles.getNode("bearing-deg", 1); + obj.BHeading = obj.TgtsFiles.getNode("true-heading-deg", 1); + obj.RangeScore = obj.TgtsFiles.getNode("range-score", 1); + obj.RelBearing = obj.TgtsFiles.getNode("ddd-relative-bearing", 1); + obj.Carrier = obj.TgtsFiles.getNode("carrier", 1); + obj.EcmSignal = obj.TgtsFiles.getNode("ecm-signal", 1); + obj.EcmSignalNorm = obj.TgtsFiles.getNode("ecm-signal-norm", 1); + obj.EcmTypeNum = obj.TgtsFiles.getNode("ecm_type_num", 1); + + obj.RadarStandby = c.getNode("sim/multiplay/generic/int[2]"); + obj.deviation = nil; + + return obj; + }, + get_heading : func { + var n = me.Heading.getValue(); + me.BHeading.setValue(n); + return n; + }, + get_bearing : func { + var n = me.Bearing.getValue(); + me.BBearing.setValue(n); + return n; + }, + set_relative_bearing : func(n) { + me.RelBearing.setValue(n); + }, + get_reciprocal_bearing : func { + return geo.normdeg(me.get_bearing() + 180); + }, + get_deviation : func(true_heading_ref) { + me.deviation = - deviation_normdeg(true_heading_ref, me.get_bearing()); + return me.deviation; + }, + get_altitude : func { + return me.Alt.getValue(); + }, + get_range : func { + return me.Range.getValue(); + }, + get_horizon : func(own_alt) { + var tgt_alt = me.get_altitude(); + if ( tgt_alt != nil ) { + if ( own_alt < 0 ) { own_alt = 0.001 } + if ( debug.isnan(tgt_alt)) { + return(0); + } + if ( tgt_alt < 0 ) { tgt_alt = 0.001 } + return radardist.radar_horizon( own_alt, tgt_alt ); + } else { + return(0); + } + }, + check_carrier_type : func { + var type = "none"; + var carrier = 0; + if ( me.AcType != nil ) { type = me.AcType.getValue() } + if ( type == "MP-Nimitz" or type == "MP-Eisenhower" or type == "MP-Vinson") { carrier = 1 } + # This works only after the mp-carrier model has been loaded. Before that it is seen like a common aircraft. + me.Carrier.setBoolValue(carrier); + return carrier; + }, + get_rdr_standby : func { + var s = 0; + if ( me.RadarStandby != nil ) { + s = me.RadarStandby.getValue(); + if (s == nil) { s = 0 } elsif (s != 1) { s = 0 } + } + return s; + }, + list : [], +}; + +