commit cb76e401de335f89dd53903dc606381b0d37ff96 Author: cfif Date: Fri Jan 24 13:22:32 2025 +0300 Перенос на новую организацию GONEC diff --git a/doc/expl.jpg b/doc/expl.jpg new file mode 100644 index 0000000..8c31af5 Binary files /dev/null and b/doc/expl.jpg differ diff --git a/inc/GonetsAlmanac.h b/inc/GonetsAlmanac.h new file mode 100644 index 0000000..1ef63f7 --- /dev/null +++ b/inc/GonetsAlmanac.h @@ -0,0 +1,74 @@ +// +// Created by dd on 06.06.2023. +// + +#ifndef DECODERALMANACH_DECODER_H +#define DECODERALMANACH_DECODER_H + +#include "stdint.h" +#include "vector.h" +#include "time.h" +#include "stdbool.h" + +typedef struct __attribute__ ((packed)) { + uint8_t NKA; + uint16_t coil; + struct { + uint8_t day; + uint8_t month; + uint8_t year; + } date; + double equator_time; + double semimajor_axis; + double eccentricity; + double inclination; + double periapsis_argument; + double assending_node_longitud; + double saros; + double assending_node_longitude_delta; + double periapsis_argument_delta; + uint8_t validity_interval; +// uint8_t beginDateWTF; +// uint8_t validToWTF; +} tGonetsAlmanac; + + +//возвращаемое значение +//это количество элемтов в массиве inRange +size_t GonetsAlmanac_GetInRangeForInterval( + tGonetsAlmanac *alms, //массив альманахов + size_t almsCount, //количество элементов в массиве + + vector2 geoLocation, //собственная широта и долгота + float rangeDistance, //ограничение по расстоянию до спутника + + //интервал времени в течении которого (полностью от начала и до конца) + //спутник должен находиться в зоне видимости + time_t begin, + time_t end, + + //возвращаемый массив с номерами спутников + uint8_t *inRange +); + + +//возвращаемое значение +//это количество элемтов в массиве inRange +size_t GonetsAlmanac_GetInRangeForMoment( + tGonetsAlmanac *alms, //массив альманахов + size_t almsCount, //количество элементов в массиве + + vector2 geoLocation, //собственная широта и долгота + float rangeDistance, //ограничение по расстоянию до спутника + + time_t moment,//момент времени для которого запрашиваем спутники в зоне видимости + + //возвращаемый массив с номерами спутников + uint8_t *inRange +); + +float GonetsAlmanac_GetDistanceByAngleDeg(float angleDeg); + +bool GonetsAlmanac_IsValid(tGonetsAlmanac *alms, time_t now); + +#endif //DECODERALMANACH_DECODER_H diff --git a/modular.json b/modular.json new file mode 100644 index 0000000..d2ce2b2 --- /dev/null +++ b/modular.json @@ -0,0 +1,17 @@ +{ + "dep": [ + { + "type": "git", + "provider": "GONEC", + "repo": "VectorMath" + } + ], + "cmake": { + "inc_dirs": [ + "./inc" + ], + "srcs": [ + "./src/**.c" + ] + } +} \ No newline at end of file diff --git a/src/GonetsAlmanac.c b/src/GonetsAlmanac.c new file mode 100644 index 0000000..8fab2f6 --- /dev/null +++ b/src/GonetsAlmanac.c @@ -0,0 +1,348 @@ +#include +#include +#include +#include +#include +#include "GonetsAlmanac.h" + + +const static double PI = 3.141592653589793238462643383279; +const static double PI2 = 6.283185307179586476925286766559; +const static double PIdiv2 = 1.570796326794896619231321691639; +const static double PI3div2 = 4.712388980384689857693965074919; +const static double _180divPi = 57.29577951308232087679815481410; + + +float RadToDeg(float rad) { + return rad * _180divPi; +} + +float DegToRad(float grad) { + return grad * (float) (PI / 180.0); +} + + +vector3 GeodesicToSpaceA(vector2 vc, int hh) { + double E2 = 0.00669438; + double EQ = 6378.137; + vc.x = DegToRad(vc.x); + vc.y = DegToRad(vc.y); + + double sin_fi = sin(vc.x); + double cos_fi = cos(vc.x); + double n = EQ / pow(1 - E2 * pow(sin_fi, 2), 0.5); + vector3 ret; + ret.x = (n + hh) * cos_fi * cos(vc.y); + ret.y = (n + hh) * cos_fi * sin(vc.y); + ret.z = ((1.0 - E2) * n + hh) * sin_fi; + return ret; +} + + +int GetSecond(int y, int m, int d, int h, int mi, int sec) { + int ret = 0; + if (y < 2000) y = 2000; + y -= 2000; + ret = (y * 365) + (y / 4) + 1; //при делении сделай целое + if (!(y % 4)) ret--; + + + int i; + for (i = 1; i < m; i++) { + int kolDay = 31; + switch (i) { + case 2: { + if (y % 4) kolDay = 28; + else + kolDay = 29; + } + break; + case 4: + kolDay = 30; + break; + case 6: + kolDay = 30; + break; + case 9: + kolDay = 30; + break; + case 11: + kolDay = 30; + break; + } + ret += kolDay; + } + ret += (d - 1); + ret = ret * 24 * 60 * 60 + h * 60 * 60 + mi * 60 + sec; + return ret; +} + + +double modfd(double a, double b) { + int dm = floor(a / b); + return a - (double) (dm * b); + +} + +vector2 GetCoorAlg1(tGonetsAlmanac *station, int sec, int day, int mon, int year) { + vector2 vc; + vc.x = 0; + vc.y = 0; + if (station->saros < 2000) return vc; + double secTc = GetSecond(year, mon, day, 0, 0, 0) + sec; + double secAll = + GetSecond(station->date.year + 2000, station->date.month, station->date.day, 0, 0, 0) + + station->equator_time; + +// double secAll= GetSecund(2023, 6, 5, 0, 0, 0) + station.equator_time; + + if (secAll > secTc) + return vc; + + double Ttek_Tnu = secTc - secAll; + + if (Ttek_Tnu > 315360000) return vc; + // console.debug("2222"); + + ////// + double i = station->inclination; + + double We = 0.00007303; + double T_T = Ttek_Tnu; + if (T_T >= station->saros) { + T_T = modfd(T_T, station->saros); + } + + double U = PI2 * T_T; + U = U / station->saros; + //console.debug(T_T); + double S = asin(sin(i) * sin(U)); + double Dd = 0; + if (0 <= U && U <= PIdiv2) { + Dd = atan(cos(i) * tan(U)); + } else if (PIdiv2 < U && U < PI3div2) { + Dd = PI + atan(cos(i) * tan(U)); + + } else if (PI3div2 < U && U < PI2) { + Dd = 2 * PI + atan(cos(i) * tan(U)); + + } else if (U == PIdiv2 || U == PI3div2) { + Dd = U; + } + + double D = (station->assending_node_longitud + Dd - (We * Ttek_Tnu)); + if (D >= PI2) { + D = modfd(D, PI2); + } + if (D <= -PI2) { + D = modfd(D, -PI2); + } + if (D < -PI) D += PI2; +// console.debug(S); +// console.debug(D); + vc.x = RadToDeg(S); + vc.y = RadToDeg(D); +// console.debug(vc.fi,"li=",vc.li); + return vc; +} + +vector3 AlmanacCalc(tGonetsAlmanac *station, struct tm date) { + + vector2 coord = GetCoorAlg1( + station, + date.tm_sec + date.tm_min * 60 + date.tm_hour * 3600, date.tm_mday, + date.tm_mon + 1, + date.tm_year + ); + + vector3 v = GeodesicToSpaceA(coord, 1500); + +// printf("%d coor = %lf %lf v=%lf %lf %lf\n", station.NKA, coord.x, coord.y, v.x, v.y, v.z); + return v; +} + +static float getTriangleOppositeAngle(float adjacent, float opposite, float angle) { + return asinf((opposite / adjacent) * sinf(angle)); +} + +static float getTriangleOppositeEdge(float adjacentA, float adjacentB, float angle) { + return sqrtf( + powf(adjacentA, 2) + powf(adjacentB, 2) - 2 * adjacentA * adjacentB * cosf(angle) + ); +} + +static float getTriangleAdjacentEdge(float adjacent, float opposite, float angle) { + float oppositeAngle = (float) PI - getTriangleOppositeAngle(adjacent, opposite, angle) - angle; + return getTriangleOppositeEdge(adjacent, opposite, oppositeAngle); +} + +static float getTriangleAngle(float adjacentA, float adjacentB, float opposite) { + return acosf((powf(adjacentA, 2) + powf(adjacentB, 2) - powf(opposite, 2)) / (2 * adjacentA * adjacentB)); +} + + +static const float earthRadius = 6378.135f; +static const float orbitMax = 8000.f; +static const float RAD_90_DEG = 1.5708f; + + +float GonetsAlmanac_GetDistanceByAngleDeg(float angleDeg) { + return getTriangleAdjacentEdge(orbitMax, earthRadius, (float) (DegToRad(angleDeg) + PI / 2)); +} + + +//получаем угол между нормалью и вектором предельной дальности +static float rangeAngleFromDistance(float distance) { + return (float) (PI - getTriangleAngle(earthRadius, distance, orbitMax)); +} + +bool GonetsAlmanac_InRange( + tGonetsAlmanac *alms, + vector3 selfPosition, + float rangeDistance, + float rangeAngle, + struct tm ts +) { + vector3 satPos; //переменная для записи координат спутника + satPos = AlmanacCalc(alms, ts); //получили координаты + + vector3 direction = vector3Less(satPos, selfPosition);// получаем вектор направления от спутника до нас + float distance = vector3Len(direction); //узнали дистанцию + + if (distance <= rangeDistance) { + + //рассчитали угол мужду нормалью к поверхности и направлением на спутник + float angle = vector3Angle(selfPosition, direction); + +// для наглядности при отладке переводим все в градусы, а так они нафиг ненужны +// float angleDeg = RadToDeg(angle); +// float rangeAngleDeg = RadToDeg(rangeAngle); + + if (angle < rangeAngle) { //проверили подходит ли спутник + return true; + } + } + return false; +} + +static const time_t time_step = 60;//шаг времени при проходе интервала + +size_t GonetsAlmanac_GetInRangeForInterval( + tGonetsAlmanac *alms, + size_t almsCount, + + vector2 geoLocation, + float rangeDistance, + + time_t begin, + time_t end, + + uint8_t *inRange +) { + float rangeAngle = rangeAngleFromDistance(rangeDistance); + vector3 selfPosition = GeodesicToSpaceA(geoLocation, 0); + + bool notInRange[almsCount]; + memset(notInRange, 0, almsCount); + + struct tm ts; + +// for (time_t timet = begin; timet <= end; timet += time_step) { //цикл по времени от начала интервала до конца +// ts = *gmtime(&timet); +// ts.tm_year = ts.tm_year - 100 + 2000; +// +// for (int i = 0; i < almsCount; i++) { //цикл по всем спутникам +// if (!GonetsAlmanac_InRange(alms + i, selfPosition, rangeDistance, rangeAngle, ts)) { +// notInRange[i] = true; +// } +// } +// } + + //проверка нахождения спутников в начале интервала + { + ts = *gmtime(&begin); + ts.tm_year = ts.tm_year - 100 + 2000; + + for (int i = 0; i < almsCount; i++) { //цикл по всем спутникам + if (!GonetsAlmanac_InRange(alms + i, selfPosition, rangeDistance, rangeAngle, ts)) { + notInRange[i] = true; + } + } + } + + + //проверка нахождения спутников в конце интервала + { + ts = *gmtime(&end); + ts.tm_year = ts.tm_year - 100 + 2000; + + for (int i = 0; i < almsCount; i++) { //цикл по всем спутникам + if (!GonetsAlmanac_InRange(alms + i, selfPosition, rangeDistance, rangeAngle, ts)) { + notInRange[i] = true; + } + } + } + + int inRangeCount = 0; + for (size_t i = 0; i < almsCount; ++i) { + if (!notInRange[i]) { + inRange[inRangeCount] = alms[i].NKA; + ++inRangeCount; + } + } + + return inRangeCount; +} + + +size_t GonetsAlmanac_GetInRangeForMoment( + tGonetsAlmanac *alms, + size_t almsCount, + + vector2 geoLocation, + float rangeDistance, + + time_t moment, + + uint8_t *inRange +) { + float rangeAngle = rangeAngleFromDistance(rangeDistance); + vector3 selfPosition = GeodesicToSpaceA(geoLocation, 0); + + bool notInRange[almsCount]; + memset(notInRange, 0, almsCount); + + struct tm ts; + + ts = *gmtime(&moment); + ts.tm_year = ts.tm_year - 100 + 2000;// что за магия? + + for (int i = 0; i < almsCount; i++) { //цикл по всем спутникам + if (!GonetsAlmanac_InRange(alms + i, selfPosition, rangeDistance, rangeAngle, ts)) { + notInRange[i] = true; + } + } + + int inRangeCount = 0; + for (size_t i = 0; i < almsCount; ++i) { + if (!notInRange[i]) { + inRange[inRangeCount] = alms[i].NKA; + ++inRangeCount; + } + } + + return inRangeCount; +} + +bool GonetsAlmanac_IsValid(tGonetsAlmanac *alms, time_t now) { + struct tm begin = {0}; + + begin.tm_year = alms->date.year + 100; + begin.tm_mon = alms->date.month - 1; + begin.tm_mday = alms->date.day; +// begin.tm_gmtoff = 3600; + + time_t begin_ts = mktime(&begin); + + return (begin_ts + (60 * 60 * 24 * alms->validity_interval)) > now; +} \ No newline at end of file diff --git a/tst/CMakeLists.txt b/tst/CMakeLists.txt new file mode 100644 index 0000000..dc977ad --- /dev/null +++ b/tst/CMakeLists.txt @@ -0,0 +1,20 @@ +cmake_minimum_required(VERSION 3.17) +project(decoderAlmanacTest C) + +set(CMAKE_C_STANDARD 99) + +include(modular.cmake) + +add_executable(decoderAlmanacTest ${SOURCES} test.c) + +target_link_libraries(decoderAlmanacTest m) + + + +#cmake_minimum_required(VERSION 3.17) +#project(test C) +# +#set(CMAKE_C_STANDARD 11) +# +# +#add_executable(test ${SOURCES} test.c) diff --git a/tst/CURALM.DAT b/tst/CURALM.DAT new file mode 100644 index 0000000..fb217a9 Binary files /dev/null and b/tst/CURALM.DAT differ diff --git a/tst/curalm(2).dat b/tst/curalm(2).dat new file mode 100644 index 0000000..fb217a9 Binary files /dev/null and b/tst/curalm(2).dat differ diff --git a/tst/modular.json b/tst/modular.json new file mode 100644 index 0000000..53c93bc --- /dev/null +++ b/tst/modular.json @@ -0,0 +1,13 @@ +{ + "dep": [ + { + "type": "git", + "provider": "GONEC", + "repo": "ArrayPrint" + }, + { + "type": "local", + "dir": "../" + } + ] +} \ No newline at end of file diff --git a/tst/test.c b/tst/test.c new file mode 100644 index 0000000..e7b1316 --- /dev/null +++ b/tst/test.c @@ -0,0 +1,112 @@ +// +// Created by xemon on 21.06.23. +// +#include "GonetsAlmanac.h" +#include +#include +#include "time.h" + +#define TEST_ALMANAC_FILE "curalm(2).dat" +//#define TEST_ALMANAC_FILE "../CURALM.DAT" + + +//double rangeAngle=90-89.65081259507197; //угол конуса +double rangeAngle = 40; +double rangeDistance = 5117; //дистанция до спутника +const RANGEMIN = 5; + + +size_t load_from_file(tGonetsAlmanac *alms) { + size_t countAlmanac = 0; + + // подгружаем альманахи + FILE *f = fopen(TEST_ALMANAC_FILE, "r+"); + fseek(f, 11, SEEK_CUR); + tGonetsAlmanac alm; + // сделали декодирование (достаточно просто считать их в запакованную структуру) + while (!feof(f)) { + size_t read = (fread(&alm, sizeof(tGonetsAlmanac), 1, f)); + ////важно чтоб весь альманах целеком был подгружен!!!! + if (read) { + *alms = alm; + ++alms; + countAlmanac++; + } + } + fclose(f); + + return countAlmanac; +} + +void timeCheck(tGonetsAlmanac *alms, int countAlmanac, time_t now) { + //вводим начальные данные + + struct tm ts; + // time(&now); + + time_t interval_begin = now - 1 * 60; + time_t interval_end = now + 1 * 60; + // now += 3 * 3600; +// ts = *localtime(&now); //текущее время + +// vector3 vectorAlmanac; //переменная для записи координат спутника + + uint8_t inRange[100]; // массив со спутниками внутри конуса + int countRange = 0; + + vector2 selfPosition = {52.232f, 41.2322f};//твоя позиция + + + countRange = GonetsAlmanac_GetInRangeForInterval( +// countRange = GonetsAlmanac_GetInRangeForMoment( + alms, + countAlmanac, + + selfPosition, + 4000, + + interval_begin, + interval_end, +// now, + + inRange + ); + + printf("in range (%i): ", countRange); + for (uint8_t *nka = inRange, *end = inRange + countRange; nka < end; ++nka) { + printf("%02i ", *nka); + } + printf("\n"); + +} + +int main() { + + tGonetsAlmanac alms[50]; + + int countAlmanac = load_from_file(alms); + + printf("alms (%i): ", countAlmanac); + for (tGonetsAlmanac *alm = alms, *end = alms + countAlmanac; alm < end; ++alm) { + printf("%02i ", alm->NKA); + } + + time_t now, end; + now = 1687536080; +// now = 1686730934; + end = now + 3600 * 120; + + printf("\n"); + if (GonetsAlmanac_IsValid(alms, now)) { + printf("valid\n "); + } else { + printf("expired\n "); + } + + + for (time_t timestamp = now; timestamp < end; timestamp += 60) { + timeCheck(alms, countAlmanac, timestamp); + } + + return 0; +}