# **************************************************************************** # CUI # # The Advanced Framework for Simulation, Integration, and Modeling (AFSIM) # # The use, dissemination or disclosure of data in this file is subject to # limitation or restriction. See accompanying README and LICENSE for details. # **************************************************************************** #always requires a commander #bids on & performs "jam-target" jobs #does not create any jobs #attempts to jam the target #assumes jammers aren't destroyed include_once ../common/common_platform_script.txt processor AIJAM-thinker WSF_RIPR_PROCESSOR #debug #script_debug_writes on //1 Hz update //update_interval 0.5 sec update_interval 1.0 sec //num_job_channels 3 // very important for bidding on and receiving multiple jobs, this is the // // number of targets the jammer can engage (jam) simultaneously // // depends on number of jamming arrays, will be updated on_initialize script_variables string mTaskManagerName = "task_mgr"; WsfTaskManager mTaskMgr; int CHANNEL = 0; double rangeBiddingScale = 2.0; double targetPriorityBidScale = 4.1; double bandPriorityBidScale = 1.0; double powerBidScale = 5.3; //Map mJobCurrentState = Map(); //keeps each jobs current engagement state //Map mJobStateTimes = Map(); //records when each job entered its current state WsfTrackId emptyTrackId = WsfTrackId(); Array mChannelTargets = Array(); //array index is job channel, array value is target track id (from job that channel is performing) /////////////////////////////////////////////////////////////////////////// // mChannelJammers and mChannelBeams are to be used in conjunction with one another // mChannelJammers stores that channel's jammer weapon // mChannelBeams stores that channel's jammer's beam to be used // //array index is channel, value is jamming weapons name Array mChannelJammers = Array(); //array index is channel, value is jamming weapons beam Array mChannelBeams = Array(); //array index is channel, value is jamming weapons pod (category) Array mChannelPods = Array(); //map key is jammer weapons pod (category), value is array of channels that use the pod Map< string, Array > mPodToChannels = Map< string, Array >(); //map key is pod of interest, value is related pod Map< string, string> mPodToPod = Map< string, string>(); /////////////////////////////////////////////////////////////////////////// double RESOURCE_ROLL_ANGLE = 75.0; // degrees double DISTANCE_3D = 500000.0; // meters double SPOT_SIZE_DEFAULT = 5000000.0; // hz //double TRACK_PURGE_INTERVAL = 10.0; //seconds string JAM_TASK_STR = "Jam"; //string techniqueCountFile = "DRFM_Technique_Count.txt"; //FileIO techFile = FileIO(); // If USE_PRIORITY_LIST is 'true' then the priority lists is used to get the specified // jammer types to be used for the given target type/name of interest. If one is not found // and USE_BAND_BREAKS is also 'true' then the band breaks will be searched and used also. //bool USE_PRIORITY_LIST = true; //bool USE_BAND_BREAKS = false; bool USE_PRIORITY_LIST = false; bool USE_BAND_BREAKS = true; // used when time modulation is done with a beam and more than one target is given to that beam //each beam can have a few spots (or time slots) //bool ADD_SPOTS_FIRST = true; # "true" does time commutation before splitting the arrays. // If set to true when a new assignment comes in and cannot be allocated to a jammer in the // priority list, the dropping of lower priority tracks for the given jammer group (category) // will begin and with each cancellation of the assignmnet will be tried again until it can be // assigned or all assignments with a lower priority are cancelled. // WARNING: this may cause some weird effects as assignments can be dropped and other // ones re-assigned in their place later, plus some other strange things. //bool ALLOW_RE_QUEUEING = true; //Map< string, Array< double > > BANDLIST = Map< string, Array< double > >(); // Radar Sensor type to jammer spot size mapping Map< string, double > mSpotSize = Map< string, double >(); // Map of the target type/name to the preferred band(s) Map< string, Array< string > > mTargetBandList = Map< string, Array< string > >(); Map< string, int > mPriorityList = Map< string, int >(); // Radar Sensor Type to jammer technique mapping (note mapping integer based for now). Map< string, int > mTechniqueId = Map< string, int >(); double time1 = 0.0; double time2 = 0.0; double time3 = 0.0; double time4 = 0.0; end_script_variables // ---------------------------------------- // return the task manager object script WsfTaskManager GetTaskManager() static WsfTaskManager taskMgr; if( !taskMgr.IsValid() ) { taskMgr = (WsfTaskManager)PLATFORM.Processor(mTaskManagerName); } return taskMgr; end_script // ------------------------------------------------------------------------- script void SetThreatDataItem(string aThreatString, Array< string > aBands, double aSpotSize, int aTechniqueId, int aPriority) mTargetBandList[aThreatString] = aBands; mSpotSize[aThreatString] = aSpotSize; mTechniqueId[aThreatString] = aTechniqueId; mPriorityList[aThreatString] = aPriority; end_script include platforms/soj_threat_data.txt /* // ------------------------------------------------------------------------- script void SetBandList(string aBandTypeName, double aLowFreq, double aUpperFreq) Array< double > Bands = Array< double >(); Bands.PushBack(aLowFreq); Bands.PushBack(aUpperFreq); BANDLIST[aBandTypeName] = Bands; end_script */ // ------------------------------------------------------------------------- // A sensor detected a threat so determine the spot size to use to jam the threat. script double SpotSize(WsfTrack aTrack) double spotSize = SPOT_SIZE_DEFAULT; if (mSpotSize.Exists(aTrack.TargetName())) { spotSize = mSpotSize[aTrack.TargetName()]; } else if (mSpotSize.Exists(aTrack.TargetType())) { spotSize = mSpotSize[aTrack.TargetType()]; } return spotSize; end_script script int TargetPriority(WsfTrack aTrack) int priority = 0; if (mPriorityList.Exists(aTrack.TargetName())) { priority = mPriorityList[aTrack.TargetName()]; } else if (mPriorityList.Exists(aTrack.TargetType())) { priority = mPriorityList[aTrack.TargetType()]; } return priority; end_script script int BandPriority(string aJammerType, WsfTrack aTrack) int priority = 0; Array jammerTypes = Array(); if (mTargetBandList.Exists(aTrack.TargetName())) { jammerTypes = mTargetBandList[aTrack.TargetName()]; } else if (mTargetBandList.Exists(aTrack.TargetType())) { jammerTypes = mTargetBandList[aTrack.TargetType()]; } int N = jammerTypes.Size(); int i = 0; for (i=0; i Freq = BANDLIST.Get(aJammerType); // if ((aTrack.Frequency() > Freq[0]) && // (aTrack.Frequency() < Freq[1])) // { // return true; // } // } } writeln_d("target ", aTrack.TargetName(), " ", aTrack.TargetType(), " has no matches with ", aJammerType); return false; end_script script WsfTrack GetJobsTrack(WsfRIPRJob aJob) string name = (string)aJob.GetData("targetTrackName"); //WsfTrack jobsTrack = PLATFORM.MasterTrackList().Find(name); //return jobsTrack; #extern WsfTrack GetTrackByName(WsfPlatform, string); WsfTrack track = GetTrackByName(PLATFORM, name); return track; end_script script double CalculateJamTargetBidValue( WsfTrack aTrack, string aJammerName) WsfWeapon jammer = PLATFORM.Weapon(aJammerName); if (!jammer.IsValid()) { writeln_d("no bid, jammer not found: ", aJammerName); return -MATH.DOUBLE_MAX(); } if (!PLATFORM.WithinFieldOfView(aTrack, aJammerName)) { writeln_d("target track outside of jammers field of view, no bid! ", aTrack.TargetName(), " outside FOV of ", aJammerName); return -MATH.DOUBLE_MAX(); } if (!IsJammerBandCapable(jammer, aTrack)) { writeln_d("jammer of this type is not band capable for target, no bid! ", aJammerName, " has no bands for ", aTrack.TargetName()); return -MATH.DOUBLE_MAX(); } ############################################################################ ##should we hold off on this test? we've already checked frequency ##so effectively, this just checks if any spots are available #if (!jammer.CanJam(aTrack.Frequency())) #{ # writeln_d("jammer already full, no more jamming requests please, no bid!"); # return -MATH.DOUBLE_MAX(); #} ############################################################################ ############################################################################ ##should we hold off on this test? we might let the job board make assignments ##and not worry so much about pods and beam counts ##the job board should dynamically reassign jamming targets when necessary or optimal #if (CanAssign(jammer, 1)) #{ # writeln_d("jammer failed frequency availability check, no bid."); # return -MATH.DOUBLE_MAX(); #} ############################################################################ double JobBidValue = 0.0; #add value based on range to target JobBidValue = JobBidValue + rangeBiddingScale * 100.0 / MATH.Sqrt(PLATFORM.SlantRangeTo(aTrack)); #add value based on target priority from mission data load JobBidValue = JobBidValue + targetPriorityBidScale * TargetPriority(aTrack); #add value based on band ordering from mission data load JobBidValue = JobBidValue + bandPriorityBidScale * BandPriority(jammer.Type(), aTrack); #add value based on power the jammer is able to put on target #JobBidValue = JobBidValue + powerBidScale * JammerPower(jammer,aTrack); return JobBidValue; end_script query_bid_type jam-target if (!JOB.IsValid()) { writeln_d("job not valid, can not process, no bid!"); return -MATH.DOUBLE_MAX(); } if (mChannelJammers.Size() <= 0) { writeln_d("no jammer weapons found, impossible, no bid!"); return -MATH.DOUBLE_MAX(); } WsfTrack track = GetJobsTrack(JOB); if (!track.IsValid()) { writeln_d("track not valid for job: ", JOB.Name(), " - ", JOB.GetDescription(), ", no bid."); return -MATH.DOUBLE_MAX(); } string jammerName = mChannelJammers.Get(CHANNEL); if(!jammerName.IsValid()) { jammerName = mChannelJammers.Get(0); } if (MATH.Fabs(PLATFORM.Roll()) >= RESOURCE_ROLL_ANGLE) { writeln_d("platform is rolled beyond the resource limit!"); return -MATH.DOUBLE_MAX(); } if (PLATFORM.SlantRangeTo(track) >= DISTANCE_3D) { writeln_d("jamming target is too far away!"); return -MATH.DOUBLE_MAX(); } double jobBidValue = CalculateJamTargetBidValue( track, jammerName); return jobBidValue; end_query_bid_type script bool DoStartJamming(int aChannel, WsfTrack aTarget) string comment = "start jamming: " + aTarget.TrackId().ToString(); PLATFORM.Comment(comment); string jammerName = mChannelJammers.Get(aChannel); WsfWeapon jammer = PLATFORM.Weapon(jammerName); int beam = mChannelBeams.Get(aChannel); if (jammer.IsValid() && aTarget.FrequencyValid()) { #should already have passed these checks, when bidding #if (jammer.CanJam(aTarget.Frequency(), TechniqueType(aTarget)) && (CanAssign(jammer, 1))) #{ int beamNumber = beam; mTaskMgr = GetTaskManager(); if (!mTaskMgr.IsValid()) { writeln("ERROR: invalid task manager for jamming control!"); return false; } //StartJamming(TRACK, "Jam", jammer, TRACK.Frequency(), 5.e6, TechniqueType()); if (mTaskMgr.StartJamming(aTarget, JAM_TASK_STR, jammer, aTarget.Frequency(), SpotSize(aTarget), beamNumber, TechniqueType(aTarget))) { writeln("T=", TIME_NOW, " START JAMMING: ", jammer.Name(), " : ", PLATFORM.Name(), " - ", aTarget.TargetName(), " : ", aTarget.TargetType(), " ", aTarget.Frequency(), " : ", SpotSize(aTarget), " : ", TechniqueType(aTarget), " Beam: ", beamNumber, " Assignments: ", jammer.ActiveRequestCount()); return true; } else { writeln("CANT START JAMMING: ", jammer.Name(), ":", PLATFORM.Name(), " - ", aTarget.TargetName(), ":", aTarget.TargetType(), " ", aTarget.Frequency(), ":", SpotSize(aTarget), ":", TechniqueType(aTarget), " RequestCount=", jammer.ActiveRequestCount(), ":", jammer.MaximumRequestCount()); } #} #else if (jammer.ActiveRequestCount() < jammer.MaximumRequestCount()) if (jammer.ActiveRequestCount() < jammer.MaximumRequestCount()) { writeln("CANT JAM THE TARGET: ", jammer.Name(), ":", PLATFORM.Name(), " - ", aTarget.TargetName(), ":", aTarget.TargetType(), " ", aTarget.Frequency(), ":", SpotSize(aTarget), ":", TechniqueType(aTarget), " RequestCount=", jammer.ActiveRequestCount(), ":", jammer.MaximumRequestCount()); } } return false; end_script script bool DoStopJamming( int aChannel, WsfTrackId aTargetId ) string comment = "stop jamming: " + aTargetId.ToString(); PLATFORM.Comment(comment); string jammerName = mChannelJammers.Get(aChannel); int beam = mChannelBeams.Get(aChannel); WsfWeapon jammer = PLATFORM.Weapon(jammerName); if (jammer.IsValid()) { WsfTrack track = PLATFORM.MasterTrackList().Find(aTargetId); mTaskMgr = GetTaskManager(); if (!mTaskMgr.IsValid()) { writeln("ERROR: invalid task manager for jamming control!"); return false; } //this should return a task list with one or none tasks in it WsfTaskList taskList = mTaskMgr.AssignedTaskList(aTargetId, JAM_TASK_STR); foreach (WsfTask task in taskList) { if (!task.IsValid()) { writeln("do stop jamming: task invalid!"); continue; } if (task.ResourceName() == jammerName) { double freq = task.ResourceFrequency(); double bw = task.ResourceBandwidth(); //if (mTaskMgr.StopJamming(aTargetId, JAM_TASK_STR, jammerName, freq, bw)) if (mTaskMgr.StopJamming(aTargetId, JAM_TASK_STR, jammerName, freq, bw, beam)) { //do stuff? writeln("T=", TIME_NOW, " STOP JAMMING: ", jammerName, " : ",PLATFORM.Name(), " - ", track.TargetName(), " : ", track.TargetType(), " ", freq, " Hz, ", bw, " Hz"); return true; } else { writeln("T=", TIME_NOW, " CANT STOP JAMMING: ", jammerName, ":", PLATFORM.Name(), " - ", track.TargetName(), ":", track.TargetType(), " ", freq, " Hz, ", bw, " Hz"); return false; } } } } return true; end_script script void DoJob(WsfRIPRJob aJob, int aChannel) # double timeMark1 = GetWallClockTime(); # double timeMark2 = timeMark1; WsfTrack track; if (aJob.IsValid()) { track = GetJobsTrack(aJob); } else { //stop performing previous jamming job if (mChannelTargets.Size() > aChannel) { WsfTrackId oldTargetId = mChannelTargets.Get(aChannel); if (oldTargetId != emptyTrackId) { if (DoStopJamming(aChannel, oldTargetId)) { mChannelTargets.Set(aChannel, emptyTrackId); writeln("successfully stopped jamming old target"); } else { writeln("error: still jamming old target, will try to stop next update!"); } } } return; } //string comment = "doing job: " + aJob.GetDescription(); //PLATFORM.Comment(comment); WsfTrackId previousTargetId = mChannelTargets.Get(aChannel); string jammerName = mChannelJammers.Get(aChannel); int beam = mChannelBeams.Get(aChannel); bool targetChanged = (!track.IsValid() || (track.TrackId() != previousTargetId)); // if this channel had a previous target, and the new target is different // (or invalid, and thus different), then stop jamming the previous target // and make room for the new one if ( targetChanged && (previousTargetId != emptyTrackId) ) { if (DoStopJamming(aChannel, previousTargetId)) { mChannelTargets.Set(aChannel, emptyTrackId); previousTargetId = mChannelTargets.Get(aChannel); } } //if the new target is valid & different, and the previous target has stopped being jammed, then //start jamming the new target if (track.IsValid() && targetChanged && (previousTargetId == emptyTrackId)) { if (DoStartJamming(aChannel, track)) { mChannelTargets.Set(aChannel, track.TrackId()); } } end_script script void final_initialize() WsfWeapon jammer; int numWeapons = PLATFORM.WeaponCount(); for (int j = 0; j < numWeapons; j = j + 1) { jammer = PLATFORM.WeaponEntry(j); if (jammer.IsValid()) { string jammerPod = "none"; if ( jammer.CategoryMemberOf("left_front_pod" )) { jammerPod = "left_front_pod"; } else if (jammer.CategoryMemberOf("left_rear_pod" )) { jammerPod = "left_rear_pod"; } else if (jammer.CategoryMemberOf("right_front_pod")) { jammerPod = "right_front_pod"; } else if (jammer.CategoryMemberOf("right_rear_pod" )) { jammerPod = "right_rear_pod"; } else if (jammer.CategoryMemberOf("left_pod_lbt" )) { jammerPod = "left_pod_lbt"; } else if (jammer.CategoryMemberOf("right_pod_lbt" )) { jammerPod = "right_pod_lbt"; } string jType = jammer.Type(); if (jType == "SOJ_VHF_JAMMER" || jType == "SOJ_SBAND_JAMMER" || jType == "SOJ_XBAND_JAMMER" ) { //map these N beams with the next N channels int numBeams = jammer.MaximumBeams(); for (int k = 1; k <= numBeams; k = k + 1) { mChannelBeams.PushBack(k); //this next channel is to use beam k... mChannelJammers.PushBack(jammer.Name()); //...of this jammer mChannelPods.PushBack(jammerPod); //...on this pod Array channels = Array(); if (mPodToChannels.Exists(jammerPod)) { channels = mPodToChannels.Get(jammerPod); } int currentChannel = mChannelBeams.Size() - 1; //channels use zero-based indexing channels.PushBack(currentChannel); mPodToChannels[jammerPod] = channels; } if (numBeams <= 0) { writeln("*** WARNING: no beams on Jammer: ", jammer.Name()); } } else { writeln("*** WARNING: Jammer type: ", jType, " not recognized. Couldn\'t map jammer weapon beams to channels."); } } else { writeln("*** WARNING: Jammer weapon entry not valid: ", j); } } if (numWeapons <= 0) { writeln("*** WARNING: no weapons!!!"); } SetNumJobChannels( mChannelJammers.Size() ); string comment = "num job channels: " + (string)GetNumJobChannels(); PLATFORM.Comment(comment); writeln_d("channels: ", GetNumJobChannels(), " pods arr: ", mChannelPods.Size(), " jammers arr: ", mChannelJammers.Size(), " beams arr: ", mChannelBeams.Size()); int N = GetNumJobChannels(); for (int i = 0; i < N; i = i + 1) { string channelDescription = "channel " + (string)i + ", pod: " + mChannelPods[i] + ", jammer: " + mChannelJammers[i] + ", beam: " + (string)mChannelBeams[i]; writeln_d(channelDescription); PLATFORM.Comment(channelDescription); } writeln("Starting multi channel jammer agent for ", PLATFORM.Name()); for (int i = 0; i < GetNumJobChannels(); i = i + 1) { mChannelTargets.Set(i, emptyTrackId); } end_script on_initialize //writeln("aijam_processor on initialize"); mTaskMgr = GetTaskManager(); if (!mTaskMgr.IsValid()) { return; } ExecuteScriptAtTime(TIME_NOW + 0.01, "final_initialize"); ExecuteScript("LoadThreatData"); //writeln("aijam_processor end on initialize"); end_on_initialize script void UnBidAllJobsAllChannels(WsfRIPRProcessor commander) for (int i = 0; i < GetNumJobChannels(); i = i + 1) { commander.ClearBidsFor(PROCESSOR, i); } end_script script void UnBidOneJobAllChannels(WsfRIPRJob aJob) for (int i = 0; i < GetNumJobChannels(); i = i + 1) { aJob.UnbidJob(PROCESSOR, i); } end_script on_update double duration = 0.0; double lStartTime = GetWallClockTime(); string comment = "num tracks: " + (string)PLATFORM.MasterTrackList().Count(); //PLATFORM.Comment(comment); WsfRIPRProcessor cmdr = GetRIPRCommanderProcessor(); if (!cmdr.IsValid()) { return; } Array jobs = cmdr.GetJobs(); comment = "num jobs: " + (string)jobs.Size(); //PLATFORM.Comment(comment); writeln_d("--- on_update Platform: ", PLATFORM.Name(), ", num jobs: ", jobs.Size(), ", num channels: ", GetNumJobChannels()); time1 = 0.0; time2 = 0.0; time3 = 0.0; time4 = 0.0; //do pruning at the highest level possible, check for jammers and the roll angle first if (mChannelJammers.Size() <= 0) { writeln_d("no recognized jammer weapons on platform!"); UnBidAllJobsAllChannels(cmdr); //unbid job on all channels jobs.Clear(); //remove jobs from array, so no bids are attempted } if (MATH.Fabs(PLATFORM.Roll()) >= RESOURCE_ROLL_ANGLE) { writeln_d("platform is rolled beyond the resource limit!"); UnBidAllJobsAllChannels(cmdr); //unbid job on all channels jobs.Clear(); //remove jobs from array, so no bids are attempted } //bid on each job from our commander foreach (WsfRIPRJob aJob in jobs) { if(aJob.IsValid() && aJob.Name() == "jam-target") { double BID = -MATH.DOUBLE_MAX(); WsfTrack track = GetJobsTrack(aJob); if (track.IsValid()) { if (PLATFORM.SlantRangeTo(track) >= DISTANCE_3D) { writeln_d("jamming target is too far away: ", track.TargetName()); UnBidOneJobAllChannels(aJob); //unbid job on all channels } else { string lastJammer = ""; for (CHANNEL = 0; CHANNEL < GetNumJobChannels(); CHANNEL = CHANNEL + 1) { string curJammer = mChannelJammers[CHANNEL]; //if its the same jammer weapon, bid the same, two beams aren't different if (curJammer == lastJammer) { BID = BID; //same bid for this beam as last beam (same jammer) } else { //BID = QueryBid(aJob); BID = CalculateJamTargetBidValue( track, curJammer); lastJammer = curJammer; //update last jammer to calculate bid } aJob.BidJob(PROCESSOR, CHANNEL, BID); } } } else { writeln_d("track not valid for job: ", aJob.Name(), " - ", aJob.GetDescription(), ", no bid."); UnBidOneJobAllChannels(aJob); //unbid job on all channels } comment = "one bid was: " + (string)BID; writeln_d(comment); //PLATFORM.Comment(comment); } } double midTime = GetWallClockTime(); //iterate over the channels (beams) for each pod //take the most important jobs for that pod (greedy) and then clear the //bids for other channels (beams) when the power is gone (spent on other beams) for (int i = 0; i < GetNumJobChannels(); i = i + 1) { WsfRIPRJob job = cmdr.GetJobFor(TIME_NOW, PROCESSOR, i); DoJob(job, i); } //extra debug stuff //WsfLocalTrackList localTracks = PLATFORM.MasterTrackList(); //writeln("multi channel guy ",PLATFORM.Name()," track count: ",localTracks.Count()); //writeln("multi channel guy ",PLATFORM.Name()," job count: ",jobs.Size()); double endTime = GetWallClockTime(); //writeln("--- on_update Platform: ", PLATFORM.Name(), ", Bidding Time: ", (midTime - lStartTime)); //writeln("--- on_update Platform: ", PLATFORM.Name(), ", Do Job Time: ", (endTime - midTime)); //writeln("--- on_update Platform: ", PLATFORM.Name(), ", Whole Time: ", (endTime - lStartTime)); end_on_update end_processor