Drone simulation logic: steps, models, structs TODO: data_rate, coverage, loss
This commit is contained in:
parent
a7d936fff6
commit
198830a424
@ -1,23 +1,81 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"moxitech/dns/internal/database"
|
// "moxitech/dns/internal/database"
|
||||||
"moxitech/dns/internal/server"
|
// "moxitech/dns/internal/server"
|
||||||
|
"moxitech/dns/package/math/simulator"
|
||||||
"os"
|
"os"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// var wg sync.WaitGroup = sync.WaitGroup{}
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
D_EXPORT_VARS()
|
// Пример карты высот, замените на настоящие данные
|
||||||
err := database.NewDBConnection()
|
heightData := [][]float64{
|
||||||
if err != nil {
|
{0, 10, 15, 20},
|
||||||
panic(err)
|
{5, 15, 25, 30},
|
||||||
|
{10, 20, 35, 40},
|
||||||
|
{15, 25, 40, 50},
|
||||||
}
|
}
|
||||||
err = server.SpawnServer()
|
|
||||||
if err != nil {
|
// Определяем карту высот
|
||||||
panic(err)
|
mapObj := &simulator.Map{
|
||||||
|
Name: "Example Map",
|
||||||
|
MinBound: [3]float64{-1000, -1000, 0},
|
||||||
|
MaxBound: [3]float64{1000, 1000, 500},
|
||||||
|
HeightData: heightData,
|
||||||
}
|
}
|
||||||
|
// Определяем дронов
|
||||||
|
drones := []*simulator.Drone{
|
||||||
|
{
|
||||||
|
ID: 1,
|
||||||
|
Name: "Drone 1",
|
||||||
|
Coords: [3]float64{100, 100, 50},
|
||||||
|
Params: simulator.DroneParams{
|
||||||
|
AntennaRadius: 500,
|
||||||
|
AntennaDirection: [3]float64{1, 0, 0},
|
||||||
|
Waypoints: [][3]float64{{200, 200, 50}},
|
||||||
|
Speed: 10,
|
||||||
|
MeshName: "MeshA",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
// Определяем базовые станции
|
||||||
|
baseStations := []*simulator.BaseStation{
|
||||||
|
{
|
||||||
|
ID: 1,
|
||||||
|
Name: "BaseStation1",
|
||||||
|
Coords: [3]float64{0, 0, 0},
|
||||||
|
Params: simulator.BaseStationParams{
|
||||||
|
AntennaRadius: 2000,
|
||||||
|
AntennaDirection: [3]float64{1, 0, 0},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
// Создаем симуляцию
|
||||||
|
sim := &simulator.NetworkSimulation{
|
||||||
|
Map: mapObj,
|
||||||
|
Drones: drones,
|
||||||
|
BaseStations: baseStations,
|
||||||
|
TimeStep: 5,
|
||||||
|
}
|
||||||
|
// Запуск симуляции на 30 секунд
|
||||||
|
sim.Simulate(300)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// func main() {
|
||||||
|
// D_EXPORT_VARS()
|
||||||
|
// err := database.NewDBConnection()
|
||||||
|
// if err != nil {
|
||||||
|
// panic(err)
|
||||||
|
// }
|
||||||
|
// err = server.SpawnServer()
|
||||||
|
// if err != nil {
|
||||||
|
// panic(err)
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
func D_EXPORT_VARS() {
|
func D_EXPORT_VARS() {
|
||||||
os.Setenv("SERVER_BASE_ADDRESS", "0.0.0.0:8080")
|
os.Setenv("SERVER_BASE_ADDRESS", "0.0.0.0:8080")
|
||||||
}
|
}
|
||||||
|
1
src/server/package/math/simulator/simulation_model.go
Normal file
1
src/server/package/math/simulator/simulation_model.go
Normal file
@ -0,0 +1 @@
|
|||||||
|
package simulator
|
177
src/server/package/math/simulator/simulator.go
Normal file
177
src/server/package/math/simulator/simulator.go
Normal file
@ -0,0 +1,177 @@
|
|||||||
|
package simulator
|
||||||
|
|
||||||
|
import (
|
||||||
|
"math"
|
||||||
|
"sync"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Map struct {
|
||||||
|
Name string
|
||||||
|
MinBound [3]float64
|
||||||
|
MaxBound [3]float64
|
||||||
|
HeightData [][]float64 // Двумерный массив с высотами карты
|
||||||
|
}
|
||||||
|
|
||||||
|
type DroneParams struct {
|
||||||
|
AntennaRadius float64
|
||||||
|
AntennaDirection [3]float64
|
||||||
|
Waypoints [][3]float64
|
||||||
|
Speed float64
|
||||||
|
MeshName string
|
||||||
|
}
|
||||||
|
|
||||||
|
type Drone struct {
|
||||||
|
ID int
|
||||||
|
Name string
|
||||||
|
Coords [3]float64
|
||||||
|
CurrentCoords [3]float64
|
||||||
|
Params DroneParams
|
||||||
|
}
|
||||||
|
|
||||||
|
type BaseStationParams struct {
|
||||||
|
AntennaRadius float64
|
||||||
|
AntennaDirection [3]float64
|
||||||
|
}
|
||||||
|
|
||||||
|
type BaseStation struct {
|
||||||
|
ID int
|
||||||
|
Name string
|
||||||
|
Coords [3]float64
|
||||||
|
Params BaseStationParams
|
||||||
|
}
|
||||||
|
|
||||||
|
type NetworkSimulation struct {
|
||||||
|
Map *Map
|
||||||
|
Drones []*Drone
|
||||||
|
BaseStations []*BaseStation
|
||||||
|
TimeStep int
|
||||||
|
}
|
||||||
|
|
||||||
|
// Simulate запускает симуляцию с параллельной обработкой дронов
|
||||||
|
func (sim *NetworkSimulation) Simulate(totalTime int) {
|
||||||
|
var wg sync.WaitGroup
|
||||||
|
times := totalTime / sim.TimeStep
|
||||||
|
|
||||||
|
for t := 0; t < times; t++ {
|
||||||
|
wg.Add(len(sim.Drones))
|
||||||
|
|
||||||
|
// Параллельная обработка каждого дрона
|
||||||
|
for _, drone := range sim.Drones {
|
||||||
|
go func(d *Drone) {
|
||||||
|
defer wg.Done()
|
||||||
|
|
||||||
|
// Перемещение дрона
|
||||||
|
d.Move(sim.TimeStep)
|
||||||
|
|
||||||
|
// Проверка соединения с базовой станцией
|
||||||
|
if !IsDroneInNetwork(d, sim.BaseStations, sim.Map) {
|
||||||
|
// Если дрон имеет mesh-сеть, ищем другой дрон для ретрансляции
|
||||||
|
closestDrone := FindClosestDroneToBaseStation(d, sim.Drones, sim.BaseStations[0], sim.Map)
|
||||||
|
if closestDrone != nil {
|
||||||
|
// Дрон может передавать данные через другой дрон
|
||||||
|
// Можно добавить логику для регистрации передачи данных
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}(drone)
|
||||||
|
}
|
||||||
|
|
||||||
|
wg.Wait() // Ожидание завершения всех горутин
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsInLOS проверяет, находится ли дрон в зоне прямой видимости с базовой станцией
|
||||||
|
func IsInLOS(drone *Drone, baseStation *BaseStation, mapObj *Map) bool {
|
||||||
|
return CheckLineOfSight(drone.CurrentCoords, baseStation.Coords, mapObj)
|
||||||
|
}
|
||||||
|
|
||||||
|
// CheckLineOfSight проверяет прямую видимость между двумя точками с учетом рельефа карты
|
||||||
|
func CheckLineOfSight(from, to [3]float64, mapObj *Map) bool {
|
||||||
|
steps := 100 // Количество шагов для дискретизации
|
||||||
|
dx := (to[0] - from[0]) / float64(steps)
|
||||||
|
dy := (to[1] - from[1]) / float64(steps)
|
||||||
|
dz := (to[2] - from[2]) / float64(steps)
|
||||||
|
|
||||||
|
for i := 0; i <= steps; i++ {
|
||||||
|
x := from[0] + float64(i)*dx
|
||||||
|
y := from[1] + float64(i)*dy
|
||||||
|
z := from[2] + float64(i)*dz
|
||||||
|
|
||||||
|
if z <= GetHeightAt(mapObj, x, y) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetHeightAt возвращает высоту рельефа на карте для данной координаты
|
||||||
|
func GetHeightAt(mapObj *Map, x, y float64) float64 {
|
||||||
|
// Предположим, что высота карты представлена как двумерный массив
|
||||||
|
// x, y должны быть приведены к индексам этого массива
|
||||||
|
if x < mapObj.MinBound[0] || x > mapObj.MaxBound[0] || y < mapObj.MinBound[1] || y > mapObj.MaxBound[1] {
|
||||||
|
return mapObj.MinBound[2] // Если за пределами карты, возвращаем минимальную высоту
|
||||||
|
}
|
||||||
|
|
||||||
|
// Преобразуем координаты в индексы
|
||||||
|
xIndex := int((x - mapObj.MinBound[0]) / (mapObj.MaxBound[0] - mapObj.MinBound[0]) * float64(len(mapObj.HeightData[0])))
|
||||||
|
yIndex := int((y - mapObj.MinBound[1]) / (mapObj.MaxBound[1] - mapObj.MinBound[1]) * float64(len(mapObj.HeightData)))
|
||||||
|
|
||||||
|
// Возвращаем соответствующую высоту
|
||||||
|
return mapObj.HeightData[yIndex][xIndex]
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsDroneInNetwork проверяет, может ли дрон подключиться к базовой станции
|
||||||
|
func IsDroneInNetwork(drone *Drone, baseStations []*BaseStation, mapObj *Map) bool {
|
||||||
|
for _, base := range baseStations {
|
||||||
|
if IsInLOS(drone, base, mapObj) && euclideanDistance(drone.CurrentCoords, base.Coords) <= base.Params.AntennaRadius {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// Move перемещает дрон по точкам следования
|
||||||
|
func (d *Drone) Move(timeStep int) {
|
||||||
|
if len(d.Params.Waypoints) > 0 {
|
||||||
|
target := d.Params.Waypoints[0]
|
||||||
|
direction := [3]float64{
|
||||||
|
target[0] - d.CurrentCoords[0],
|
||||||
|
target[1] - d.CurrentCoords[1],
|
||||||
|
target[2] - d.CurrentCoords[2],
|
||||||
|
}
|
||||||
|
|
||||||
|
distance := math.Sqrt(direction[0]*direction[0] + direction[1]*direction[1] + direction[2]*direction[2])
|
||||||
|
moveDistance := d.Params.Speed * float64(timeStep)
|
||||||
|
|
||||||
|
// Обновляем координаты
|
||||||
|
for i := 0; i < 3; i++ {
|
||||||
|
d.CurrentCoords[i] += direction[i] / distance * moveDistance
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// FindClosestDroneToBaseStation находит ближайший дрон к базовой станции в mesh-сети
|
||||||
|
func FindClosestDroneToBaseStation(drone *Drone, allDrones []*Drone, baseStation *BaseStation, mapObj *Map) *Drone {
|
||||||
|
var closestDrone *Drone
|
||||||
|
minDistance := math.MaxFloat64
|
||||||
|
|
||||||
|
for _, otherDrone := range allDrones {
|
||||||
|
if otherDrone.ID == drone.ID || otherDrone.Params.MeshName != drone.Params.MeshName {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if IsInLOS(otherDrone, baseStation, mapObj) {
|
||||||
|
distance := euclideanDistance(otherDrone.CurrentCoords, baseStation.Coords)
|
||||||
|
if distance < minDistance {
|
||||||
|
minDistance = distance
|
||||||
|
closestDrone = otherDrone
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return closestDrone
|
||||||
|
}
|
||||||
|
|
||||||
|
// euclideanDistance рассчитывает евклидово расстояние между двумя точками
|
||||||
|
func euclideanDistance(p1, p2 [3]float64) float64 {
|
||||||
|
return math.Sqrt(math.Pow(p2[0]-p1[0], 2) + math.Pow(p2[1]-p1[1], 2) + math.Pow(p2[2]-p1[2], 2))
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user