diff --git a/src/server/cmd/main.go b/src/server/cmd/main.go index 1fc2f06..92c97d8 100644 --- a/src/server/cmd/main.go +++ b/src/server/cmd/main.go @@ -3,9 +3,76 @@ package main import ( "moxitech/dns/internal/database" "moxitech/dns/internal/server" + + // "fmt" + // "moxitech/dns/package/math/simulator" + // u_sorting "moxitech/dns/package/utils/sorting" "os" ) +// var wg sync.WaitGroup = sync.WaitGroup{} + +// func main() { +// // Пример карты высот, замените на настоящие данные +// heightData := [][]float64{ +// {0, 10, 15, 20}, +// {5, 15, 25, 30}, +// {10, 20, 35, 40}, +// {15, 25, 40, 50}, +// } + +// // Определяем карту высот +// 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: 2, +// } +// // Запуск симуляции на 300 секунд +// result_sim := sim.Simulate(300) +// result := u_sorting.SortMap(result_sim) +// for time, state := range result { +// for localstate, f := range state { +// fmt.Printf("%v| %v sec :: %v\n", time, localstate, f) +// } +// } + +// } + func main() { D_EXPORT_VARS() err := database.NewDBConnection() diff --git a/src/server/package/math/coverage/coverage.go b/src/server/package/math/coverage/coverage.go index 6fe40cd..c628382 100644 --- a/src/server/package/math/coverage/coverage.go +++ b/src/server/package/math/coverage/coverage.go @@ -4,7 +4,7 @@ import ( "fmt" "math" model "moxitech/dns/entity/math" - loss "moxitech/dns/package/math" + loss "moxitech/dns/package/math/loss" ) // CalculateCoverage Расчет зон радиопокрытия diff --git a/src/server/package/math/distance/distance.go b/src/server/package/math/distance/distance.go new file mode 100644 index 0000000..b0d1c8e --- /dev/null +++ b/src/server/package/math/distance/distance.go @@ -0,0 +1,8 @@ +package distance + +import "math" + +// 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)) +} diff --git a/src/server/package/math/loss.go b/src/server/package/math/loss/loss.go similarity index 100% rename from src/server/package/math/loss.go rename to src/server/package/math/loss/loss.go diff --git a/src/server/package/math/simulator/simulation_model.go b/src/server/package/math/simulator/simulation_model.go new file mode 100644 index 0000000..71a1702 --- /dev/null +++ b/src/server/package/math/simulator/simulation_model.go @@ -0,0 +1 @@ +package simulator diff --git a/src/server/package/math/simulator/simulator.go b/src/server/package/math/simulator/simulator.go new file mode 100644 index 0000000..de4310d --- /dev/null +++ b/src/server/package/math/simulator/simulator.go @@ -0,0 +1,243 @@ +package simulator + +import ( + "math" + "moxitech/dns/package/math/distance" + "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 + Modulation string // Тип модуляции (например, QPSK, QAM, OFDM) + Bandwidth float64 // Полоса частот в MHz + DataRate float64 // Скорость передачи данных в Mbps +} + +type Drone struct { + ID int + Name string + Coords [3]float64 + CurrentCoords [3]float64 + Params DroneParams +} + +type BaseStationParams struct { + AntennaRadius float64 + AntennaDirection [3]float64 + Modulation string // Тип модуляции + Bandwidth float64 // Полоса частот + DataRate 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) map[int]map[string][]interface{} { + var wg sync.WaitGroup + times := totalTime / sim.TimeStep + simulationData := make(map[int]map[string][]interface{}) + + for t := 0; t < times; t++ { + currentTime := t * sim.TimeStep + + // Создаем временное хранилище для дронов и базовых станций в данной секунде + secondState := map[string][]interface{}{ + "drones": make([]interface{}, 0), + // "baseStations": make([]interface{}, 0), + } + + 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 { + // Дрон может передавать данные через другой дрон + // Логику передачи можно добавить сюда + } + } + + // Добавляем данные о дроне в текущее состояние + // Пример в симуляции, где обновляется информация о дроне + secondState["drones"] = append(secondState["drones"], map[string]interface{}{ + "id": d.ID, + "name": d.Name, + "coords": d.CurrentCoords, + "speed": d.Params.Speed, + "dataRate": CalculateDataRate(d.Params.Modulation, d.Params.Bandwidth), // Добавляем расчет скорости передачи + }) + + }(drone) + } + + wg.Wait() // Ожидание завершения всех горутин + + // Добавляем параметры базовых станций в текущее состояние + // TODO : для возможности динамической смены параметров базовой станции + // for _, baseStation := range sim.BaseStations { + // secondState["baseStations"] = append(secondState["baseStations"], map[string]interface{}{ + // "id": baseStation.ID, + // "name": baseStation.Name, + // "coords": baseStation.Coords, + // }) + // } + + // Сохраняем состояние для данной секунды + simulationData[currentTime] = secondState + } + + return simulationData +} + +// IsInLOS проверяет, находится ли дрон в зоне прямой видимости с базовой станцией +func IsInLOS(drone *Drone, baseStation *BaseStation, mapObj *Map) bool { + return CheckLineOfSight(drone.CurrentCoords, baseStation.Coords, mapObj) +} + +// 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) && distance.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 { + return // Если нет путевых точек, дрон останавливается + } + + 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) + + if moveDistance >= distance { + d.CurrentCoords = target + d.Params.Waypoints = d.Params.Waypoints[1:] // Удаляем достигнутую точку + } else { + for i := 0; i < 3; i++ { + d.CurrentCoords[i] += direction[i] / distance * moveDistance + } + } +} + +// CheckLineOfSight проверяет прямую видимость между двумя точками с учетом рельеф +func CheckLineOfSight(from, to [3]float64, mapObj *Map) bool { + distance := distance.EuclideanDistance(from, to) + steps := int(distance * 10) // Используем шаги, пропорциональные длине пути + 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 +} + +// 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 := distance.EuclideanDistance(otherDrone.CurrentCoords, baseStation.Coords) + if distance < minDistance { + minDistance = distance + closestDrone = otherDrone + } + } + } + + return closestDrone +} + +// CalculateDataRate рассчитывает скорость передачи данных на основе типа модуляции и полосы частот +func CalculateDataRate(modulation string, bandwidth float64) float64 { + var spectralEfficiency float64 + + switch modulation { + case "QPSK": + spectralEfficiency = 2.0 // биты/Гц + case "16QAM": + spectralEfficiency = 4.0 + case "64QAM": + spectralEfficiency = 6.0 + case "256QAM": + spectralEfficiency = 8.0 + case "OFDM": + spectralEfficiency = 10.0 + default: + spectralEfficiency = 1.0 // базовый случай + } + + return spectralEfficiency * bandwidth // скорость передачи данных в Mbps +} diff --git a/src/server/package/utils/sorting/sorting.go b/src/server/package/utils/sorting/sorting.go new file mode 100644 index 0000000..7433d10 --- /dev/null +++ b/src/server/package/utils/sorting/sorting.go @@ -0,0 +1,23 @@ +package u_sorting + +import "sort" + +// Функция сортировки карты по ключам int +func SortMap(m map[int]map[string][]interface{}) []map[int]map[string][]interface{} { + // Извлечь ключи карты + keys := make([]int, 0, len(m)) + for k := range m { + keys = append(keys, k) + } + + // Отсортировать ключи + sort.Ints(keys) + + // Подготовить результат с отсортированными ключами + sorted := make([]map[int]map[string][]interface{}, 0, len(m)) + for _, k := range keys { + sorted = append(sorted, map[int]map[string][]interface{}{k: m[k]}) + } + + return sorted +}