Skip to content

ELINT system for DCS. Detects and finds radars in a realistic way

License

Notifications You must be signed in to change notification settings

uriba107/DCS-Hound

Repository files navigation

Hound ELINT system for DCS

Overview

Hound ELINT is a mission script for DCS. it uses one or more assigned ELINT platforms to approximates location of transmitting enemy radars using triangulation. Platforms are pre-assigned or dynamic assigned assets, they can be Air born, ground units or stationary objects from a set list of assets available.

Hound presents data in serval methods.

  1. F10 map markers indicating estimated position of the Radar, with type and accuracy information for tactical decisions. this works best with "My AC" or "Map only" modes
  2. Hound offers a Text-To-Speech ATIS system using SRS. This feature provides a radio channel with constantly updated information about current threats.
  3. Detailed information by a "SAM controller" can be provided as TTS (via SRS) and as text messages.

System can gather information about Enemy radar deployments and help understand the tactical situation or penetrate enemy defences. Because the System is asset based, you also need to be protecting these assets, as if they are destroyed, you loose your tactical data.

Hound requires MIST and is compatible with MOOSE, Skynet IADS and High-Digit SAMs and more.

Video Intro (YouTube)

Hound Cinematic Intro video

Putting this to work

Hound system triangulates positions of radars. It does this by taking bearing readings at set times, while recording the platform position. using these plotted data points system can estimate the position. the more points you have, with greater intersection angles between them, there is a better chance of estimating the position correctly. you will never get a perfect "hit" but you may be able to get a position within a 200 meter radius, where you can can use other sensors to pinpoint for a strike, or know where you need to avoid flying.

Only specific units are ELINT capable. In order to get the best positional accuracy you want your best precision platforms positioned as close as possible and as high as possible. Remember the higher you go the longer you can see, simple physics.

placing two C-17s going race-track holding patterns at 30,000 ft can get you positional data on radars more then 200nm away, not the best accuracy of course. using a Comms Tower placed on a high mountain will provide very accurate baseline on which aircraft data can be triangulated. However, tall mountains are not very common, and clear line-of-site is a thing.

Helicopters may be of some use, but they can, using existing mission scripts, transport ground units to tall mountains deep inside enemy territory. Same goes to Fast movers like the Viggen, F-16, JF-17 or the Su-25T. they can dash into enemy territory and help you find the radars trying to hide.

Remember that the system is using a simulated DF to determine the bearing of the radar from the platform. Low precision systems will cause the calculated position to be with a higher ellipse of uncertainty for radar position. below you can find the list of working units and their sensor precision.

Resolution of platforms are derived from antenna size and emitter frequency. shout out to TLTeo for explaining the physics of this.

Hound Currently has a 10 degrees angular resolution cut-off point to avoid introducing "bad data". The the first band that is valid for a platform is denoted in the Minimum Band column.

Note: While currently not implemented. Intention of including both Viggen and the Su-25T is that they will only be able to participate if they are carrying their ELINT pods

Available assets

Airborn assets

Airplanes


Platform Accuracy Deg. (C/H Bands) Min. Band Remarks
C-130 0.65 / 0.07 A
C-17 0.57 / 0.06 A Stand-in for RC-135
An-30M 0.92 / 0.10 A
Tu-95 0.46 / 0.05 A
Tu-142 0.46 / 0.05 A
IL-76MD 0.60 / 0.06 A
H-6J 6.54 / 0.70 C
C-47 1.91 / 0.20 A
S-3B 1.59 / 0.17 A
E-2D 6.54 / 0.70 C
E-3A 5.09 / 0.55 C
An-26B 0.98 / 0.10 A
A-50 5.09 / 0.55 C
Viggen 5.09 / 0.55 C U22
Su-25T 6.54 / 0.70 C Fantasmagoria
JF-17 7.05 / 0.76 C KG-600 SPJ
F-16C 15.79 / 1.69 D Block 50 w/HTS

* Data with angular resolution below 10 deg is rejected. That is a rudimentary way to drop very bad data.

Helicopters


Platform Accuracy Deg. (C/H Bands) Min. Band
CH-47D 1.91 / 0.20 A
CH-53E 2.29 / 0.25 A
MIL-26 1.15 / 0.12 A
UH-60A 2.86 / 0.31 B
SH-60B 2.86 / 0.31 B
Mi-8MT 2.86 / 0.31 B
UH-1H 5.73 / 0.61 C
Ka-27 5.73 / 0.61 C

Ground Units

Platform Accuracy Deg. (C/H Bands) Min. Band
SPK-11 1.53 / 0.16 A
MLRS FDDM 1.53 / 0.16 A

Static Objects

Platform Accuracy Deg. (C/H Bands) Min. Band
Comms tower M 0.29 / 0.03 A

Community Mods

Platform Accuracy Deg. (C/H Bands) Min. Band
Anubis C-130J 0.65 / 0.07 A
EF-18G (CJS) 1.64 / 0.18 A
VSN EA-6B Prowler 2.54 / 0.27 B
UH-60L 2.86 / 0.31 B
RC-135W (SSS) 0.57 / 0.06 A
EC-130H (SSS) 0.65 / 0.07 A
P-3C (MAM) 0.92 / 0.10 A
P-8A (CLP) 0.65 / 0.07 A
TU-214R (CLP) 0.57 / 0.06 A

Can I have the syntax please?

Yes you can. if upgrading from Hound 0.1 please see Breaking changes

Adding Hound to a Mission

Required external scripts

MIST (by mrSkortch)

Optional scripts - required for TTS (only one of them is required, based on your preference) DCS-gRPC DCS-SimpleTextToSpeech (by ciribob)

For installation of STTS or DCS-gRPC please consult project of choice repo. Both require you to modify "DCS World/Scripts/MissionScripting.lua"
for more information of de-sanitization process, look here.

adding scripts in mission editor

NOTE the order of scripts - it's important
on a "ONCE" type action with "time more 1" condition, add the scripts in the following order

  1. MIST
  2. DCS-SimpleTextToSpeech (if TTS via STTS is desired - gRPC is implemented globally)
  3. HoundElint.lua

some screenshot as hints

Add scripts

Minimum required Code to get Hound working


The bare minimum, more customization options are available.

do
  Elint_blue = HoundElint:create(coalition.side.BLUE)
  Elint_blue:addPlatform("NAME_OF_UNIT_1")
  -- it's recommended to have at least two active platform to make system faster and more accurate
  Elint_blue:addPlatform("NAME_OF_UNIT_2")
  Elint_blue:systemOn()
  -- This is a basic setup with map markers only
  -- additional stuff (uncomment if desired)
  -- Elint_blue:enableAtis() -- ATIS requires STTS, as it is voice only
  -- Elint_blue:enableController() -- This will enable Voice+text controller messages
end

Basic Hound setup (YouTube)

Hound mission editor video

Advanced configuration

It doesn't need to make sense to you, there is actually more explanations ahead. But this is an example of a more complex configuration.

    HoundBlue = HoundElint:create(coalition.side.BLUE)
    HoundBlue:addPlatform("ELINT North") -- C-130
    HoundBlue:addPlatform("ELINT South") -- C-130
    HoundBlue:addPlatform("ELINT Galil") -- C-130
    HoundBlue:addPlatform("ELINT HERMON") -- Ground Station
    HoundBlue:addPlatform("ELINT MERON") -- Ground Station

    HoundBlue:addSector("Lebanon")
    -- HoundBlue:addSector("North Syria")
    -- HoundBlue:addSector("South Syria")

    local controller_args = {
        freq = "251.000,122.000,35.000",
        modulation = "AM,AM,FM",
        gender = "male"
    }
    local atis_args = {
        freq = "253.000,124.000",
        modulation = "AM,AM"
    }
    HoundBlue:enableController("Lebanon",controller_args)
    HoundBlue:enableAtis("Lebanon",atis_args)
    HoundBlue:enableNotifier("default")

    HoundBlue:setTransmitter("all","ELINT MERON")
    HoundBlue:enableText("all")

    HoundBlue:setZone("Lebanon","Sector_Lebanon")

    HoundBlue:setMarkerType(HOUND.MARKER.POLYGON)
    HoundBlue:enableMarkers()
    HoundBlue:enableBDA()
    HoundBlue:systemOn()

On screen Debug

when this setting is enabled, Hound will print a short status report after each update cycle. (every ~15 seconds by default) it is controlled by the onScreenDebug function. this output is disabled by default

-- to enable
    HoundBlue:onScreenDebug(true)
-- to disable
    HoundBlue:onScreenDebug(false)

Deep Dive

Initialization

First we create hound instance. on creation Hound must have a coalition assigned. this can be done in several ways.

    -- direct coalition assignment
    HoundInstance = HoundElint:create(coalition.side.BLUE)

An instance without any platforms would be created.

you can also create Hound with an initial platform. coalition will be taken from the Unit assigned. Hound adds units by using their names (or pilot name) not by a group name.

    -- create with platform (static object in this case)
    HoundInstance = HoundElint:create("Migariya_Elint")

Platforms

Platforms can be added at any time (before or after system activation)

    HoundInstance:addPlatform("ELINT_C17")

and if need be the opposite is also available

    HoundInstance:removePlatform("ELINT_C17")

please make sure you go over the available assets list of each to determine what would work best for your mission.

Energize

That's it, all you need to do now is to activate the system

    HoundInstance:systemOn()

Once activated the system will use all available platforms to locate transmitting radars. Information about these radars is updated periodicity onto the F10 map.

Note: during this first implementation, markers are updated every 2 minutes

You can of course turn it off for any reason with:

    HoundInstance:systemOff()

Handling pre-briefed contacts

In some cases you would want to always provide accurate positional information on a contact. for example a stationary SAM site you provided strike coordinated for in the Briefing. you can sync Hound to use the actual unit data as position. The contact will be treated as "Pre-Briefed" and will not update position like the others. However if a PB concat moves more then 100m from it's original position the special "pre-briefed" flag will be removed and radar will be processed as a normal contact from that point on. you can mark Unit or Group, only valid Hound Radars will be added (it will not add units it will not normally track). if a group was passed and in contains more then one valid radar, all of the radars will be added lua HoundInstance:preBriefedContact('UNIT_NAME') HoundInstance:preBriefedContact('GROUP_NAME') ## Global settings Global settings are best set early, which is why I'm listing them here. However they might effect resources that will only be explained later in this document. So if something looks out of place, don't worry about it.


Map markers

Hound uses Map markers to indicate the estimated position of the radar tracker. It's a product of the system, and only contains data user can get from the system in other ways (equivalent to making marks on a paper map). Map markers are enabled by default. In addition, if radar went offline, the marker fill will fade slowly over time until it reaches a minimum value on contact timeout (thee time in which all past contact data points are deleted).

However, some mission designers may want to disable the markers.

    HoundInstance:disableMarkers()

they can be turned back on with

    HoundInstance:enableMarkers()

Hound Supports a few different marker types for the uncertainty ellipse that can be selected. The type of marker is set per Hound instance.

    HoundInstance:setMarkerType(HOUND.MARKER.POLYGON)

the available marker types are:

HOUND.MARKER Description
NONE no ellipse is drawn (only position marker)
CIRCLE a circle of uncertainty will be drawn
DIAMOND a diamond will be drawn with 4 points representing uncertainty ellipse (Default)
OCTAGON ellipse will be drawn with 8 points (diamond with midpoints)
POLYGON ellipse will be drawn as a 16 sides polygon

Note: More points causes higher CPU usage. DIAMOND is default

Living with other marker spawning scripts

Hound does it best to play nice with other Marker generating scripts. if MOOSE is loaded Hound will default to use UTILS.GetMarkID() to get the next marker ID. if that is not available, and MIST is in version 4.5 and above. Hound will attempt to use MIST's mist.marker.getNextId() method. if none of those options is available it will use an internal counter to track mark IDs.

if from any reason you still encounter issues you can force Hound to use the internal counter by setting

HOUND.FORCE_MANAGE_MARKERS = true

By default the internal counter starts from 10,000. You can change the initial value to avoid conflicts with other numbering things (which are not MOOSE or MIST) by using the method HOUND.Utils.setInitialMarkId(). As mentioned earlier, if MOOSE or MIST v4.5 are present their numbering engine will take priority over Hound's internal Numbering. It is highly recommended that you use one of them (or HOUND.Utils.getMarkId()) for all other scripted Map markers.

In addition to all that Hound will only delete its own markers (by tracking every Marker ID it's placing)


Platform position errors

Position of the platform is a baseline used for the triangulation. In the real world however position on the platform is always never accurate. Older aircraft have INS systems that drift overtime unless updated periodically, while in newer Aircraft a less "drift" system is updated automatically from GPS. To simulate this you can enable position errors. When this setting is enabled, a random error is introduced to platform's position when stored.

    HoundInstance:enablePlatformPosErrors()

    -- disable (default)
    HoundInstance:disablePlatformPosErrors()

DBA reports

By default the Controller and Notifier will push alerts when a radar is destroyed when track is dropped. you may choose to disable this behaviour

    HoundInstance:disableBDA()

-- enable (default)
    HoundInstance:enableBDA()

-- get current value
local bool = HoundInstance:getBDA()

This setting only affects automatic marking of dead contacts. You can manually mark a contact as dead (and notifications will be transmitted) regardless of BDA settings.
To mark a contact as dead use HoundInstance:markDeadContact(radarUnit) see extended docs for more information.


Reposition Controller radio menu

By default the Controller will generate the "ELINT" root menu in the base F10 menu. You may choose to change this to a different base location in some cases.

-- target menu MUST be created BEFORE it's assigned to Radio menu
    SuperDuperMenu = missionCommands.addSubMenuForCoalition(coalition.side.BLUE,"Fantastic functionality")

-- it is highly recommended to set the new parent menu BEFORE calling enableController (but can be after configureController if called separately). 
-- If set after "enableController()" is called, in some cases a user will be required to retake his slot.
    HoundInstance:setRadioMenuParent(SuperDuperMenu)

-- after parent has been assigned you can enable controller
    HoundInstance:enableController()

NATO call signs

Sectors get automatically assigned callsigns. The callsigns are picked from a pool of names. However there is an alternate list, taken from callsigns used by RC-135 squadrons. to use this alternate call sign list by default, you'll need to set the following.

-- enable use of alternate pool
    HoundInstance:useNATOCallsignes(true)
-- disable this setting (return to use default pool)
    HoundInstance:useNATOCallsignes(false)

NATO Low-down

The ATIS system has two modes, Normal and NATO low-down. same report in both will look slightly different. in the Normal default format, ATIS will also call out radar names and Grid position.
Straight Flush 17, grid GG20, accuracy very high

it is possible to switch it to NATO LOWDOWN format.
6, ACTIVE, BULLSEYE 012 13, accuracy very high

This change is global and preformed via the use of the following:

-- enable Lowdown
    HoundInstance:enableNATO()
-- disable lowdown (revert to default)
    HoundInstance:disableNATO()

-- get current setting
    local bool = HoundInstance:getNATO()

ATIS update interval

The ATIS system by default will generate a new message every 5 minutes. you can change the update rate if desired.

-- pass desired update interval in seconds
    HoundInstance:setAtisUpdateInterval(120)

-- Default setting is
    HoundInstance:setAtisUpdateInterval(5*60)

System timers Intervals

Hound works with multiple timers that will control the frequency of internal tasks. the four timers and their default values are:

  • scan: 5s
  • process: 30s
  • menus: 60s
  • markers: 120s

scan controls the interval in which platforms are tested gains radars and data points are added.
process is the position calculation interval.
menus is the interval in which the comms menus will be computed.
markers is the interval in which all map markers will be updated.
you can change the default value if you wish by passing interval name and new value. this is normally done to tune performance impact.

for example: increasing the scan interval to 20 seconds and the process interval to 60 seconds might help when a very large number of radars are present in the missions and there is suspicion Hound is the cause.

HoundInstance:setTimerInterval("display",180)

Sectors

The next big building block of Hound are the sectors. Introduced in 0.2 this aims to solve a problem in large servers. in the past there was only one "default" sector that everyone contacted for information. In practice in large missions it was just unmanageable.

A "Sector" is a internal named object that manages communication with players. each sector is assigned a name and a callsign. when initializing Hound a "default" sector is created with the call sign "HOUND". when not passing any sector name argument, "default" sector is the sector that would be affected.

A Sector can be geo fenced, if such geofencing is is set (more on this later) only radars in and around the sector will be reported. see more under Zone management

There are two reserved sector names:

  • default - default sector name created with hound instance. it cannot be removed and some features such as geofencing is not available on it
  • all - all sectors. some settings can be changes across all sectors using the "all" keyword. this is available on generic config functions not on

Managing sectors

The most basic command is to add a sector. you will need to provide a name for the sector (not a callsign), this name will be used in the comms menu for example. so you can make it human descriptive or match your SOP .

-- Sector name must be provided
-- here are a few random examples
    HoundInstance:addSector("Sukhumi")
    HoundInstance:addSector("Abkazia")
    HoundInstance:addSector("North Syria")
    HoundInstance:addSector("RANGE 13")

You can request a list of all sector names

    HoundInstance:listSectors()

or if from some bizarre reason you would like to remove a sector

    HoundInstance:removeSector("sectorName")

Sector configuration

Sectors have a few options worth knowing.

Text messages

By default Hound will only broadcast using SRS. You can optionally enable Text messages of all controller messages (ATIS and notifier will remain Voice only). Text notification will only show up for groups that are currently checked in with a controller. enable and disable is per-sector lua HoundInstance:enableText("sectorName") HoundInstance:disableText("anotherSector") or to all of them using the "all" keyword lua HoundInstance:enableText("all") #### TTS transmissions Hound is primary built to use Text-To-Speachh messages to communicate. However if from any reason you wish to disable this feature. (which is strictly enabled by default) you can use the following

    HoundInstance:disableTTS("sectorName")
-- to re-enable
    HoundInstance:enableTTS("sectorName")

or to all of them using the "all" keyword

    HoundInstance:disableTTS("all")

Zones

Geofencing a sector will be achieved by assigning a "Zone". There are two valid polygon inputs to the Sector.

  • Draw tool free-form polygon
  • DCS Group waypoints (standard method - best practise is to use a late activation helicopter group)

it is then added to the sector using the following:

    HoundInstance:setZone("sectorName","drawToolPolygon")
    -- or 
    HoundInstance:setZone("sectorName","GroupName")

if both polygon and group share the same name. Polygon will take precedence.

There is also a special case, if "sectorName Sector" is a valid draw polygon you can use it without passing any arguments.

    -- This will try and use a polygon called "sectorName Sector" if one exists.
    HoundInstance:setZone("sectorName")

You can also get the currently set zone on the sector (nil means not zone is set)

    HoundInstance:getZone("sectorName")

To remove a zone from sector use:

    HoundInstance:removeZone("sectorName")

Transmitter

A sector can have a transmitter which will broadcast all the TTS messages for the sector. when no transmitter is assigned, everyone on the frequency will be able to hear then transmissions, without any limitations, a "Magic Satlink" if you wish.

Once transmitter is set, SRS will use transmitter's current position for the transmission forcing line-of-sight, maximum radio range and any other SRS limitation that comes with it.
If transmitter unit is destroyed, no TTS transmissions will occur. To resolve it you would either need to set a new transmitter to take over.

you can also remove the transmitter at any time to return to the default "Magic Satlink" state.

Transmitter can be a Unit or a static object, and it's called by Unit/Pilot name

    HoundInstance:setTransmitter("sectorName","AWACS_Unit")

Remove transmitter using

    HoundInstance:removeTransmitter("sectorName")

you can also use the "all" keyword for apply the transmitter to all sectors

    HoundInstance:setTransmitter("all","GCI_bunker")

Callsigns

each sector has a randomly assigned callsign. these callsigns are selected from a pool of callsigns. you can get currently assigned callsign using

local assignedCallsign = HoundInstance:getCallsign("sectorName")

If you wish you can also assign a new callsign

-- choose random callsign from the "generic" pool (default behaviour, not need to use this)
    HoundInstance:setCallsign("sectorName")

-- assign the callsign "CALLSIGN" to the sector "sectorName"
    HoundInstance:setCallsign("sectorName","CALLSIGN")

there are two callsign pools, one is generic the other is a list of callsigns for RC-135s in the USAF. if you with for a specific sector to use a callsign from the NATO list you can call

    HoundInstance:setCallsign("sectorName",true)
-- or
    HoundInstance:setCallsign("sectorName","NATO")

if you want ALL sectors to use callsigns from this pool there is a global setting for this. See Global settings -> NATO callsigns

Text-To-Speech


In addition to the map markers described above. Hound is utilizing Text-To-Speech to provide the player with information via SRS. The three communication types are:

they are all configurable as will be described the Text-To-Speach configuration segment below.

ATIS system


The Automated Tactical Information System (ATIS). Will provide an automated information message loop on a set frequency. Default frequency for ATIS is 250.500 AM. This feature can be activated in the default sector with default config using:

    HoundInstance:enableAtis()

and turned off with

    HoundInstance:disableAtis()

this however is just the very very basic way to configure it and will only affect the "default" sector. The better way to use it would be to enable it on a non-default sector

    HoundInstance:enableAtis("Lebanon")
    HoundInstance:disableAtis("Lebanon")

However, having all the ATIS in all the sectors broadcast on the same frequency isn't really useful. so you can pass configuration table then enable

    HoundInstance:configureAtis("Sukhumi",atis_conf)
    HoundInstance:enableAtis("Sukhumi")

or you can pass the configuration on enable

    HoundInstance:enableAtis("Sukhumi",atis_conf)

additional settings

  • ATIS by default will not report EWR radars as threat, but will only notify you on their presence (and how many of them are tracked in the sector). If from some reason you prefer to get a normal brief on them as well you can enable it using the following:
    HoundInstance:reportEWR("Sukhumi",true)
-- disable again with
    HoundInstance:reportEWR("Sukhumi",false)

-- and set for all of them with
    HoundInstance:reportEWR("all",true)

SAM controller


The SAM controller is the main user interface with the system. Via the F10 menu, you can request detailed information about specific tracked radars. the controller defaults to 250.00 AM

basic enable is done via

    HoundInstance:enableController()

as with the ATIS, it's recommended to activate on a non-default sector and pass configuration

    HoundInstance:configureController("Saipan",controller_config)
    HoundInstance:enableController("Saipan")

or the one liner

    HoundInstance:enableController("Saipan",controller_config)

disable is done via

    HoundInstance:disableController()
    --- or the named sector
    HoundInstance:disableController("Saipan")

Additional settings

By default a controller will alert you on new radars detected and on dead emitters. you can disable all controller alerts (does not affect the Notifier).

   HoundInstance:disableAlerts("Sukhumi")
-- enable again (default behaviour)
   HoundInstance:enableAlerts("Sukhumi")

-- and set for all of them with
   HoundInstance:disableAlerts("all")

By default the controller will provide you with MGRS in 10 digits format (5 for easting and 5 northing). this is set by a global variable you can override this to get different precision (i.e 3 will give you 6 digits MGRS)

    HOUND.setMgrsPresicion(3)

Controller message format

The controller has a fixed message structure as follows.

  • Radar UID (unique for every radar)
  • Roughly WHEN this radar was last seen
  • Roughly WHERE this radar is (using bullseye)
  • Roughly HOW ACCURATE the system is estimating the solution to be
  • Precise estimated position - using LL (repeated twice for readback/VR)
  • Precise estimated position - using MGRS
  • Elevation of Radar above Sea-level (in 50ft increments)
  • Extended uncertainty ellipse information (Major axis, Minor Axis, rotation of major axis)
  • Extended Tracking time information (How long is tracked, when last seed)

This Reads like this:

<Radar Type> <Radar UID>, [Active/Recent/stale etc.] at Bullseye XXX YY, accuracy [Very High/High/Medium/Low etc.], 
position <LL in Aircraft format>, I repeat <LL in Aircraft format>,
MGRS <MGRS with HOUND.MGRS_PRECISION>,
elevation XXXX feet MSL,
ellipse is XX by YY, aligned bearing ZZ,
Tracked for XX [minutes/seconds], last seen YY [minutes/seconds] ago.

Advanced users what wish to change this structure may do it. If you are satisfied by only suppressing the Extended uncertainty and the Extended Tracking time info you can do so by invoking HOUND.showExtendedInfo() function. This will have an affect globally.

  HOUND.showExtendedInfo(false)

If a more extensive change is desired, The recommended way to achieve it is to COPY the HOUND.Contact:generateTtsReport and HOUND.Contact:generateTextReport functions from src/301 - HoundContact_comms.lua file in this repo to a new file. In that new file perform the changes you want. To activate load the new file to the mission using Do script file AFTER the main Hound script is loaded. this will replace the original implementation without editing the original file. allowing a simpler upgrades to newer Hound versions without loosing you changes.

Notifier


This, as the name suggests is notification only agent. it functions independently of controller or ATIS and will only report pop-up and if enable radar destruction alerts. this is intended to be operated on a different frequency then the controller (which has the same alerting capacity). This may be used for improving SA on Air-To-Air frequency or on general strike channels.

Notifier has a special case when used under "default" sector when radar is inside a geo-fenced sector. In this scenario it will report using sector name rather then with location. for example:

  • Normal: Attention All Aircraft! This is HOUND. New threat detected! Straight flush 11 is now Alive, bullseye XXX YY, Grid ZZ 1 4.
  • Special case: Attention All Aircraft! this is HOUND. New thread detected! Straight flush 11 is now Alive in Bander Abbas.

by default it will broadcast on 243.000AM and 121.500AM, i.e Guard frequency. but will accept TTS configuration.

Example snippets:

  -- enable on default sector with default settings
  HoundInstance:enableNotifier()
  -- enable with custom config on separate sector
  HoundInstace:enableNotifier("Bander Abbas",notifier_config)

  -- configure and set frequency inline without enabling
  HoundInstace:enableNotifier("Qeshem",{freq=254,modulation="AM",gender="male"})

Text-To-Speach configuration


Oviously, you may want to tweak the radio to better work with you mission. this can be done using an arguments table and passing it to the configuration function.

possible settings are slightly different based on your TTS provider of choice.

by default, if correct gRPC version is present, Hound will use it over STTS to change it and use STTS regardless. you need to set a global variable (which is true by default)

  HOUND.PREFER_GRPC_TTS = false

STTS settings

        args = {
            freq = 250.000,
            modulation = "AM", -- optional
            volume = "1.0", -- optional
            speed = <speed> -- number default is 0/1 for controller/atis. range is -10 to +10 on windows TTS. for google it's 0.25 to 4.0
            gender = "male"|"female",
            culture = "en-US"|"en-UK" -- (any installed on your system)
            isGoogle = true/false -- use google TTS (requires additional STTS config)
        }

gRPC.tts settings

        args = {
            freq = 250.000,
            speed = <speed> -- optional, range is -10 to +10 on windows TTS. you can also specify a number between 50 and 250 which will be treated as speech speed (100% is normal)
            volume = "1.0", -- optional
            gender = "male"|"female", -- optional
            culture = "en-US"|"en-UK" -- (must be available on you system)
            name = "name_of_voice", -- optional (overrides gender/culture settings)
            provider = {} -- optional gRPC.tts provider settings (consult DCS-gRPC). for example ATIS works with windows TTS. controller via a cloud provider (like AWS or Azure)
      
#### applying the settings
you can override one or more, and you can also have multiple frequencies.
you then pass the table into the appropriate functions
```lua
    HoundInstance:configureController(args)
    HoundInstance:configureAtis(args)

for example:

    controller_args = {
        freq = "251,35"
        modulation = "AM,FM"
    }
    atis_args = {
        freq = 251.500,
    }
    HoundInstance:configureController(controller_args)
    HoundInstance:configureAtis(atis_args)

    HoundInstance:enableController()
    HoundInstance:enableAtis()

This will change ATIS frequency to 251.5 and enable ATIS and will enable Controller both in Text and in Voice, while transmitting on two frequencies 251.0 AM and 35 FM

Event handlers

Introduced with Hound 0.2 you now have Hound event handling. This for example allows you to preform scripted actions on specific events. available events are (Note that reserved events are not yet emitted):

name id
HOUND_ENABLED 1
HOUND_DISABLED 2
PLATFORM_ADDED 3
PLATFORM_REMOVED 4
PLATFORM_DESTROYED 5
TRANSMITTER_ADDED 6
TRANSMITTER_REMOVED 7
TRANSMITTER_DESTROYED 8
RADAR_NEW 9
RADAR_DETECTED 10
RADAR_UPDATED 11
RADAR_DESTROYED 12
RADAR_ALIVE 13
RADAR_ASLEEP 14
SITE_NEW 15 (RESERVED)
SITE_CREATED 16 (RESERVED)
SITE_UPDATED 17 (RESERVED)
SITE_REMOVED 18 (RESERVED)
SITE_ALIVE 19 (RESERVED)
SITE_ASLEEP 20 (RESERVED)

Event structure is as follows

houndEvent = {
    id = <HOUND.EVENT> enum,
    coalition = <coalition.side> enum of coalition emitting the event,
    houndId = Hound Instance ID that emitted the event,
    initiator = DCS unit or HoundContact
    time = time of the event (timer.getTimer())
}

to use them you need to create a table with the function onHoundEvent(event) and register it.

    FakeEventHandler = {}
    function FakeEventHandler:onHoundEvent(event)
        if event.coalition == coalition.side.BLUE then
            if event.id == HOUND.EVENTS.RADAR_DETECTED then
                local contact = event.initiator
                trigger.action.outTextForCoalition(event.coalition,"Let's pretend a SEAD flight was fragged to strike " .. contact:getName())
            end
            if event.id == HOUND.EVENTS.PLATFROM_DESTROYED  then
                trigger.action.outTextForCoalition(event.coalition,initiator:getName() .. "has been destroyed")
            end
        end
    end

    HOUND.addEventHandler(FakeEventHandler)

to remove use

    HOUND.removeEventHandler(CustomHoundScript)

NOTE: Event handlers are global so make sure you validate coalition or houndId as the event might be from a different Instance from a different coalition RADAR_DESTROYED event is delayed from the DCS Unit destroyed event, so unit is gone by then. unit field in a dead contact is unit-name not unit object like on other events. Try and use initiator.DCSgroupName whenever possible


Performance Tuning

when running a large mission with a huge Air defence network it is not uncommon to encounter some performance issues.
These issues are caused by the huge number of markers needed to be created and DCS' ability to manage them. Here are some tips to help you mitigate this.

  1. Disable Markers! if you don't need them, just disable them altogether.
 HoundInstance:disableMarkers()
  1. if you want some markers, then disable just the uncertainty markers, this will cut down the number of markers needed by half. the information will still be included in the description on the point marker.
HoundInstance:setMarkerType(HOUND.MARKER.NONE)
  1. in addition, you can lower the update rate of the markers. Default refresh is 120 seconds, you can set it to 180 or 240 to further cut down on the amount of markers needed.
HoundInstance:setTimerInterval("display",180)

Exports

Current implementation supports two types of export. LUA and CSV.

LUA Export

HoudnInstace:getContacts()

Calling this function will return a LUA table

 {
    ewr = { 
            count = 0,
            contacts = {}
          },
    sam = {
            count = 0,
            contacts = {}
          }
}

Each contact will be added to the appropriate category and count will be updated to match number of contacts in each category. data structure of each record will follow this pattern.

{
    typeName = <String ("straight flush","P-19")> 
    uid = <int (2 digits)> 
    DCSunitName = <String (Name of actual DCS Unit)>
    maxWeaponsRange = <Int (Max range of group weapons in Meters)>
    last_seen = <float (time last spotted by platform in seconds, timer.getAbsTime)>
    detected_by = <table (list of platform names that detected contact)>
    if contact has position then
        pos = <table (DCS point of estimated position)>
        LL = {
            lat = <Float>,
            lon = <Float>
        }
        accuracy = <String>
        uncertenty = {
            major = <Int (meters)>,
            minor = <Int (meters)>,
            heading = <Float (deg)>
        }
    end
}

CSV export

HoundInstance:dumpIntelBrief()

this will crate a file in the DCS saved games folder. default filename is "hound_contacts_XX.csv" (where 'XX' is the Hound instance UID) you can specify a filename if desired:

HoundInstance:dumpIntelBrief("custom_name.csv")

CSV structure:

TrackId,NatoDesignation,RadarType,State,Bullseye,Latitude,Longitude,MGRS,Accuracy,lastSeen,DCStype,DCSunit,DCSgroup,ReportGenerated

Sample data

TrackId,NatoDesignation,RadarType,State,Bullseye,Latitude,Longitude,MGRS,Accuracy,lastSeen,DCStype,DCSunit,DCSgroup,ReportGenerated
I-1,2,Fan-song,Down,187/78,33.721733,35.800634,36S YC 5951 3482,Precise,1700,SNR_75V,SYR_SA-2_TR,SYR_SA-2,1705
I-2,2 or 3,Flat Face,Active,187/78,33.723213,35.799935,36S YC 5944 3498,Precise,1705,p-19 s-125 sr,SYR_SA-2_SR,SYR_SA-2,1705
E-12,11 or 17,Snow Drift,Active,186/77,33.734985,35.821898,36S YC 6144 3634,High,1705,SA-11 Buk SR 9S18M1,SYRIA gnd 3 unit1,SYRIA gnd 3,1705
E-10,6,Straight Flush,Active,189/84,33.622484,35.727605,36S
 YC 5303 2363,High,1705,Kub 1S91 str,SYRIA gnd 2 unit1,SYRIA gnd 2,1705
E-11,6,Straight Flush,Active,181/71,33.845855,35.952393,36S YC 7318 4898,Very High,1705,Kub 1S91 str,SYRIA gnd 1 unit1,SYRIA gnd 1,1705
E-9,EWR,Box Spring,Active,185/96,33.418094,35.864466,36S YC 6636 130,Very Low,1705,1L13 EWR,EWR-SKYNET-1,EWR-SKYNET-0,1705
I-3,EWR,Box Spring,Active,147/60,34.207544,36.618624,37S BT 8059 8773,Precise,1705,1L13 EWR,EWR-SKYNET-4-1,EWR-SKYNET-4,1705
I-4,EWR,Box Spring,Active,191/81,33.678493,35.704000,36S YC 5068 2979,Precise,1705,1L13 EWR,EWR-SKYNET-1-1,EWR-SKYNET-1,1705
I-5,EWR,Box Spring,Active,170/44,34.301650,36.114852,37S BT 3446 9937,Precise,1705,1L13 EWR,EWR-SKYNET-5-1,EWR-SKYNET-5,1705
I-6,EWR,Box Spring,Active,200/75,33.820852,35.486437,36S YC 3012 4507,Precise,1705,1L13 EWR,EWR-SKYNET-6-1,EWR-SKYNET-6,1705
I-7,EWR,Box Spring,Active,185/64,33.950048,35.878007,36S YC 6597 6034,Precise,1705,1L13 EWR,EWR-SKYNET-2-1,EWR-SKYNET-2,1705
I-8,EWR,Box Spring,Active,183/52,34.151685,35.911686,36S YC 6845 8280,Precise,1705,1L13 EWR,EWR-SKYNET-3-1,EWR-SKYNET-3,17050

NOTE: This function requires you do de-sanitize io and lfs modules in DCS scripting engine.


Known Issues

  • On initial detection accuracy will usually be very high with solution nowhere near the radar actual position. This is sorted by the system as more data points are gathered. allow at least 2 minutes for contact to stabilize.
  • Adding low resolution platforms will degrade the solution as Hound currently does not reject "bad data". Hound will drop readings that have more then 10 degrees of error. but if resolution is above the threshold, but very far away, it may still degrade the resolution.
  • Overlapping of sectors is currently not recommended. you can add a small high priority sector on top of a larger sector, but this is the ONLY tested overlap, and there might be some unexpected behaviour with that.
  • MIST 4.4 is REQUIRED. However if used with MIST 4.5.103+ some a additional functionality is enabled. (e.g. SAM that threaten sectors )

Breaking changes

0.1.X to 0.2.X

If you are upgrading from 0.1 please note that some changes will be required.

  • enableController() no longer accepts boolean to enable or disable text. please use enableText() call.
  • Every function that has ATIS in it needs to be changed to have Atis - note the capitalization.
  • "name" argument passed in the TTS config table is no longer used. (silent failure)
  • setTransmitter() is now a sector function. in general passing everything directly to Instance.controller or Instance.atis will no longer work due to changes in the internal architecture.

0.2.X to 0.3.X

From 0.2 to 0.3 there was an internal change and all classes (except form HoundElint) where wrapped into HOUND class (rather then several independent classes).

  • HoundEventHandler now called HOUND.EventHandler please make sure to update you scripts

More Docs

  • Main script Documentation - all the options available for the avarage mission builder, even those I didn't write here
  • Developers Documentation - this is actually everything. You don't need this unless you intend to hack your way to glory.
  • Scripting Ideas - A random bunch of scripting ideas. feel free to suggest more via an issue or Pull-Request.

De-sanitize DCS Scripting Engine

By default the DCS scripting engine blocks all access to the OS to avoid potential security risks. some functions, most notably anything that needs to write to disk, will not work in this default state. You'll need to "De-sanitize" the DCS Scripting Engine and allow these LUA core modules to be used.

NOTE: This is DCS core files changes, that grants DCS access to functions that allows it to run potential malicious code. USE WITH CAUTION

This is done by editing a single core DCS lua file. this change will be reverted on every DCS update and will need to be re-applied. open the file <DCS_ROOT_FOLDER>/scripts/MissionScripting.lua in your favourite text editor (Notepad++ for example) in that file you'll see the following 3 lines.

sanitizeModule('os')
sanitizeModule('io')
sanitizeModule('lfs')

Each of these lines represent a core lua module that is disabled by DCS Scripting Engine. to enable them just comment out the line that corresponds to the module needed. when all 3 are enabled, that part of the file will look like this

-- sanitizeModule('os')
-- sanitizeModule('io')
-- sanitizeModule('lfs')

for example, STTS require all 3 to be available. dumpIntelBrief requires io and lfs to be available

Special thanks

And a very special thanks is (and will always be) reserved to those who choose to click the button below :)

Toss A coin to your witcher
Bonus track

About

ELINT system for DCS. Detects and finds radars in a realistic way

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Languages