Перенос на новую организацию GONEC

This commit is contained in:
cfif 2025-01-24 13:22:32 +03:00
commit cb76e401de
9 changed files with 584 additions and 0 deletions

BIN
doc/expl.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 120 KiB

74
inc/GonetsAlmanac.h Normal file
View File

@ -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

17
modular.json Normal file
View File

@ -0,0 +1,17 @@
{
"dep": [
{
"type": "git",
"provider": "GONEC",
"repo": "VectorMath"
}
],
"cmake": {
"inc_dirs": [
"./inc"
],
"srcs": [
"./src/**.c"
]
}
}

348
src/GonetsAlmanac.c Normal file
View File

@ -0,0 +1,348 @@
#include <math.h>
#include <vector.h>
#include <time.h>
#include <stdbool.h>
#include <memory.h>
#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;
}

20
tst/CMakeLists.txt Normal file
View File

@ -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)

BIN
tst/CURALM.DAT Normal file

Binary file not shown.

BIN
tst/curalm(2).dat Normal file

Binary file not shown.

13
tst/modular.json Normal file
View File

@ -0,0 +1,13 @@
{
"dep": [
{
"type": "git",
"provider": "GONEC",
"repo": "ArrayPrint"
},
{
"type": "local",
"dir": "../"
}
]
}

112
tst/test.c Normal file
View File

@ -0,0 +1,112 @@
//
// Created by xemon on 21.06.23.
//
#include "GonetsAlmanac.h"
#include <stdio.h>
#include <vector.h>
#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;
}