From 4ee6865209e11b3ae16b1498269413db4a5845c2 Mon Sep 17 00:00:00 2001 From: James Packer Date: Tue, 17 Mar 2026 08:19:29 +0000 Subject: [PATCH 1/7] Initial stages for RACON implementation. --- src/RadarCalculation.cpp | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/src/RadarCalculation.cpp b/src/RadarCalculation.cpp index 45d37f27..3a3e7fc8 100644 --- a/src/RadarCalculation.cpp +++ b/src/RadarCalculation.cpp @@ -779,6 +779,7 @@ void RadarCalculation::scan(irr::core::vector3d offsetPosition, const T //Some tuning constants irr::f32 radarFactorLand=2.0; irr::f32 radarFactorVessel=0.0001; + irr::f32 radarFactorRACON= radarFactorVessel * pow(1852.0/200.0, 2); // for Equivalent RCS of 1m2 at 200m(Fig 8.11, Target detection by marine radar) //Convert range to cell size irr::f32 cellLength = M_IN_NM*radarRangeNm.at(radarRangeIndex)/rangeResolution; ; //Assume that radarRangeIndex is in bounds @@ -805,12 +806,16 @@ void RadarCalculation::scan(irr::core::vector3d offsetPosition, const T currentScanAngle = ((irr::f32) currentScanLine / (irr::f32) angularResolution) * 360.0f; irr::f32 scanSlope = -0.5; //Slope at start of scan (in metres/metre) - Make slightly negative so vessel contacts close in get detected + + // clear this line (before the main scan loop, so we can add things like racon which will appear beyond contact + for (irr::u32 currentStep = 1; currentStep < rangeResolution; currentStep++) { //Note that currentStep starts as 1, not 0. This is used in anti-rain clutter filter, which checks element at currentStep-1 + scanArray[currentScanLine][currentStep] = 0.0; + } + + for (irr::u32 currentStep = 1; currentStep offsetPosition, const T irr::f32 radarEchoStrength = radarFactorVessel * std::pow(M_IN_NM/localRange,4) * radarData.at(thisContact).rcs; scanArray[currentScanLine][currentStep] += radarEchoStrength; + // Testing for RACON - fill to half range with echo + irr::f32 raconEchoStart = currentStep * cellLength + 50; + irr::f32 raconEchoEnd = rangeResolution * cellLength / 2.0; + irr::f32 raconEchoStrength = radarFactorRACON * std::pow(M_IN_NM / localRange, 2); //RACON / SART goes with inverse square law as we are receiving the direct signal, not echo + for (irr::u32 raconStep = currentStep; raconStep < rangeResolution; raconStep++) { + + if ((raconStep * cellLength >= raconEchoStart) && (raconStep * cellLength <= raconEchoEnd)) { + scanArray[currentScanLine][raconStep] += raconEchoStrength; + } + } + //Start ARPA section // ARPA mode - 0: Off/Manual, 1: MARPA, 2: ARPA if (arpaMode > 0 && radarEchoStrength*2 > localNoise) { From c2d122cb533d45d42236f1b6a091afeb2f7a9a59 Mon Sep 17 00:00:00 2001 From: James Packer Date: Tue, 17 Mar 2026 08:51:11 +0000 Subject: [PATCH 2/7] Start to structure RACON code. --- src/RadarCalculation.cpp | 28 +++++++++++++++++++--------- src/RadarCalculation.hpp | 1 + 2 files changed, 20 insertions(+), 9 deletions(-) diff --git a/src/RadarCalculation.cpp b/src/RadarCalculation.cpp index 3a3e7fc8..b401d77f 100644 --- a/src/RadarCalculation.cpp +++ b/src/RadarCalculation.cpp @@ -898,15 +898,10 @@ void RadarCalculation::scan(irr::core::vector3d offsetPosition, const T irr::f32 radarEchoStrength = radarFactorVessel * std::pow(M_IN_NM/localRange,4) * radarData.at(thisContact).rcs; scanArray[currentScanLine][currentStep] += radarEchoStrength; - // Testing for RACON - fill to half range with echo - irr::f32 raconEchoStart = currentStep * cellLength + 50; - irr::f32 raconEchoEnd = rangeResolution * cellLength / 2.0; - irr::f32 raconEchoStrength = radarFactorRACON * std::pow(M_IN_NM / localRange, 2); //RACON / SART goes with inverse square law as we are receiving the direct signal, not echo - for (irr::u32 raconStep = currentStep; raconStep < rangeResolution; raconStep++) { - - if ((raconStep * cellLength >= raconEchoStart) && (raconStep * cellLength <= raconEchoEnd)) { - scanArray[currentScanLine][raconStep] += raconEchoStrength; - } + std::string testRaconCode = "M"; + if (testRaconCode != "") { + irr::f32 raconEchoStrength = radarFactorRACON * std::pow(M_IN_NM / localRange, 2); //RACON / SART goes with inverse square law as we are receiving the direct signal, not echo + addRaconString(raconEchoStrength, cellLength, localRange, testRaconCode); } //Start ARPA section @@ -1151,6 +1146,21 @@ void RadarCalculation::scan(irr::core::vector3d offsetPosition, const T } +void RadarCalculation::addRaconString(irr::f32 raconEchoStrength, irr::f32 cellLength, irr::f32 contactRange, std::string raconCode) +{ + // Testing for RACON - fill for 1 Nm + irr::f32 raconEchoStart = contactRange + 50; + irr::f32 raconEchoEnd = contactRange + 1852; + + // As with other radar scans, start sweep at 1 (0 reserved so we can do rain clutter 'graient' calculation) + for (irr::u32 raconStep = 1; raconStep < rangeResolution; raconStep++) { + + if ((raconStep * cellLength >= raconEchoStart) && (raconStep * cellLength <= raconEchoEnd)) { + scanArray[currentScanLine][raconStep] += raconEchoStrength; + } + } +} + void RadarCalculation::addManualPoint(bool newContact, irr::core::vector3d offsetPosition, const OwnShip& ownShip, uint64_t absoluteTime) { // Assumes that CursorRangeNm and CursorBrg reflect the current cursor point diff --git a/src/RadarCalculation.hpp b/src/RadarCalculation.hpp index c669dacd..00e006d7 100644 --- a/src/RadarCalculation.hpp +++ b/src/RadarCalculation.hpp @@ -230,6 +230,7 @@ class RadarCalculation std::vector radarRangeNm; void scan(irr::core::vector3d offsetPosition, const Terrain& terrain, const OwnShip& ownShip, const Buoys& buoys, const OtherShips& otherShips, irr::f32 weather, irr::f32 rain, irr::f32 tideHeight, irr::f32 deltaTime, uint64_t absoluteTime); + void addRaconString(irr::f32 raconEchoStrength, irr::f32 cellLength, irr::f32 contactRange, std::string raconCode); void updateARPA(irr::core::vector3d offsetPosition, const OwnShip& ownShip, uint64_t absoluteTime); void updateArpaEstimate(ARPAContact& thisArpaContact, int contactID, const OwnShip& ownShip, irr::core::vector3d absolutePosition, uint64_t absoluteTime); irr::f32 radarNoise(irr::f32 radarNoiseLevel, irr::f32 radarSeaClutter, irr::f32 radarRainClutter, irr::f32 weather, irr::f32 radarRange,irr::f32 radarBrgDeg, irr::f32 windDirectionDeg, irr::f32 radarInclinationAngle, irr::f32 rainIntensity); From b56f545507e725efb2e3bfc53c634d64afc930ee Mon Sep 17 00:00:00 2001 From: James Packer Date: Tue, 17 Mar 2026 19:04:13 +0000 Subject: [PATCH 3/7] Mostly implemented racon return. Need to set on/off time, and allow racon code to be configured. --- src/RadarCalculation.cpp | 163 ++++++++++++++++++++++++++++++++++++++- src/RadarCalculation.hpp | 1 + 2 files changed, 160 insertions(+), 4 deletions(-) diff --git a/src/RadarCalculation.cpp b/src/RadarCalculation.cpp index b401d77f..6823490b 100644 --- a/src/RadarCalculation.cpp +++ b/src/RadarCalculation.cpp @@ -898,7 +898,7 @@ void RadarCalculation::scan(irr::core::vector3d offsetPosition, const T irr::f32 radarEchoStrength = radarFactorVessel * std::pow(M_IN_NM/localRange,4) * radarData.at(thisContact).rcs; scanArray[currentScanLine][currentStep] += radarEchoStrength; - std::string testRaconCode = "M"; + std::string testRaconCode = "SOS"; if (testRaconCode != "") { irr::f32 raconEchoStrength = radarFactorRACON * std::pow(M_IN_NM / localRange, 2); //RACON / SART goes with inverse square law as we are receiving the direct signal, not echo addRaconString(raconEchoStrength, cellLength, localRange, testRaconCode); @@ -1148,9 +1148,161 @@ void RadarCalculation::scan(irr::core::vector3d offsetPosition, const T void RadarCalculation::addRaconString(irr::f32 raconEchoStrength, irr::f32 cellLength, irr::f32 contactRange, std::string raconCode) { - // Testing for RACON - fill for 1 Nm - irr::f32 raconEchoStart = contactRange + 50; - irr::f32 raconEchoEnd = contactRange + 1852; + const irr::f32 racon_pulse_length = 750; // 'Short' racon pulse length in metres + + irr::f32 raconEchoStart = contactRange + racon_pulse_length/4; // Start 1/4th of a pulse beyond the target + + int stringLength = raconCode.length(); + for (int i = 0; i < stringLength; i++) { + switch (raconCode[i]) { + case 'A': + addRaconReturn(raconEchoStrength, cellLength, racon_pulse_length * 1, racon_pulse_length * 1, raconEchoStart); // Short + addRaconReturn(raconEchoStrength, cellLength, racon_pulse_length * 3, racon_pulse_length * 1, raconEchoStart); // Long + break; + case 'B': + addRaconReturn(raconEchoStrength, cellLength, racon_pulse_length * 3, racon_pulse_length * 1, raconEchoStart); // Long + addRaconReturn(raconEchoStrength, cellLength, racon_pulse_length * 1, racon_pulse_length * 1, raconEchoStart); // Short + addRaconReturn(raconEchoStrength, cellLength, racon_pulse_length * 1, racon_pulse_length * 1, raconEchoStart); // Short + addRaconReturn(raconEchoStrength, cellLength, racon_pulse_length * 1, racon_pulse_length * 1, raconEchoStart); // Short + break; + case 'C': + addRaconReturn(raconEchoStrength, cellLength, racon_pulse_length * 3, racon_pulse_length * 1, raconEchoStart); // Long + addRaconReturn(raconEchoStrength, cellLength, racon_pulse_length * 1, racon_pulse_length * 1, raconEchoStart); // Short + addRaconReturn(raconEchoStrength, cellLength, racon_pulse_length * 3, racon_pulse_length * 1, raconEchoStart); // Long + addRaconReturn(raconEchoStrength, cellLength, racon_pulse_length * 1, racon_pulse_length * 1, raconEchoStart); // Short + break; + case 'D': + addRaconReturn(raconEchoStrength, cellLength, racon_pulse_length * 3, racon_pulse_length * 1, raconEchoStart); // Long + addRaconReturn(raconEchoStrength, cellLength, racon_pulse_length * 1, racon_pulse_length * 1, raconEchoStart); // Short + addRaconReturn(raconEchoStrength, cellLength, racon_pulse_length * 1, racon_pulse_length * 1, raconEchoStart); // Short + break; + case 'E': + addRaconReturn(raconEchoStrength, cellLength, racon_pulse_length * 1, racon_pulse_length * 1, raconEchoStart); // Short + break; + case 'F': + addRaconReturn(raconEchoStrength, cellLength, racon_pulse_length * 1, racon_pulse_length * 1, raconEchoStart); // Short + addRaconReturn(raconEchoStrength, cellLength, racon_pulse_length * 1, racon_pulse_length * 1, raconEchoStart); // Short + addRaconReturn(raconEchoStrength, cellLength, racon_pulse_length * 3, racon_pulse_length * 1, raconEchoStart); // Long + addRaconReturn(raconEchoStrength, cellLength, racon_pulse_length * 1, racon_pulse_length * 1, raconEchoStart); // Short + break; + case 'G': + addRaconReturn(raconEchoStrength, cellLength, racon_pulse_length * 3, racon_pulse_length * 1, raconEchoStart); // Long + addRaconReturn(raconEchoStrength, cellLength, racon_pulse_length * 3, racon_pulse_length * 1, raconEchoStart); // Long + addRaconReturn(raconEchoStrength, cellLength, racon_pulse_length * 1, racon_pulse_length * 1, raconEchoStart); // Short + break; + case 'H': + addRaconReturn(raconEchoStrength, cellLength, racon_pulse_length * 1, racon_pulse_length * 1, raconEchoStart); // Short + addRaconReturn(raconEchoStrength, cellLength, racon_pulse_length * 1, racon_pulse_length * 1, raconEchoStart); // Short + addRaconReturn(raconEchoStrength, cellLength, racon_pulse_length * 1, racon_pulse_length * 1, raconEchoStart); // Short + addRaconReturn(raconEchoStrength, cellLength, racon_pulse_length * 1, racon_pulse_length * 1, raconEchoStart); // Short + break; + case 'I': + addRaconReturn(raconEchoStrength, cellLength, racon_pulse_length * 1, racon_pulse_length * 1, raconEchoStart); // Short + addRaconReturn(raconEchoStrength, cellLength, racon_pulse_length * 1, racon_pulse_length * 1, raconEchoStart); // Short + break; + case 'J': + addRaconReturn(raconEchoStrength, cellLength, racon_pulse_length * 1, racon_pulse_length * 1, raconEchoStart); // Short + addRaconReturn(raconEchoStrength, cellLength, racon_pulse_length * 3, racon_pulse_length * 1, raconEchoStart); // Long + addRaconReturn(raconEchoStrength, cellLength, racon_pulse_length * 3, racon_pulse_length * 1, raconEchoStart); // Long + addRaconReturn(raconEchoStrength, cellLength, racon_pulse_length * 3, racon_pulse_length * 1, raconEchoStart); // Long + break; + case 'K': + addRaconReturn(raconEchoStrength, cellLength, racon_pulse_length * 3, racon_pulse_length * 1, raconEchoStart); // Long + addRaconReturn(raconEchoStrength, cellLength, racon_pulse_length * 1, racon_pulse_length * 1, raconEchoStart); // Short + addRaconReturn(raconEchoStrength, cellLength, racon_pulse_length * 3, racon_pulse_length * 1, raconEchoStart); // Long + break; + case 'L': + addRaconReturn(raconEchoStrength, cellLength, racon_pulse_length * 1, racon_pulse_length * 1, raconEchoStart); // Short + addRaconReturn(raconEchoStrength, cellLength, racon_pulse_length * 3, racon_pulse_length * 1, raconEchoStart); // Long + addRaconReturn(raconEchoStrength, cellLength, racon_pulse_length * 1, racon_pulse_length * 1, raconEchoStart); // Short + addRaconReturn(raconEchoStrength, cellLength, racon_pulse_length * 1, racon_pulse_length * 1, raconEchoStart); // Short + break; + case 'M': + addRaconReturn(raconEchoStrength, cellLength, racon_pulse_length * 3, racon_pulse_length * 1, raconEchoStart); // Long + addRaconReturn(raconEchoStrength, cellLength, racon_pulse_length * 3, racon_pulse_length * 1, raconEchoStart); // Long + break; + case 'N': + addRaconReturn(raconEchoStrength, cellLength, racon_pulse_length * 3, racon_pulse_length * 1, raconEchoStart); // Long + addRaconReturn(raconEchoStrength, cellLength, racon_pulse_length * 1, racon_pulse_length * 1, raconEchoStart); // Short + break; + case 'O': + addRaconReturn(raconEchoStrength, cellLength, racon_pulse_length * 3, racon_pulse_length * 1, raconEchoStart); // Long + addRaconReturn(raconEchoStrength, cellLength, racon_pulse_length * 3, racon_pulse_length * 1, raconEchoStart); // Long + addRaconReturn(raconEchoStrength, cellLength, racon_pulse_length * 3, racon_pulse_length * 1, raconEchoStart); // Long + break; + case 'P': + addRaconReturn(raconEchoStrength, cellLength, racon_pulse_length * 1, racon_pulse_length * 1, raconEchoStart); // Short + addRaconReturn(raconEchoStrength, cellLength, racon_pulse_length * 3, racon_pulse_length * 1, raconEchoStart); // Long + addRaconReturn(raconEchoStrength, cellLength, racon_pulse_length * 3, racon_pulse_length * 1, raconEchoStart); // Long + addRaconReturn(raconEchoStrength, cellLength, racon_pulse_length * 1, racon_pulse_length * 1, raconEchoStart); // Short + break; + case 'Q': + addRaconReturn(raconEchoStrength, cellLength, racon_pulse_length * 3, racon_pulse_length * 1, raconEchoStart); // Long + addRaconReturn(raconEchoStrength, cellLength, racon_pulse_length * 3, racon_pulse_length * 1, raconEchoStart); // Long + addRaconReturn(raconEchoStrength, cellLength, racon_pulse_length * 1, racon_pulse_length * 1, raconEchoStart); // Short + addRaconReturn(raconEchoStrength, cellLength, racon_pulse_length * 3, racon_pulse_length * 1, raconEchoStart); // Long + break; + case 'R': + addRaconReturn(raconEchoStrength, cellLength, racon_pulse_length * 1, racon_pulse_length * 1, raconEchoStart); // Short + addRaconReturn(raconEchoStrength, cellLength, racon_pulse_length * 3, racon_pulse_length * 1, raconEchoStart); // Long + addRaconReturn(raconEchoStrength, cellLength, racon_pulse_length * 1, racon_pulse_length * 1, raconEchoStart); // Short + break; + case 'S': + addRaconReturn(raconEchoStrength, cellLength, racon_pulse_length * 1, racon_pulse_length * 1, raconEchoStart); // Short + addRaconReturn(raconEchoStrength, cellLength, racon_pulse_length * 1, racon_pulse_length * 1, raconEchoStart); // Short + addRaconReturn(raconEchoStrength, cellLength, racon_pulse_length * 1, racon_pulse_length * 1, raconEchoStart); // Short + break; + case 'T': + addRaconReturn(raconEchoStrength, cellLength, racon_pulse_length * 3, racon_pulse_length * 1, raconEchoStart); // Long + break; + case 'U': + addRaconReturn(raconEchoStrength, cellLength, racon_pulse_length * 1, racon_pulse_length * 1, raconEchoStart); // Short + addRaconReturn(raconEchoStrength, cellLength, racon_pulse_length * 1, racon_pulse_length * 1, raconEchoStart); // Short + addRaconReturn(raconEchoStrength, cellLength, racon_pulse_length * 3, racon_pulse_length * 1, raconEchoStart); // Long + break; + case 'V': + addRaconReturn(raconEchoStrength, cellLength, racon_pulse_length * 1, racon_pulse_length * 1, raconEchoStart); // Short + addRaconReturn(raconEchoStrength, cellLength, racon_pulse_length * 1, racon_pulse_length * 1, raconEchoStart); // Short + addRaconReturn(raconEchoStrength, cellLength, racon_pulse_length * 1, racon_pulse_length * 1, raconEchoStart); // Short + addRaconReturn(raconEchoStrength, cellLength, racon_pulse_length * 3, racon_pulse_length * 1, raconEchoStart); // Long + break; + case 'W': + addRaconReturn(raconEchoStrength, cellLength, racon_pulse_length * 1, racon_pulse_length * 1, raconEchoStart); // Short + addRaconReturn(raconEchoStrength, cellLength, racon_pulse_length * 3, racon_pulse_length * 1, raconEchoStart); // Long + addRaconReturn(raconEchoStrength, cellLength, racon_pulse_length * 3, racon_pulse_length * 1, raconEchoStart); // Long + break; + case 'X': + addRaconReturn(raconEchoStrength, cellLength, racon_pulse_length * 3, racon_pulse_length * 1, raconEchoStart); // Long + addRaconReturn(raconEchoStrength, cellLength, racon_pulse_length * 1, racon_pulse_length * 1, raconEchoStart); // Short + addRaconReturn(raconEchoStrength, cellLength, racon_pulse_length * 1, racon_pulse_length * 1, raconEchoStart); // Short + addRaconReturn(raconEchoStrength, cellLength, racon_pulse_length * 3, racon_pulse_length * 1, raconEchoStart); // Long + break; + case 'Y': + addRaconReturn(raconEchoStrength, cellLength, racon_pulse_length * 3, racon_pulse_length * 1, raconEchoStart); // Long + addRaconReturn(raconEchoStrength, cellLength, racon_pulse_length * 1, racon_pulse_length * 1, raconEchoStart); // Short + addRaconReturn(raconEchoStrength, cellLength, racon_pulse_length * 3, racon_pulse_length * 1, raconEchoStart); // Long + addRaconReturn(raconEchoStrength, cellLength, racon_pulse_length * 3, racon_pulse_length * 1, raconEchoStart); // Long + break; + case 'Z': + addRaconReturn(raconEchoStrength, cellLength, racon_pulse_length * 3, racon_pulse_length * 1, raconEchoStart); // Long + addRaconReturn(raconEchoStrength, cellLength, racon_pulse_length * 3, racon_pulse_length * 1, raconEchoStart); // Long + addRaconReturn(raconEchoStrength, cellLength, racon_pulse_length * 1, racon_pulse_length * 1, raconEchoStart); // Short + addRaconReturn(raconEchoStrength, cellLength, racon_pulse_length * 1, racon_pulse_length * 1, raconEchoStart); // Short + break; + default: + break; + } + + // Add space after each character + raconEchoStart = raconEchoStart + 3 * racon_pulse_length; + + } + +} + +void RadarCalculation::addRaconReturn(irr::f32 raconEchoStrength, irr::f32 cellLength, irr::f32 raconEchoLength, irr::f32 raconSpaceLength, irr::f32& raconEchoStart) +{ + irr::f32 raconEchoEnd = raconEchoStart + raconEchoLength; // As with other radar scans, start sweep at 1 (0 reserved so we can do rain clutter 'graient' calculation) for (irr::u32 raconStep = 1; raconStep < rangeResolution; raconStep++) { @@ -1159,6 +1311,9 @@ void RadarCalculation::addRaconString(irr::f32 raconEchoStrength, irr::f32 cellL scanArray[currentScanLine][raconStep] += raconEchoStrength; } } + + // Update raconEchoStart for the next character + raconEchoStart = raconEchoEnd + raconSpaceLength; } void RadarCalculation::addManualPoint(bool newContact, irr::core::vector3d offsetPosition, const OwnShip& ownShip, uint64_t absoluteTime) diff --git a/src/RadarCalculation.hpp b/src/RadarCalculation.hpp index 00e006d7..ed9505f1 100644 --- a/src/RadarCalculation.hpp +++ b/src/RadarCalculation.hpp @@ -231,6 +231,7 @@ class RadarCalculation std::vector radarRangeNm; void scan(irr::core::vector3d offsetPosition, const Terrain& terrain, const OwnShip& ownShip, const Buoys& buoys, const OtherShips& otherShips, irr::f32 weather, irr::f32 rain, irr::f32 tideHeight, irr::f32 deltaTime, uint64_t absoluteTime); void addRaconString(irr::f32 raconEchoStrength, irr::f32 cellLength, irr::f32 contactRange, std::string raconCode); + void addRaconReturn(irr::f32 raconEchoStrength, irr::f32 cellLength, irr::f32 raconEchoLength, irr::f32 raconSpaceLength, irr::f32& raconEchoStart); void updateARPA(irr::core::vector3d offsetPosition, const OwnShip& ownShip, uint64_t absoluteTime); void updateArpaEstimate(ARPAContact& thisArpaContact, int contactID, const OwnShip& ownShip, irr::core::vector3d absolutePosition, uint64_t absoluteTime); irr::f32 radarNoise(irr::f32 radarNoiseLevel, irr::f32 radarSeaClutter, irr::f32 radarRainClutter, irr::f32 weather, irr::f32 radarRange,irr::f32 radarBrgDeg, irr::f32 windDirectionDeg, irr::f32 radarInclinationAngle, irr::f32 rainIntensity); From d998a184717b497abfb586a46f611ad6432e08fd Mon Sep 17 00:00:00 2001 From: James Packer Date: Tue, 17 Mar 2026 22:16:33 +0000 Subject: [PATCH 4/7] Set RACON code from buoy.ini file --- src/Buoy.cpp | 9 ++++++--- src/Buoy.hpp | 3 ++- src/Buoys.cpp | 3 ++- src/RadarCalculation.cpp | 31 ++++++++++++++++++++++++++++--- 4 files changed, 38 insertions(+), 8 deletions(-) diff --git a/src/Buoy.cpp b/src/Buoy.cpp index d79052f6..a80de470 100644 --- a/src/Buoy.cpp +++ b/src/Buoy.cpp @@ -26,7 +26,7 @@ //using namespace irr; -Buoy::Buoy(const std::string& name, const std::string& internalName, const std::string& worldName, const irr::core::vector3df& location, irr::f32 radarCrossSection, bool floating, irr::f32 heightCorrection, irr::scene::ISceneManager* smgr, irr::IrrlichtDevice* dev) +Buoy::Buoy(const std::string& name, const std::string& internalName, const std::string& worldName, const irr::core::vector3df& location, irr::f32 radarCrossSection, std::string raconCode, bool floating, irr::f32 heightCorrection, irr::scene::ISceneManager* smgr, irr::IrrlichtDevice* dev) { std::string basePath = "Models/Buoy/" + name + "/"; @@ -100,6 +100,8 @@ Buoy::Buoy(const std::string& name, const std::string& internalName, const std:: rcs = 0.005*std::pow(length,3); //Default RCS if not set, base radar cross section on length^3 (following RCS table Ship_RCS_table.pdf) } + racon = raconCode; + this->floating = floating; //Does the buoy respond to the water } @@ -190,10 +192,11 @@ RadarData Buoy::getRadarData(irr::core::vector3df scannerPosition) const radarData.minAngle=std::min(relAngle1,relAngle2); radarData.maxAngle=std::max(relAngle1,relAngle2); + radarData.racon = racon; //Racon code if set + radarData.raconOffsetTime = 0.0; // TODO: Setup RACON data for buoys + //Initial defaults: Will need changing with full implementation radarData.hidden=false; - radarData.racon=""; //Racon code if set - radarData.raconOffsetTime=0.0; radarData.SART=false; radarData.contact = (void*)this; diff --git a/src/Buoy.hpp b/src/Buoy.hpp index 397dcbcb..8a887b72 100644 --- a/src/Buoy.hpp +++ b/src/Buoy.hpp @@ -27,7 +27,7 @@ struct RadarData; class Buoy { public: - Buoy(const std::string& name, const std::string& internalName, const std::string& worldName, const irr::core::vector3df& location, irr::f32 radarCrossSection, bool floating, irr::f32 heightCorrection, irr::scene::ISceneManager* smgr, irr::IrrlichtDevice* dev); + Buoy(const std::string& name, const std::string& internalName, const std::string& worldName, const irr::core::vector3df& location, irr::f32 radarCrossSection, std::string raconCode, bool floating, irr::f32 heightCorrection, irr::scene::ISceneManager* smgr, irr::IrrlichtDevice* dev); virtual ~Buoy(); irr::core::vector3df getPosition() const; void setPosition(irr::core::vector3df position); @@ -49,6 +49,7 @@ class Buoy irr::f32 height; //For radar calculation irr::f32 heightCorrection; irr::f32 rcs; + std::string racon; bool floating; //Does the buoy move with water (normally true, false for a post etc) bool triangleSelectorEnabled; //Keep track of this so we don't keep re-setting the selector }; diff --git a/src/Buoys.cpp b/src/Buoys.cpp index 7e9b75e4..c7b045f3 100644 --- a/src/Buoys.cpp +++ b/src/Buoys.cpp @@ -63,6 +63,7 @@ void Buoys::load(const std::string& worldName, irr::scene::ISceneManager* smgr, //get buoy RCS if set irr::f32 rcs = IniFile::iniFileTof32(scenarioBuoyFilename,IniFile::enumerate1("RCS",currentBuoy)); + std::string racon = IniFile::iniFileToString(scenarioBuoyFilename, IniFile::enumerate1("RACON", currentBuoy)); irr::f32 heightCorrection = IniFile::iniFileTof32(scenarioBuoyFilename,IniFile::enumerate1("HeightCorrection",currentBuoy)); @@ -75,7 +76,7 @@ void Buoys::load(const std::string& worldName, irr::scene::ISceneManager* smgr, //Create buoy and load into vector std::string internalName = "Buoy_"; internalName.append(std::to_string(currentBuoy-1)); // -1 as we want index from 0 - buoys.push_back(Buoy (buoyName.c_str(),internalName,worldName,irr::core::vector3df(buoyX,0.0f,buoyZ),rcs,floating,heightCorrection,smgr,dev)); + buoys.push_back(Buoy (buoyName.c_str(),internalName,worldName,irr::core::vector3df(buoyX,0.0f,buoyZ),rcs,racon,floating,heightCorrection,smgr,dev)); //Find scene node irr::scene::ISceneNode* buoyNode = buoys.back().getSceneNode(); diff --git a/src/RadarCalculation.cpp b/src/RadarCalculation.cpp index 6823490b..c7d2bd3b 100644 --- a/src/RadarCalculation.cpp +++ b/src/RadarCalculation.cpp @@ -898,10 +898,9 @@ void RadarCalculation::scan(irr::core::vector3d offsetPosition, const T irr::f32 radarEchoStrength = radarFactorVessel * std::pow(M_IN_NM/localRange,4) * radarData.at(thisContact).rcs; scanArray[currentScanLine][currentStep] += radarEchoStrength; - std::string testRaconCode = "SOS"; - if (testRaconCode != "") { + if (radarData.at(thisContact).racon != "") { irr::f32 raconEchoStrength = radarFactorRACON * std::pow(M_IN_NM / localRange, 2); //RACON / SART goes with inverse square law as we are receiving the direct signal, not echo - addRaconString(raconEchoStrength, cellLength, localRange, testRaconCode); + addRaconString(raconEchoStrength, cellLength, localRange, radarData.at(thisContact).racon); } //Start ARPA section @@ -1156,134 +1155,160 @@ void RadarCalculation::addRaconString(irr::f32 raconEchoStrength, irr::f32 cellL for (int i = 0; i < stringLength; i++) { switch (raconCode[i]) { case 'A': + case 'a': addRaconReturn(raconEchoStrength, cellLength, racon_pulse_length * 1, racon_pulse_length * 1, raconEchoStart); // Short addRaconReturn(raconEchoStrength, cellLength, racon_pulse_length * 3, racon_pulse_length * 1, raconEchoStart); // Long break; case 'B': + case 'b': addRaconReturn(raconEchoStrength, cellLength, racon_pulse_length * 3, racon_pulse_length * 1, raconEchoStart); // Long addRaconReturn(raconEchoStrength, cellLength, racon_pulse_length * 1, racon_pulse_length * 1, raconEchoStart); // Short addRaconReturn(raconEchoStrength, cellLength, racon_pulse_length * 1, racon_pulse_length * 1, raconEchoStart); // Short addRaconReturn(raconEchoStrength, cellLength, racon_pulse_length * 1, racon_pulse_length * 1, raconEchoStart); // Short break; case 'C': + case 'c': addRaconReturn(raconEchoStrength, cellLength, racon_pulse_length * 3, racon_pulse_length * 1, raconEchoStart); // Long addRaconReturn(raconEchoStrength, cellLength, racon_pulse_length * 1, racon_pulse_length * 1, raconEchoStart); // Short addRaconReturn(raconEchoStrength, cellLength, racon_pulse_length * 3, racon_pulse_length * 1, raconEchoStart); // Long addRaconReturn(raconEchoStrength, cellLength, racon_pulse_length * 1, racon_pulse_length * 1, raconEchoStart); // Short break; case 'D': + case 'd': addRaconReturn(raconEchoStrength, cellLength, racon_pulse_length * 3, racon_pulse_length * 1, raconEchoStart); // Long addRaconReturn(raconEchoStrength, cellLength, racon_pulse_length * 1, racon_pulse_length * 1, raconEchoStart); // Short addRaconReturn(raconEchoStrength, cellLength, racon_pulse_length * 1, racon_pulse_length * 1, raconEchoStart); // Short break; case 'E': + case 'e': addRaconReturn(raconEchoStrength, cellLength, racon_pulse_length * 1, racon_pulse_length * 1, raconEchoStart); // Short break; case 'F': + case 'f': addRaconReturn(raconEchoStrength, cellLength, racon_pulse_length * 1, racon_pulse_length * 1, raconEchoStart); // Short addRaconReturn(raconEchoStrength, cellLength, racon_pulse_length * 1, racon_pulse_length * 1, raconEchoStart); // Short addRaconReturn(raconEchoStrength, cellLength, racon_pulse_length * 3, racon_pulse_length * 1, raconEchoStart); // Long addRaconReturn(raconEchoStrength, cellLength, racon_pulse_length * 1, racon_pulse_length * 1, raconEchoStart); // Short break; case 'G': + case 'g': addRaconReturn(raconEchoStrength, cellLength, racon_pulse_length * 3, racon_pulse_length * 1, raconEchoStart); // Long addRaconReturn(raconEchoStrength, cellLength, racon_pulse_length * 3, racon_pulse_length * 1, raconEchoStart); // Long addRaconReturn(raconEchoStrength, cellLength, racon_pulse_length * 1, racon_pulse_length * 1, raconEchoStart); // Short break; case 'H': + case 'h': addRaconReturn(raconEchoStrength, cellLength, racon_pulse_length * 1, racon_pulse_length * 1, raconEchoStart); // Short addRaconReturn(raconEchoStrength, cellLength, racon_pulse_length * 1, racon_pulse_length * 1, raconEchoStart); // Short addRaconReturn(raconEchoStrength, cellLength, racon_pulse_length * 1, racon_pulse_length * 1, raconEchoStart); // Short addRaconReturn(raconEchoStrength, cellLength, racon_pulse_length * 1, racon_pulse_length * 1, raconEchoStart); // Short break; case 'I': + case 'i': addRaconReturn(raconEchoStrength, cellLength, racon_pulse_length * 1, racon_pulse_length * 1, raconEchoStart); // Short addRaconReturn(raconEchoStrength, cellLength, racon_pulse_length * 1, racon_pulse_length * 1, raconEchoStart); // Short break; case 'J': + case 'j': addRaconReturn(raconEchoStrength, cellLength, racon_pulse_length * 1, racon_pulse_length * 1, raconEchoStart); // Short addRaconReturn(raconEchoStrength, cellLength, racon_pulse_length * 3, racon_pulse_length * 1, raconEchoStart); // Long addRaconReturn(raconEchoStrength, cellLength, racon_pulse_length * 3, racon_pulse_length * 1, raconEchoStart); // Long addRaconReturn(raconEchoStrength, cellLength, racon_pulse_length * 3, racon_pulse_length * 1, raconEchoStart); // Long break; case 'K': + case 'k': addRaconReturn(raconEchoStrength, cellLength, racon_pulse_length * 3, racon_pulse_length * 1, raconEchoStart); // Long addRaconReturn(raconEchoStrength, cellLength, racon_pulse_length * 1, racon_pulse_length * 1, raconEchoStart); // Short addRaconReturn(raconEchoStrength, cellLength, racon_pulse_length * 3, racon_pulse_length * 1, raconEchoStart); // Long break; case 'L': + case 'l': addRaconReturn(raconEchoStrength, cellLength, racon_pulse_length * 1, racon_pulse_length * 1, raconEchoStart); // Short addRaconReturn(raconEchoStrength, cellLength, racon_pulse_length * 3, racon_pulse_length * 1, raconEchoStart); // Long addRaconReturn(raconEchoStrength, cellLength, racon_pulse_length * 1, racon_pulse_length * 1, raconEchoStart); // Short addRaconReturn(raconEchoStrength, cellLength, racon_pulse_length * 1, racon_pulse_length * 1, raconEchoStart); // Short break; case 'M': + case 'm': addRaconReturn(raconEchoStrength, cellLength, racon_pulse_length * 3, racon_pulse_length * 1, raconEchoStart); // Long addRaconReturn(raconEchoStrength, cellLength, racon_pulse_length * 3, racon_pulse_length * 1, raconEchoStart); // Long break; case 'N': + case 'n': addRaconReturn(raconEchoStrength, cellLength, racon_pulse_length * 3, racon_pulse_length * 1, raconEchoStart); // Long addRaconReturn(raconEchoStrength, cellLength, racon_pulse_length * 1, racon_pulse_length * 1, raconEchoStart); // Short break; case 'O': + case 'o': addRaconReturn(raconEchoStrength, cellLength, racon_pulse_length * 3, racon_pulse_length * 1, raconEchoStart); // Long addRaconReturn(raconEchoStrength, cellLength, racon_pulse_length * 3, racon_pulse_length * 1, raconEchoStart); // Long addRaconReturn(raconEchoStrength, cellLength, racon_pulse_length * 3, racon_pulse_length * 1, raconEchoStart); // Long break; case 'P': + case 'p': addRaconReturn(raconEchoStrength, cellLength, racon_pulse_length * 1, racon_pulse_length * 1, raconEchoStart); // Short addRaconReturn(raconEchoStrength, cellLength, racon_pulse_length * 3, racon_pulse_length * 1, raconEchoStart); // Long addRaconReturn(raconEchoStrength, cellLength, racon_pulse_length * 3, racon_pulse_length * 1, raconEchoStart); // Long addRaconReturn(raconEchoStrength, cellLength, racon_pulse_length * 1, racon_pulse_length * 1, raconEchoStart); // Short break; case 'Q': + case 'q': addRaconReturn(raconEchoStrength, cellLength, racon_pulse_length * 3, racon_pulse_length * 1, raconEchoStart); // Long addRaconReturn(raconEchoStrength, cellLength, racon_pulse_length * 3, racon_pulse_length * 1, raconEchoStart); // Long addRaconReturn(raconEchoStrength, cellLength, racon_pulse_length * 1, racon_pulse_length * 1, raconEchoStart); // Short addRaconReturn(raconEchoStrength, cellLength, racon_pulse_length * 3, racon_pulse_length * 1, raconEchoStart); // Long break; case 'R': + case 'r': addRaconReturn(raconEchoStrength, cellLength, racon_pulse_length * 1, racon_pulse_length * 1, raconEchoStart); // Short addRaconReturn(raconEchoStrength, cellLength, racon_pulse_length * 3, racon_pulse_length * 1, raconEchoStart); // Long addRaconReturn(raconEchoStrength, cellLength, racon_pulse_length * 1, racon_pulse_length * 1, raconEchoStart); // Short break; case 'S': + case 's': addRaconReturn(raconEchoStrength, cellLength, racon_pulse_length * 1, racon_pulse_length * 1, raconEchoStart); // Short addRaconReturn(raconEchoStrength, cellLength, racon_pulse_length * 1, racon_pulse_length * 1, raconEchoStart); // Short addRaconReturn(raconEchoStrength, cellLength, racon_pulse_length * 1, racon_pulse_length * 1, raconEchoStart); // Short break; case 'T': + case 't': addRaconReturn(raconEchoStrength, cellLength, racon_pulse_length * 3, racon_pulse_length * 1, raconEchoStart); // Long break; case 'U': + case 'u': addRaconReturn(raconEchoStrength, cellLength, racon_pulse_length * 1, racon_pulse_length * 1, raconEchoStart); // Short addRaconReturn(raconEchoStrength, cellLength, racon_pulse_length * 1, racon_pulse_length * 1, raconEchoStart); // Short addRaconReturn(raconEchoStrength, cellLength, racon_pulse_length * 3, racon_pulse_length * 1, raconEchoStart); // Long break; case 'V': + case 'v': addRaconReturn(raconEchoStrength, cellLength, racon_pulse_length * 1, racon_pulse_length * 1, raconEchoStart); // Short addRaconReturn(raconEchoStrength, cellLength, racon_pulse_length * 1, racon_pulse_length * 1, raconEchoStart); // Short addRaconReturn(raconEchoStrength, cellLength, racon_pulse_length * 1, racon_pulse_length * 1, raconEchoStart); // Short addRaconReturn(raconEchoStrength, cellLength, racon_pulse_length * 3, racon_pulse_length * 1, raconEchoStart); // Long break; case 'W': + case 'w': addRaconReturn(raconEchoStrength, cellLength, racon_pulse_length * 1, racon_pulse_length * 1, raconEchoStart); // Short addRaconReturn(raconEchoStrength, cellLength, racon_pulse_length * 3, racon_pulse_length * 1, raconEchoStart); // Long addRaconReturn(raconEchoStrength, cellLength, racon_pulse_length * 3, racon_pulse_length * 1, raconEchoStart); // Long break; case 'X': + case 'x': addRaconReturn(raconEchoStrength, cellLength, racon_pulse_length * 3, racon_pulse_length * 1, raconEchoStart); // Long addRaconReturn(raconEchoStrength, cellLength, racon_pulse_length * 1, racon_pulse_length * 1, raconEchoStart); // Short addRaconReturn(raconEchoStrength, cellLength, racon_pulse_length * 1, racon_pulse_length * 1, raconEchoStart); // Short addRaconReturn(raconEchoStrength, cellLength, racon_pulse_length * 3, racon_pulse_length * 1, raconEchoStart); // Long break; case 'Y': + case 'y': addRaconReturn(raconEchoStrength, cellLength, racon_pulse_length * 3, racon_pulse_length * 1, raconEchoStart); // Long addRaconReturn(raconEchoStrength, cellLength, racon_pulse_length * 1, racon_pulse_length * 1, raconEchoStart); // Short addRaconReturn(raconEchoStrength, cellLength, racon_pulse_length * 3, racon_pulse_length * 1, raconEchoStart); // Long addRaconReturn(raconEchoStrength, cellLength, racon_pulse_length * 3, racon_pulse_length * 1, raconEchoStart); // Long break; case 'Z': + case 'z': addRaconReturn(raconEchoStrength, cellLength, racon_pulse_length * 3, racon_pulse_length * 1, raconEchoStart); // Long addRaconReturn(raconEchoStrength, cellLength, racon_pulse_length * 3, racon_pulse_length * 1, raconEchoStart); // Long addRaconReturn(raconEchoStrength, cellLength, racon_pulse_length * 1, racon_pulse_length * 1, raconEchoStart); // Short From 3011a87221a3ad511d1286a832a7cc0e36298c3e Mon Sep 17 00:00:00 2001 From: James Packer Date: Sat, 21 Mar 2026 10:44:05 +0000 Subject: [PATCH 5/7] Setup racon so it isn't always on. Still need to enable this to be configured. --- src/Buoy.cpp | 3 ++- src/OtherShip.cpp | 2 -- src/RadarCalculation.cpp | 7 +++++-- src/RadarData.hpp | 4 +++- 4 files changed, 10 insertions(+), 6 deletions(-) diff --git a/src/Buoy.cpp b/src/Buoy.cpp index a80de470..448b1d8a 100644 --- a/src/Buoy.cpp +++ b/src/Buoy.cpp @@ -193,7 +193,8 @@ RadarData Buoy::getRadarData(irr::core::vector3df scannerPosition) const radarData.maxAngle=std::max(relAngle1,relAngle2); radarData.racon = racon; //Racon code if set - radarData.raconOffsetTime = 0.0; // TODO: Setup RACON data for buoys + radarData.raconOnTime = 20; //TODO: Setup RACON data for buoys + radarData.raconOffsetTime = 0; // TODO: Setup RACON data for buoys //Initial defaults: Will need changing with full implementation radarData.hidden=false; diff --git a/src/OtherShip.cpp b/src/OtherShip.cpp index 89e1a832..d81a4a02 100644 --- a/src/OtherShip.cpp +++ b/src/OtherShip.cpp @@ -454,8 +454,6 @@ RadarData OtherShip::getRadarData(irr::core::vector3df scannerPosition) const //Initial defaults: Fixme: Will need changing with full implementation radarData.hidden=false; - radarData.racon=""; //Racon code if set - radarData.raconOffsetTime=0.0; radarData.SART=false; radarData.contact = (void*)this; diff --git a/src/RadarCalculation.cpp b/src/RadarCalculation.cpp index c7d2bd3b..ecc0108c 100644 --- a/src/RadarCalculation.cpp +++ b/src/RadarCalculation.cpp @@ -899,8 +899,11 @@ void RadarCalculation::scan(irr::core::vector3d offsetPosition, const T scanArray[currentScanLine][currentStep] += radarEchoStrength; if (radarData.at(thisContact).racon != "") { - irr::f32 raconEchoStrength = radarFactorRACON * std::pow(M_IN_NM / localRange, 2); //RACON / SART goes with inverse square law as we are receiving the direct signal, not echo - addRaconString(raconEchoStrength, cellLength, localRange, radarData.at(thisContact).racon); + + if (int(absoluteTime + radarData.at(thisContact).raconOffsetTime) % 60 <= radarData.at(thisContact).raconOnTime) { + irr::f32 raconEchoStrength = radarFactorRACON * std::pow(M_IN_NM / localRange, 2); //RACON / SART goes with inverse square law as we are receiving the direct signal, not echo + addRaconString(raconEchoStrength, cellLength, localRange, radarData.at(thisContact).racon); + } } //Start ARPA section diff --git a/src/RadarData.hpp b/src/RadarData.hpp index ff4c0e02..a46794a8 100644 --- a/src/RadarData.hpp +++ b/src/RadarData.hpp @@ -41,7 +41,8 @@ struct RadarData { bool hidden; std::string racon; //Racon code if set - irr::f32 raconOffsetTime; + irr::u32 raconOnTime; //Duration on per minute, in seconds + irr::u32 raconOffsetTime; // Offset in seconds bool SART; //SART enabled? //irr::f32 radarHorizon; //Only used for tracking contacts outside current radar visibility range @@ -65,6 +66,7 @@ struct RadarData { hidden(false), racon(""), raconOffsetTime(0), + raconOnTime(0), SART(false) {} From b444adc6aa1a5ffaa506ef61fca509aa2aab451c Mon Sep 17 00:00:00 2001 From: James Packer Date: Mon, 23 Mar 2026 21:20:00 +0000 Subject: [PATCH 6/7] Use floating point modulus for RACON on/off --- src/RadarCalculation.cpp | 9 ++++----- src/RadarCalculation.hpp | 4 ++-- src/RadarData.hpp | 4 ++-- src/SimulationModel.cpp | 2 +- 4 files changed, 9 insertions(+), 10 deletions(-) diff --git a/src/RadarCalculation.cpp b/src/RadarCalculation.cpp index ecc0108c..80276e01 100644 --- a/src/RadarCalculation.cpp +++ b/src/RadarCalculation.cpp @@ -705,7 +705,7 @@ void RadarCalculation::changeRadarColourChoice() radarScreenStale = true; } -void RadarCalculation::update(irr::video::IImage * radarImage, irr::video::IImage * radarImageOverlaid, irr::core::vector3d offsetPosition, const Terrain& terrain, const OwnShip& ownShip, const Buoys& buoys, const OtherShips& otherShips, irr::f32 weather, irr::f32 rain, irr::f32 tideHeight, irr::f32 deltaTime, uint64_t absoluteTime, irr::core::vector2di mouseRelPosition, bool isMouseDown) +void RadarCalculation::update(irr::video::IImage * radarImage, irr::video::IImage * radarImageOverlaid, irr::core::vector3d offsetPosition, const Terrain& terrain, const OwnShip& ownShip, const Buoys& buoys, const OtherShips& otherShips, irr::f32 weather, irr::f32 rain, irr::f32 tideHeight, irr::f32 deltaTime, uint64_t absoluteTime, irr::f32 scenarioTime, irr::core::vector2di mouseRelPosition, bool isMouseDown) { #ifdef WITH_PROFILING @@ -753,7 +753,7 @@ void RadarCalculation::update(irr::video::IImage * radarImage, irr::video::IImag CursorRangeNm = pow(pow(cursorRangeXNm,2)+pow(cursorRangeYNm,2),0.5); } { IPROF("Scan"); - scan(offsetPosition, terrain, ownShip, buoys, otherShips, weather, rain, tideHeight, deltaTime, absoluteTime); // scan into scanArray[row (angle)][column (step)], and with filtering and amplification into scanArrayAmplified[][] + scan(offsetPosition, terrain, ownShip, buoys, otherShips, weather, rain, tideHeight, deltaTime, absoluteTime, scenarioTime); // scan into scanArray[row (angle)][column (step)], and with filtering and amplification into scanArrayAmplified[][] } { IPROF("Update ARPA"); updateARPA(offsetPosition, ownShip, absoluteTime); //From data in arpaContacts, updated in scan() } { IPROF("Render"); @@ -763,7 +763,7 @@ void RadarCalculation::update(irr::video::IImage * radarImage, irr::video::IImag } -void RadarCalculation::scan(irr::core::vector3d offsetPosition, const Terrain& terrain, const OwnShip& ownShip, const Buoys& buoys, const OtherShips& otherShips, irr::f32 weather, irr::f32 rain, irr::f32 tideHeight, irr::f32 deltaTime, uint64_t absoluteTime) +void RadarCalculation::scan(irr::core::vector3d offsetPosition, const Terrain& terrain, const OwnShip& ownShip, const Buoys& buoys, const OtherShips& otherShips, irr::f32 weather, irr::f32 rain, irr::f32 tideHeight, irr::f32 deltaTime, uint64_t absoluteTime, irr::f32 scenarioTime) { //IPROF_FUNC; @@ -899,8 +899,7 @@ void RadarCalculation::scan(irr::core::vector3d offsetPosition, const T scanArray[currentScanLine][currentStep] += radarEchoStrength; if (radarData.at(thisContact).racon != "") { - - if (int(absoluteTime + radarData.at(thisContact).raconOffsetTime) % 60 <= radarData.at(thisContact).raconOnTime) { + if (std::fmod(scenarioTime + radarData.at(thisContact).raconOffsetTime, 60.0f) <= radarData.at(thisContact).raconOnTime) { irr::f32 raconEchoStrength = radarFactorRACON * std::pow(M_IN_NM / localRange, 2); //RACON / SART goes with inverse square law as we are receiving the direct signal, not echo addRaconString(raconEchoStrength, cellLength, localRange, radarData.at(thisContact).racon); } diff --git a/src/RadarCalculation.hpp b/src/RadarCalculation.hpp index ed9505f1..41b48cea 100644 --- a/src/RadarCalculation.hpp +++ b/src/RadarCalculation.hpp @@ -171,7 +171,7 @@ class RadarCalculation irr::video::SColor getRadarSurroundColour() const; irr::f32 getBrilliance() const; void setBrilliance(irr::f32 brilliance); - void update(irr::video::IImage * radarImage, irr::video::IImage * radarImageOverlaid, irr::core::vector3d offsetPosition, const Terrain& terrain, const OwnShip& ownShip, const Buoys& buoys, const OtherShips& otherShips, irr::f32 weather, irr::f32 rain, irr::f32 tideHeight, irr::f32 deltaTime, uint64_t absoluteTime, irr::core::vector2di mouseRelPosition, bool isMouseDown); + void update(irr::video::IImage * radarImage, irr::video::IImage * radarImageOverlaid, irr::core::vector3d offsetPosition, const Terrain& terrain, const OwnShip& ownShip, const Buoys& buoys, const OtherShips& otherShips, irr::f32 weather, irr::f32 rain, irr::f32 tideHeight, irr::f32 deltaTime, uint64_t absoluteTime, irr::f32 scenarioTime, irr::core::vector2di mouseRelPosition, bool isMouseDown); private: irr::IrrlichtDevice* device; @@ -229,7 +229,7 @@ class RadarCalculation irr::f32 brilliance; std::vector radarRangeNm; - void scan(irr::core::vector3d offsetPosition, const Terrain& terrain, const OwnShip& ownShip, const Buoys& buoys, const OtherShips& otherShips, irr::f32 weather, irr::f32 rain, irr::f32 tideHeight, irr::f32 deltaTime, uint64_t absoluteTime); + void scan(irr::core::vector3d offsetPosition, const Terrain& terrain, const OwnShip& ownShip, const Buoys& buoys, const OtherShips& otherShips, irr::f32 weather, irr::f32 rain, irr::f32 tideHeight, irr::f32 deltaTime, uint64_t absoluteTime, irr::f32 scenarioTime); void addRaconString(irr::f32 raconEchoStrength, irr::f32 cellLength, irr::f32 contactRange, std::string raconCode); void addRaconReturn(irr::f32 raconEchoStrength, irr::f32 cellLength, irr::f32 raconEchoLength, irr::f32 raconSpaceLength, irr::f32& raconEchoStart); void updateARPA(irr::core::vector3d offsetPosition, const OwnShip& ownShip, uint64_t absoluteTime); diff --git a/src/RadarData.hpp b/src/RadarData.hpp index a46794a8..18b93d72 100644 --- a/src/RadarData.hpp +++ b/src/RadarData.hpp @@ -41,8 +41,8 @@ struct RadarData { bool hidden; std::string racon; //Racon code if set - irr::u32 raconOnTime; //Duration on per minute, in seconds - irr::u32 raconOffsetTime; // Offset in seconds + irr::f32 raconOnTime; //Duration on per minute, in seconds + irr::f32 raconOffsetTime; // Offset in seconds bool SART; //SART enabled? //irr::f32 radarHorizon; //Only used for tracking contacts outside current radar visibility range diff --git a/src/SimulationModel.cpp b/src/SimulationModel.cpp index 1d144b0e..800b28cc 100644 --- a/src/SimulationModel.cpp +++ b/src/SimulationModel.cpp @@ -1980,7 +1980,7 @@ SimulationModel::~SimulationModel() radarImageChosen = radarImage; radarImageOverlaidChosen = radarImageOverlaid; } - radarCalculation.update(radarImageChosen,radarImageOverlaidChosen,offsetPosition,terrain,ownShip,buoys,otherShips,weather,rainIntensity,tideHeight,deltaTime,absoluteTime,cursorPositionRadar,isMouseDown); + radarCalculation.update(radarImageChosen,radarImageOverlaidChosen,offsetPosition,terrain,ownShip,buoys,otherShips,weather,rainIntensity,tideHeight,deltaTime,absoluteTime,scenarioTime,cursorPositionRadar,isMouseDown); }{ IPROF("Update radar screen"); radarScreen.update(radarImageOverlaidChosen); }{ IPROF("Update radar camera"); From 1ee53701aaf321d9def758cc2e14c46ec51b0fdf Mon Sep 17 00:00:00 2001 From: James Packer Date: Tue, 24 Mar 2026 07:49:47 +0000 Subject: [PATCH 7/7] Make RACON on time configurable --- bin/World/SimpleEstuary/buoy.ini | 2 ++ bin/World/SimpleEstuary/radarreflector.ini | 4 ---- doc/WorldFileSpec.html | 17 ++++++++++++----- src/Buoy.cpp | 10 +++++++--- src/Buoy.hpp | 4 +++- src/Buoys.cpp | 3 ++- 6 files changed, 26 insertions(+), 14 deletions(-) delete mode 100644 bin/World/SimpleEstuary/radarreflector.ini diff --git a/bin/World/SimpleEstuary/buoy.ini b/bin/World/SimpleEstuary/buoy.ini index dc148d84..35919cbe 100644 --- a/bin/World/SimpleEstuary/buoy.ini +++ b/bin/World/SimpleEstuary/buoy.ini @@ -295,3 +295,5 @@ Lat(67)=50.0088 Type(68)="safe" Long(68)=-9.979 Lat(68)=50.0396 +Racon(68)="M" +RaconOnTime(68)=20 diff --git a/bin/World/SimpleEstuary/radarreflector.ini b/bin/World/SimpleEstuary/radarreflector.ini deleted file mode 100644 index 26d0b4f2..00000000 --- a/bin/World/SimpleEstuary/radarreflector.ini +++ /dev/null @@ -1,4 +0,0 @@ -Number=1 -Buoy(1)=68 -Height(1)=2 -Racon(1)="M" \ No newline at end of file diff --git a/doc/WorldFileSpec.html b/doc/WorldFileSpec.html index badd08e7..86e3eb52 100755 --- a/doc/WorldFileSpec.html +++ b/doc/WorldFileSpec.html @@ -172,16 +172,23 @@
terrain.ini
buoy.ini
-

Contains 1 general variable, and a set of 3 to 6 variables for each buoy defined. The global variable is Number, which is the number of +

Contains 1 general variable, and a set of 3 to 8 variables for each buoy defined. The global variable is Number, which is the number of buoys to be defined in the file. This can be zero, in which case no buoys are defined, and nothing further is required in this file. The three required variables for each buoy are Type(#), Long(#) and Lat(#). Type(#) takes the buoy type, as a text string. This must correspond to an available buoy model as defined in the Models\Buoy folder under the Bridge Command root directory. Long(#) and Lat(#) take respectively the buoy's Longitude and Latitude in standard decimal degrees. Note that only the buoy model and its location is specified here - if the buoy has a light attached, it must be specified in light.ini, as specified below. -The first optional variable is RCS(#), which sets the buoy's radar cross section in metres squared. If not set, a default value will be used. -The second optional variable is Grounded(#). If set to 1, this means that the 'buoy' will not respond to wave or tide, for example -for a post. The third optional variable is HeightCorrection, which adjusts the vertical position of the buoy, and is set in metres, with a positive -value moving the 'buoy' higher. Again this is useful for adjusting the height of a post.

+

+

The optional variables are:

+

+

    +
  • RCS(#), which sets the buoy's radar cross section in metres squared. If not set, a default value will be used.
  • +
  • Racon(#), if set to a string of 1 or more characters, this RACON code will be shown in morse code on the radar.
  • +
  • RaconOnTime(#), used with the Racon setting above, sets how many seconds per minute the RACON is active for (default 20s per minute).
  • +
  • Grounded(#), if set to 1, this means that the 'buoy' will not respond to wave or tide, for example for a post.
  • +
  • HeightCorrection(#), which adjusts the vertical position of the buoy, and is set in metres, with a positive value moving the 'buoy' higher. Again this is useful for adjusting the height of a post.
  • +
+

Note that a folder Models/Buoy can be created in the world model folder to hold buoys required for this world model.

diff --git a/src/Buoy.cpp b/src/Buoy.cpp index 448b1d8a..17ebf451 100644 --- a/src/Buoy.cpp +++ b/src/Buoy.cpp @@ -23,10 +23,11 @@ #include #include +#include //For rand() //using namespace irr; -Buoy::Buoy(const std::string& name, const std::string& internalName, const std::string& worldName, const irr::core::vector3df& location, irr::f32 radarCrossSection, std::string raconCode, bool floating, irr::f32 heightCorrection, irr::scene::ISceneManager* smgr, irr::IrrlichtDevice* dev) +Buoy::Buoy(const std::string& name, const std::string& internalName, const std::string& worldName, const irr::core::vector3df& location, irr::f32 radarCrossSection, std::string raconCode, irr::f32 raconOnTime, bool floating, irr::f32 heightCorrection, irr::scene::ISceneManager* smgr, irr::IrrlichtDevice* dev) { std::string basePath = "Models/Buoy/" + name + "/"; @@ -101,6 +102,9 @@ Buoy::Buoy(const std::string& name, const std::string& internalName, const std:: } racon = raconCode; + this->raconOnTime = raconOnTime; + + raconOffsetTime = 60.0f * (irr::f32) rand() / RAND_MAX; this->floating = floating; //Does the buoy respond to the water @@ -193,8 +197,8 @@ RadarData Buoy::getRadarData(irr::core::vector3df scannerPosition) const radarData.maxAngle=std::max(relAngle1,relAngle2); radarData.racon = racon; //Racon code if set - radarData.raconOnTime = 20; //TODO: Setup RACON data for buoys - radarData.raconOffsetTime = 0; // TODO: Setup RACON data for buoys + radarData.raconOnTime = raconOnTime; + radarData.raconOffsetTime = raconOffsetTime; //Initial defaults: Will need changing with full implementation radarData.hidden=false; diff --git a/src/Buoy.hpp b/src/Buoy.hpp index 8a887b72..6d8e9f81 100644 --- a/src/Buoy.hpp +++ b/src/Buoy.hpp @@ -27,7 +27,7 @@ struct RadarData; class Buoy { public: - Buoy(const std::string& name, const std::string& internalName, const std::string& worldName, const irr::core::vector3df& location, irr::f32 radarCrossSection, std::string raconCode, bool floating, irr::f32 heightCorrection, irr::scene::ISceneManager* smgr, irr::IrrlichtDevice* dev); + Buoy(const std::string& name, const std::string& internalName, const std::string& worldName, const irr::core::vector3df& location, irr::f32 radarCrossSection, std::string raconCode, irr::f32 raconOnTime, bool floating, irr::f32 heightCorrection, irr::scene::ISceneManager* smgr, irr::IrrlichtDevice* dev); virtual ~Buoy(); irr::core::vector3df getPosition() const; void setPosition(irr::core::vector3df position); @@ -50,6 +50,8 @@ class Buoy irr::f32 heightCorrection; irr::f32 rcs; std::string racon; + irr::f32 raconOnTime; + irr::f32 raconOffsetTime; bool floating; //Does the buoy move with water (normally true, false for a post etc) bool triangleSelectorEnabled; //Keep track of this so we don't keep re-setting the selector }; diff --git a/src/Buoys.cpp b/src/Buoys.cpp index c7b045f3..b6913e62 100644 --- a/src/Buoys.cpp +++ b/src/Buoys.cpp @@ -64,6 +64,7 @@ void Buoys::load(const std::string& worldName, irr::scene::ISceneManager* smgr, //get buoy RCS if set irr::f32 rcs = IniFile::iniFileTof32(scenarioBuoyFilename,IniFile::enumerate1("RCS",currentBuoy)); std::string racon = IniFile::iniFileToString(scenarioBuoyFilename, IniFile::enumerate1("RACON", currentBuoy)); + irr::f32 raconOnTime = IniFile::iniFileTof32(scenarioBuoyFilename,IniFile::enumerate1("RaconOnTime",currentBuoy), 20.0f); irr::f32 heightCorrection = IniFile::iniFileTof32(scenarioBuoyFilename,IniFile::enumerate1("HeightCorrection",currentBuoy)); @@ -76,7 +77,7 @@ void Buoys::load(const std::string& worldName, irr::scene::ISceneManager* smgr, //Create buoy and load into vector std::string internalName = "Buoy_"; internalName.append(std::to_string(currentBuoy-1)); // -1 as we want index from 0 - buoys.push_back(Buoy (buoyName.c_str(),internalName,worldName,irr::core::vector3df(buoyX,0.0f,buoyZ),rcs,racon,floating,heightCorrection,smgr,dev)); + buoys.push_back(Buoy (buoyName.c_str(),internalName,worldName,irr::core::vector3df(buoyX,0.0f,buoyZ),rcs,racon,raconOnTime,floating,heightCorrection,smgr,dev)); //Find scene node irr::scene::ISceneNode* buoyNode = buoys.back().getSceneNode();