General Question Antenna visibility determination

Gondos

Well-known member
Joined
Apr 18, 2022
Messages
514
Reaction score
707
Points
108
Location
On my chair
Hi,
I'm trying to determine a way to find if communication is possible between two spacecrafts, taking into account light speed delay and planetary occultations (in realtime if possible).
Does anybody know of a book or papers related to this problem? There are a few references to tools that do that on some NTRS papers but nothing explicit...
I have some ideas for ways to do it but if that particular problem has already been solved, I might as well do some reuse.
Thanks
 
Hi,
I'm trying to determine a way to find if communication is possible between two spacecrafts, taking into account light speed delay and planetary occultations (in realtime if possible).
Does anybody know of a book or papers related to this problem? There are a few references to tools that do that on some NTRS papers but nothing explicit...
I have some ideas for ways to do it but if that particular problem has already been solved, I might as well do some reuse.
Thanks
You might want to take a look at how we do this in NASSP. The Omni and HGA classes have examples: https://github.com/orbiternassp/NAS...samples/ProjectApollo/src_csm/csm_telecom.cpp

On a simple level the two antennas have pointing vectors, and if they point at each other, it's just the dot-product of their global vectors. You can add radiation polars and polarization on top of this with some more simple vector math.

For checking if a planet or moon is in the way, you'd need to loop through a list of celestial bodies, get their sizes and global positions (you may not want to do this every timestep, but do it often), and then do some vector math to check if the angle subtended by the planetary disk exceeds: the relative angle from the antenna you're trying to see, to the center of the planet in question,  and the distance to the other antenna is greater than the distance from the planetary centroid to you. If that condition is ever true, you have occultation.
 
Thanks but it assumes instant transmission, the receiver could be hidden at the time of transmission and visible when the radio wave arrives, and vice versa. For cislunar transmissions it's no big deal but for a probe around e.g. jupiter, it could be different.
 
Thanks but it assumes instant transmission, the receiver could be hidden at the time of transmission and visible when the radio wave arrives, and vice versa. For cislunar transmissions it's no big deal but for a probe around e.g. jupiter, it could be different.
Ahh you are correct, I'm forever stuck in cis-lunar mode haha.

This is more brainstorming than advice.

Realistically, the only way I think you could do this would be to add some relativistic functionality into the Orbiter core.

Orbiter runs on a Barycentric Dynamic Time clock, internally. I think you would need two things:
  1. A function call that gets global positions with a time-offset.
  2. Each vessel would need its own clock offset from the TDBModJulian.
For a single "message" to propagate through space, you could store the global position of the point where it was radiated from, and then "propagate" it toward the target (really simulating an expanding sphere). Check that your line of sight (between the emitting point and the receiving vessel) isn't intercepted by a planet. For transmissions that are longer in duration, you could do the same thing with the start and end, and interpolate.

GMAT has a tool called "ContactLocator". It might be worth looking at the code for it.
 
What about using beamtracing?


With many spacecraft likely a bit CPU heavy, but seems to be accurate.

Or what about inverting things? Just use the line of sight at reception and calculate enlongated "shadow mask" of celestial body positions in the past. If you just use linear extrapolation of the current velocity vector of the celestial body, the errors should be tolerable for round-trip times shorter than one day. Not exactly accurate, but should be calculated fast.
 
Could you use the same code, more or less as the propagation of shadows on a body during a solar eclipse? But, that may be a ‘local’ calculation as opposed to, let’s say, the Earth to Saturn calculation. I just noticed that O2016 fails to show moon shadow on the Earth, so maybe that doesn’t work now.
I had also noticed that viewing a solar eclipse from Earth, the visual Sun is way smaller than the visual Moon, should be roughly the same.
 
Thanks for the feedback:)

The "growing sphere" idea is exactly what I had in mind :
  • save emitter position and speed at the time of emission, plus position of every planetary bodies
  • at each timestep, check if the distance between emitter and receiver is less than speed of light multiplied by the time since emission
  • the first time it is true :
- compute the ray between emitter position when sending and current receiver position. With the speed saved at emission, you can also compute the doppler effect if wanted​
- for each planet, compute the distance between the ray and the "capsule" defined by the planet position at emission and reception times ; if it's less than 0 we had an occlusion. Since we're using a linear interpolation for the planet movement, it may be possible to reduce this to a point/line distance check with regard to the planet radius with a change of frame of reference​
It's also possible to save the antenna position at emission time to compute the gain when we know the direction the ray is pointed to, same at reception side.
If we need sub-timestep precision, it requires solving for the exact time the receiver/radioemission sphere collide ; with a linear interpolation between the receiver position at the last timestep and the current one, it will probably lead to a quadratic equation, I haven't checked the math yet.

All of this relies on using linar interpolation for the movement between :
  • emission and reception for the planets
  • during the last timestep for the receiver
The second point may be problematic for low orbiting spacecrafts at high time acceleration

Edit:
Started to do some prototyping, first with the time delay estimation. I can get some good looking numbers but it's not that easy to make sure they are actually correct ; they're in the right ballpark from mercury to neptune.
The main issue is that with this model, if you have for exemple two vessels at rest with each other, the time delay between the two should be exactly their distance over c, but here it takes into account the movement in the global frame and it introduces an error in the estimated delay. Maybe some relativity tricks are in order here, but I'm not ready to touch that yet.
If I park two vessels on the moon 200 meters from each other, the estimated delay converted back to distance is in agreement with submeter accuracy from x1 to x1000 time acceleration. It jumps to several kilometers when using x100000 (@60Hz with VSync enabled). Should be good enough for most usecases. Next step is working on planetary occultations...
 
Last edited:
Some progress : visibility, transit time and doppler effect between an Earth orbiting vessel and another orbiting Io.
tt1.png
tt2.png
Still need to check if the doppler shift is accurate enough.
 
That's awesome. Are you developing this like an API/header that could be added to any vessel?
That is the point ;-)
I am prototyping now so there is no definitive API. Currently it looks like this to declare a radio link :
Code:
        OBJHANDLE sender = oapiGetObjectByName("SH-01");
        OBJHANDLE recv = oapiGetObjectByName("SH-03");
        if(sender && recv) {
            hEm = oapiCreateEmitter(sender, recv, [](CRadioMessage msg, double mjd) {
                if(msg->type == 1) {
                    TestMsg *packet = oapiRadioMessageAs<TestMsg>(msg);
                    strcpy (oapiDebugString(), (packet->msg+" freq="+std::to_string(msg->freq)).c_str());
                }
            });
        }
and like this to send a packet
Code:
        auto packet = oapiMakeRadioMessage<TestMsg>(1, 2000000000.0);
        packet->data.msg = "hello@"+std::to_string(td.SimT1);
        oapiEmitRadioPacket(hEm, std::move(packet));
Note :
  • I think I'll get rid of the templating and use a raw buffer for message data because it'll be easier to serialize in a generic way (I guess compressed + base64 encoded).
  • usage of a unique_ptr because when you send a packet, whether it'll be received or not, it will need to be deleted at some point and it helps with ownership tracking.
  • std::function as a callback for when a packet is received
These are not the usual things you find in the current OAPI SDK so I'm not sure people are "ready" for this and I don't want to introduce discrepency or confusion for "casual" programmers (no offense intended) who just want to program their thing and don't aspire to be experts in C++ smart pointer semantics, serialization patterns or lambda subtleties.
I don't know how it'll turn out, but if you have an opinion on this please do share.
 
Replaced the linear interpolation for vessel positions with Hermite interpolation ; now even at max time acceleration the calculated transit time stays stable with sub-centimeter equivalent accuracy for closely parked vessels. Had to do some some juggling because we're hitting double precision accuracy limits.
Some tests with a transponder-like callback, between two vessels landed on the Moon at max time acceleration, and between an Earth orbiter and a Ganymede orbiter :

hermit1.pnghermit2.png
 

Attachments

  • hermit1.png
    hermit1.png
    370.2 KB · Views: 0
Last edited:
I'm starting to scratch my head over that one trying to test it.
I noticed that the transit time calculated by the "growing sphere" method changes as time is passing while the distance between both vessels is still the same.
Since the coordinates are heliocentric and the distance I'm interested in is between the emitter and the receiver, I tried to plug in a Lorentz transformation to get the elapsed time from the transmitting vessel frame.
The results are much closer to the value I'm expecting but there is still a residual error that I'm not explaining.
For example with two vessels far away from the sun in an hyperbolic trajectory with a small relative velocity between them I get :
  • "real orbiter" distance (length between oapiGetGlobalPos vectors) : 92'979'987'283.1m
  • calculated light delay (growing sphere + hermit interpolation of positions during the last frame) : 310.163707049185234s
  • equivalent distance (c*t): 92'984'740'118.7m (delta ~ 4'752'835m)
  • light delay after lorentz transformation : 310.147856695070800s
  • equivalent distance : 92'979'988'302.0m (delta ~ 1'019m)
The vessels are drifting away at ~20cm/s so it should not account for the ~1km difference...
I feel I'm way over my head here, any idea of what could be wrong with my assumptions ?
(I don't think it is due to rounding errors with 64bit floating points but I'm not really sure.)
 
I'm starting to scratch my head over that one trying to test it.
I noticed that the transit time calculated by the "growing sphere" method changes as time is passing while the distance between both vessels is still the same.
Since the coordinates are heliocentric and the distance I'm interested in is between the emitter and the receiver, I tried to plug in a Lorentz transformation to get the elapsed time from the transmitting vessel frame.
The results are much closer to the value I'm expecting but there is still a residual error that I'm not explaining.
For example with two vessels far away from the sun in an hyperbolic trajectory with a small relative velocity between them I get :
  • "real orbiter" distance (length between oapiGetGlobalPos vectors) : 92'979'987'283.1m
  • calculated light delay (growing sphere + hermit interpolation of positions during the last frame) : 310.163707049185234s
  • equivalent distance (c*t): 92'984'740'118.7m (delta ~ 4'752'835m)
  • light delay after lorentz transformation : 310.147856695070800s
  • equivalent distance : 92'979'988'302.0m (delta ~ 1'019m)
The vessels are drifting away at ~20cm/s so it should not account for the ~1km difference...
I feel I'm way over my head here, any idea of what could be wrong with my assumptions ?
(I don't think it is due to rounding errors with 64bit floating points but I'm not really sure.)
Two thoughts:

How far away from the Sun are you. There are precision limits if you get too far away.
Is this error dependent on time-step length?
 
Good call, the error does change with time acceleration (it even changes sign...).
I tried using doubledouble floats for computations during Hermite interpolation, Newton Raphson iterations and Lorentz transformation but it does not change a thing:confused:
 
Good call, the error does change with time acceleration (it even changes sign...).
I tried using doubledouble floats for computations during Hermite interpolation, Newton Raphson iterations and Lorentz transformation but it does not change a thing:confused:
I'm more thinking it could be related to some kind of pre-step/post-step or off-by-one timestep thing.

It might be a pain to do, but you could probably figure out the errors introduced and propagate then through the calculations.

IEEE-754 x64 should be able to represent sub distances to the hundredth of a mm, at the distance you listed. Also could it be a reference frame issue (wrong vessel used)?
 
Did some more tests with vessels "on a rail" (P=P0+V*t) at a constant distance and it looks like it was due to length contraction plus a bug in my code : the distance calculated using oapiGetGlobalPos is seeing the distance measured between moving objects whereas from the sending vessel's point of view, it's at rest ; so the length from the global frame is contracted with respect to the one from the moving vessel. Seems obvious in hindsight but I'm new to this game😫
 
Back
Top