# Julia and the GPS payload onboard Waratah Seed-1 satellite

**URL:** https://discourse.julialang.org/t/julia-and-the-gps-payload-onboard-waratah-seed-1-satellite/123795
**Category:** Community
**Created:** [December 13, 2024, 1:00am UTC](https://discourse.julialang.org/t/julia-and-the-gps-payload-onboard-waratah-seed-1-satellite/123795 "2024-12-13T01:00:46Z")
**Posts on this page:** 20
**Page:** 1

<div class="post-metadata">

### Author: ![minetest2048](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/minetest2048/32/45961_2.png) [@minetest2048](https://discourse.julialang.org/u/minetest2048)
#### Post date: [December 13, 2024, 1:00am UTC](https://discourse.julialang.org/t/julia-and-the-gps-payload-onboard-waratah-seed-1-satellite/123795/1 "2024-12-13T01:00:46Z")

</div>

Hi Julia community,

I’m Ignatius Rivaldi, research engineer working at UNSW ACSER: [Australian Centre for Space Engineering Research (ACSER)](https://www.unsw.edu.au/research/acser)

We flew our GPS receiver payload, Harry v3 on Waratah Seed-1 6U cubesat developed by our collaborator, [ARC Training Centre for CubeSats, UAVs, and their Applications (CUAVA)](https://www.cuava.com.au/)

After several public announcements and a presentation at [ASRC 2024](https://www.nssa.com.au/asrc2024) , this is our first data from our Kea GPS receiver navigating in space:

 ![|794px;x435px;](https://global.discourse-cdn.com/julialang/original/3X/c/b/cb1612099c0c2b9b673c2576c2030a1a2047852d.png)

(The TLE was propagated by SatelliteToolbox.jl and plotted by Makie.jl)

LinkedIn post by our PI, [To you, this might look like an ordinary image of a GNSS receiver navigating in space. At Australian Centre for Space Engineering Research (ACSER), UNSW Sydney , we have integrated many receivers… | Andrew Dempster | 25 comments](https://www.linkedin.com/feed/update/urn:li:activity:7270551426156625921/)

## Why Julia

Part of the process of hardware integration between our GPS payload and WS-1 bus is verifying whether the RF chain works before we launch it into space. In orbit, our FPGA-based Kea GPS receiver will process the GPS signals into navigation solutions. But, if something breaks, it will be hard to debug.

Our payload can be configured to dump raw intermediate frequency (IF) samples from its RF frontends at data rate of about 2 MB/s . We can then run a software receiver on the IF samples to verify that our RF frontends can successfully receive GPS signal. A good guide of this can be found in Daniel Estevez’s post: [Timing SDR recordings with GPS – Daniel Estévez](https://destevez.net/2022/03/timing-sdr-recordings-with-gps/)

There are a lot of open source GPS software receivers out there:

> **[GNSS-SDR](https://gnss-sdr.org/)**
>
> An open source Global Navigation Satellite Systems software-defined receiver.

This is based on [GNU Radio framework](https://www.gnuradio.org/) , and this is the most featureful open source GNSS software receiver out there. It can process GPS L1,L2,L5, Galileo, Beidou, GLONASS including Galileo navigation message authentication,  
at real time on embedded hardware such as Raspberry Pi. The issue is that to support those functions and as it is using GNU Radio, it is written in some extremely involved C++: [GNSS-SDR](https://gnss-sdr.org/docs/fundamentals/#general-class-hierarchy-for-gnss-sdr)

[https://github.com/nlsfi/FGI-GSRx](https://github.com/nlsfi/FGI-GSRx)

This is written in Matlab, have similar functions as GNSS-SDR. Because it is written in Matlab, it is much easier to modify and extend compared to GNSS-SDR.

Unfortunately, Matlab doesn’t encourage the user to write performant code, from [hiding how their JIT compiler worked](https://au.mathworks.com/matlabcentral/answers/430098-documentation-on-jit-compiler#comment_638005), to having multithreading support as a [paid $1800 DLC](https://au.mathworks.com/pricing-licensing.html?prodcode=DM). The worst sin is that in 2024,[Matlab doesn’t have an official function of reading interleaved complex binary file](https://au.mathworks.com/help/matlab/import_export/exporting-binary-data-with-low-level-i-o.html#br48alm), leading to Matlab users using [some very inefficient and error-prone method of reading complex data](https://au.mathworks.com/matlabcentral/answers/556855-efficient-ways-to-read-and-write-complex-valued-data) or [third-party solution that implements complex file read in C](https://au.mathworks.com/matlabcentral/fileexchange/77530-freadcomplex-and-fwritecomplex).

All of these papercuts leads to this software receiver taking **30 minutes!** to process 40 second of IF data, while GNSS-SDR runs in only 10 seconds

We have a very fast software receiver that’s hard to extend, and a very slow software receiver that’s easy to extend. Sounds like a two-language problem to me

Then I found this from @zsoerenm :

> **[JuliaGNSS](https://github.com/JuliaGNSS)**
>
> GNSS packages for Julia. JuliaGNSS has 14 repositories available. Follow their code on GitHub.

This is perfect for my application,as I can:

- Read _any_ complex file is just a `mmap("complex.iq", Complex{Float32})` away, no matter what the real datatype is, from `UInt8` to `Float64`, with it just working by the power of parametric polymorphism and multiple dispatch
- see the assembly output of Julia compiler by `@code_native`,
- benchmark by BenchmarkTools.jl,
- profile by VS code `@profview` ,
- use Tracy.jl ,the profiler that game devs uses
- use LIKWID.jl to measure FLOPS
- use Bumper.jl to reduce memory allocations and GC
- `Threads.@threads for` is free!

Now we have a GPS software receiver that’s as easy to modify as the Matlab receiver, but nearly as fast as GNSS-SDR

## Julia running in space!

Julia can also run on Raspberry Pi CM4, the processor I used on our GPS payload computer. Unfortunately, precompilation delay means that its not practical to run the GPS signal processing script in space - every watt matters in space.

In space, we also capture IF data for us to do postprocessing in ground. But the IF data doesn’t fit into a single 1-2 minute satellite downlink pass, so I wrote a small Julia script to chunk the IF file on the payload computer into multiple smaller chunks, which can be downloaded over multiple passes. Which is then recombined at the ground, then postprocessed using JuliaGNSS

```julia-auto
| WS-1 GPS payload | WS-1 cubesat bus | Groundstation
Kea -> Julia script -> S-band radio to ground -> JuliaGNSS

```

This is the output of one of our IF captures that was chunked by Julia script in space, and postprocessed by JuliaGNSS at ground:

 ![|292px;x194px;](https://global.discourse-cdn.com/julialang/original/3X/c/2/c259f84629e8850b02c7ebd3865fdcfb5a339afb.png)

JuliaGNSS can receive and decode 3 GPS satellites:

 ![|415px;x97px;](https://global.discourse-cdn.com/julialang/original/3X/b/d/bd69d622d8d52772fddad9a7bc6fa093310b9e7d.png)

This is the first time I know of that Julia is running in space

---

<div class="post-metadata">

### Author: ![zsoerenm](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/zsoerenm/32/664_2.png) [@zsoerenm](https://discourse.julialang.org/u/zsoerenm)
#### Post date: [December 13, 2024, 7:58am UTC](https://discourse.julialang.org/t/julia-and-the-gps-payload-onboard-waratah-seed-1-satellite/123795/2 "2024-12-13T07:58:43Z")

</div>

It’s great to see that JuliaGNSS is actually being used 😉  
It motivates me to continue my work.

> Now we have a GPS software receiver that’s as easy to modify as the Matlab receiver, but nearly as fast as GNSS-SDR

I have more performance improvements in the pipe 🙂

---

<div class="post-metadata">

### Author: ![RGerzaguet](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/rgerzaguet/32/45492_2.png) [@RGerzaguet](https://discourse.julialang.org/u/RGerzaguet)
#### Post date: [December 13, 2024, 5:21pm UTC](https://discourse.julialang.org/t/julia-and-the-gps-payload-onboard-waratah-seed-1-satellite/123795/3 "2024-12-13T17:21:43Z")

</div>

It’s really excellent!! Note that if you want to connect your processing more directly with software-defined radios, you can take a look at the SDR driver we developed on [JuliaTelecom](https://github.com/JuliaTelecom) to directly output the IQ data to your processing unit. But it’s truly exciting to see what can be achieved with Julia-based signal processing!

---

<div class="post-metadata">

### Author: ![minetest2048](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/minetest2048/32/45961_2.png) [@minetest2048](https://discourse.julialang.org/u/minetest2048)
#### Post date: [December 15, 2024, 5:56am UTC](https://discourse.julialang.org/t/julia-and-the-gps-payload-onboard-waratah-seed-1-satellite/123795/4 "2024-12-15T05:56:00Z")

</div>

There are more reasons that makes Julia one of the very promising language and ecosystem for SDR signal processing:

There are PLL algorithms that promises to be ‘better’ than conventional second order PLL loop:

- Kalman filter PLL: [Are PLLs dead? A tutorial on kalman filter-based techniques for digital carrier synchronization](https://www.researchgate.net/publication/319927378_Are_PLLs_dead_A_tutorial_on_kalman_filter-based_techniques_for_digital_carrier_synchronization)
- [Kalman Filtering applied to Timing Recovery  
in Tracking Mode](https://mtns.math.nd.edu/papers/13997_4.pdf)
- Even basic FLL-assisted PLL or FLL then PLL

But GNU Radio is still stuck in second order PLL and symbol synchronization loop. What gives?

One of the possible reason is that GNU Radio 3.x flowgraph doesn’t support feedback: [Why can’t we do loops?](https://wiki.gnuradio.org/index.php/FAQ#Why_can't_we_do_loops)

> A lot of users come into the project looking to experiment, including building known algorithms like phase-locked loops (PLLs). GNU Radio comes with each of the blocks to build your own PLL in a flowgraph, like a multiplier, lowpass filter, and VCO. But you try to put it together and GNU Radio tells you it won’t work. That the flow graphs don’t allow you to do loops. Why? PLLs are fundamental to radio and signal processing! How can it be that I can’t build loops into a flow graph?

So a user that wants to implement their exotic PLLs to evaluate whether it meets their needs can’t use the user friendly GNU Radio Companion flowgraph interface:

 ![image](https://global.discourse-cdn.com/julialang/original/3X/0/4/048c23de2779c41fc4090679aba2a009b6382e55.png)

and they need to drop to some involved C++:

> <https://github.com/gnuradio/gnuradio/blob/main/gr-analog/lib/pll_carriertracking_cc_impl.cc>

It turns out that GNU Radio consists of 4 languages:

- Flow graph, which compiles to
- Python script, which connects
- Signal processing blocks which is written in C++, which uses
- Math kernels written in assembly: [GitHub - gnuradio/volk: The Vector Optimized Library of Kernels](https://github.com/gnuradio/volk)

Its hard to move between dragging virtual cables between signal processing blocks and writing C++ .

While Julia might be able to replace the 4 different languages with one using metaprogramming and code generation.

It seems that they simplify this situation in GNU Radio 4.0 using modern C++. I haven’t played around with it though.

Another trend is because of AI hype, everyone is making their own AI accelerator chip. Those are screaming for us to run SDR workloads on that, all AI accelerator chip do is accelerate the matmuls. They don’t care whether its part of deep neural net or signal processing flowgraph.  
Tenstorrent have very interesting architecture:

> <https://github.com/tenstorrent/tt-metal/blob/main/METALIUM_GUIDE.md>

 ![image](https://global.discourse-cdn.com/julialang/original/3X/6/9/69e7ada865c64b6b3a2d0e282c6f5ef4d083689a.png)

What we need is a good framework to convert our SDR flowgraphs into something that can run on Tensix core array. GNU Radio can’t do that because they connect precompiled C++ blocks, while Julia GPUCompiler.jl might be able to compile our flowgraph description into Tensix RISC-V assembly.

---

<div class="post-metadata">

### Author: ![xiaoxi](https://avatars.discourse-cdn.com/v4/letter/x/a9adbd/32.png) [@xiaoxi](https://discourse.julialang.org/u/xiaoxi)
#### Post date: [December 15, 2024, 7:38am UTC](https://discourse.julialang.org/t/julia-and-the-gps-payload-onboard-waratah-seed-1-satellite/123795/5 "2024-12-15T07:38:49Z")

</div>

Could the first OP post be modified to become a Julia-lang blog post?

I wish Julia-lang blog could also post successful use cases of Julia like this one.

---

<div class="post-metadata">

### Author: ![TheCedarPrince](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/thecedarprince/32/17323_2.png) [@TheCedarPrince](https://discourse.julialang.org/u/TheCedarPrince)
#### Post date: [December 15, 2024, 5:08pm UTC](https://discourse.julialang.org/t/julia-and-the-gps-payload-onboard-waratah-seed-1-satellite/123795/6 "2024-12-15T17:08:11Z")

</div>

Oh that is a great idea. I am pinging @rayegun !

---

<div class="post-metadata">

### Author: ![Ronis\_BR](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ronis_br/32/50999_2.png) [@Ronis\_BR](https://discourse.julialang.org/u/Ronis_BR)
#### Post date: [December 16, 2024, 1:42pm UTC](https://discourse.julialang.org/t/julia-and-the-gps-payload-onboard-waratah-seed-1-satellite/123795/7 "2024-12-16T13:42:46Z")

</div>

Hi @minetest2048 !

This is awesome! I am so glad to see more people using Julia in the space community 🙂

One of my projects now is to prove that we can use Julia for RT applications to write an entire attitude and orbit control subsystem software of a satellite in Julia. I am still having problems for RT deadlines 5% of the time, but when we fix that, I will apply for funding a CubeSat mission to test the approach. In this case, I will mention your mission that now has Julia running in space. It will be some much better for the proposal!

Thank you very much for sharing!

---

<div class="post-metadata">

### Author: ![giordano](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/giordano/32/2166_2.png) [@giordano](https://discourse.julialang.org/u/giordano)
#### Post date: [December 16, 2024, 1:50pm UTC](https://discourse.julialang.org/t/julia-and-the-gps-payload-onboard-waratah-seed-1-satellite/123795/8 "2024-12-16T13:50:27Z")

</div>

> [@minetest2048](#):
>
> What we need is a good framework to convert our SDR flowgraphs into something that can run on Tensix core array. GNU Radio can’t do that because they connect precompiled C++ blocks, while Julia [GPUCompiler.jl](https://juliahub.com/ui/Packages/General/GPUCompiler) might be able to compile our flowgraph description into Tensix RISC-V assembly.

I should get access to a tenstorrent board in the next few months and I want to experiment with julia on it. But I was planning to go by the MLIR route: [GitHub - tenstorrent/tt-mlir: Tenstorrent MLIR compiler](https://github.com/tenstorrent/tt-mlir)

---

<div class="post-metadata">

### Author: ![minetest2048](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/minetest2048/32/45961_2.png) [@minetest2048](https://discourse.julialang.org/u/minetest2048)
#### Post date: [December 18, 2024, 11:46am UTC](https://discourse.julialang.org/t/julia-and-the-gps-payload-onboard-waratah-seed-1-satellite/123795/9 "2024-12-18T11:46:31Z")

</div>

Thanks @Ronis_BR for your SatelliteToolbox.jl, I used it a lot for mission planning

Some wishlist for SatelliteToolbox:

- I wish we have support for converting ECI to RIC frame, all the existing literature uses RIC frame to measure error between GPS position fixes and propagated TLE, as it is easier to interpret than ECEF error
- Typed data input and output so that I can just compare the output of TLE propagation with GPS fixes from our receiver without [messing with Julian days so I can convert ECI to ECEF](https://juliaspace.github.io/SatelliteToolbox.jl/stable/tutorials/iss_observation/) or trying to understand which [100 reference frames](https://juliaspace.github.io/SatelliteToolboxTransformations.jl/stable/man/ecef_eci/) I should use so my TLE works correctly (turns out its PEF)

Ideally it works like this:

```julia
orbp = Propagators.init(Val(:SGP4), iss_tle)
ecis = Propagators.propagate!.(orbp, 0:1:86400)
ecefs = to_ecef(ecis) # It handles all the conversions without me needing to construct the transform matrix 

```

With humans landing on the moon in[hopefully 5 years](https://en.wikipedia.org/wiki/Artemis_III), things will become more interesting. We will have [lunar coordinate system](https://en.wikipedia.org/wiki/Selenographic_coordinate_system), [lunar UTC](https://www.nasa.gov/solar-system/moon/nasa-to-develop-lunar-time-standard-for-exploration-initiatives/), [lunar GPS](https://www.gps.gov/cgsic/meetings/2022/murata.pdf). We also going to try to receive Earth GPS on the Moon and try to navigate with that using [NaviMoon](https://spacepnt.com/navimoon/) receiver

For your realtime Julia, this CppCon talk just dropped yesterday about Clang RealtimeSanitizer and performance constraints for C++:

[![](https://global.discourse-cdn.com/julialang/original/3X/2/a/2a8ff0ec49b6194d6f9930de9926aed2f14276a6.jpeg "LLVM's Realtime Safety Revolution: Tools for Modern Mission Critical Systems - CppCon 2024") ](https://www.youtube.com/watch?v=KvhgNdxX6Uw)

Previous thread on this: [Can we get RealtimeSanitizer in Julia?](https://discourse.julialang.org/t/can-we-get-realtimesanitizer-in-julia/119330)

If we take inspiration from this, and extend AllocCheck.jl to not just detect memory allocation, but also other non-RT functions such as `gc_collect` and taking locks/mutexes, we can go closer to realtime Julia.

The other option that works today, but its very brutal is compiling your code to a shared library using StaticCompiler.jl. You won’t trigger GC if there’s no GC in the first place, same with memory allocation.

I tried to write a GNU Radio block with this and kind of gave up. Its very easy to accidentally depend on `libjulia` and have missing symbols errors during linking. But the worst thing is that StaticCompiler doesn’t currently emit debug symbols. So when you segfault, which is very easy to do because freestanding Julia doesn’t currently have memory safety features unlike Rust, both `gdb` and Valgrind won’t help you find where it is and debug it

---

<div class="post-metadata">

### Author: ![juliohm](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/juliohm/32/215266_2.png) [@juliohm](https://discourse.julialang.org/u/juliohm)
#### Post date: [December 18, 2024, 12:43pm UTC](https://discourse.julialang.org/t/julia-and-the-gps-payload-onboard-waratah-seed-1-satellite/123795/10 "2024-12-18T12:43:18Z")

</div>

> [@minetest2048](#):
>
> Typed data input and output so that I can just compare the output of TLE propagation with GPS fixes from our receiver without [messing with Julian days so I can convert ECI to ECEF](https://juliaspace.github.io/SatelliteToolbox.jl/stable/tutorials/iss_observation/) or trying to understand which [100 reference frames](https://juliaspace.github.io/SatelliteToolboxTransformations.jl/stable/man/ecef_eci/)

CoordRefSystems.jl might help with this wishlist item if I understood the challenge correctly.

---

<div class="post-metadata">

### Author: ![Ronis\_BR](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ronis_br/32/50999_2.png) [@Ronis\_BR](https://discourse.julialang.org/u/Ronis_BR)
#### Post date: [December 23, 2024, 1:04am UTC](https://discourse.julialang.org/t/julia-and-the-gps-payload-onboard-waratah-seed-1-satellite/123795/11 "2024-12-23T01:04:02Z")

</div>

Hi @minetest2048 !

Awesome!

> [@minetest2048](#):
>
> I wish we have support for converting ECI to RIC frame, all the existing literature uses RIC frame to measure error between GPS position fixes and propagated TLE, as it is easier to interpret than ECEF error

I can easiy implement this. Do you mind open an issue so that I do not forget?

> [@minetest2048](#):
>
> Typed data input and output so that I can just compare the output of TLE propagation with GPS fixes from our receiver without [messing with Julian days so I can convert ECI to ECEF](https://juliaspace.github.io/SatelliteToolbox.jl/stable/tutorials/iss_observation/) or trying to understand which [100 reference frames](https://juliaspace.github.io/SatelliteToolboxTransformations.jl/stable/man/ecef_eci/) I should use so my TLE works correctly (turns out its PEF)

We can do this using a layer on top of the functions we have now. However, we must think very careful because, depending on the use case, you might have some problems. There are a lot of ECEF reference frames. You selected PEF from IAU-76 convention, but another application might require the ITRF or another one from the IAU-2010 convertion.

That’s why I decided to let the user select the specific frame.

> [@minetest2048](#):
>
> If we take inspiration from this, and extend [AllocCheck.jl](https://juliaregistries.github.io/General/packages/redirect_to_repo/AllocCheck) to not just detect memory allocation, but also other non-RT functions such as `gc_collect` and taking locks/mutexes, we can go closer to realtime Julia.

I fully agree!

---

<div class="post-metadata">

### Author: ![Ronis\_BR](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ronis_br/32/50999_2.png) [@Ronis\_BR](https://discourse.julialang.org/u/Ronis_BR)
#### Post date: [December 23, 2024, 1:07am UTC](https://discourse.julialang.org/t/julia-and-the-gps-payload-onboard-waratah-seed-1-satellite/123795/12 "2024-12-23T01:07:01Z")

</div>

Ah! By the way, one of my projects if to extend static arrays so that we can annotate the reference system in which the vector is represented. It will help a lot, since, in this case, we can convert by only specifying the target system. However, it will require a huge rewrite of a lot of packages in the SatelliteToolbox.jl ecosystem.

---

<div class="post-metadata">

### Author: ![juliohm](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/juliohm/32/215266_2.png) [@juliohm](https://discourse.julialang.org/u/juliohm)
#### Post date: [December 23, 2024, 1:11am UTC](https://discourse.julialang.org/t/julia-and-the-gps-payload-onboard-waratah-seed-1-satellite/123795/13 "2024-12-23T01:11:50Z")

</div>

> [@Ronis\_BR](#):
>
> Ah! By the way, one of my projects if to extend static arrays so that we can annotate the reference system in which the vector is represented. It will help a lot, since, in this case, we can convert by only specifying the target system

That is precisely what CoordRefSystems.jl does, except we don’t implement the StaticArrays.jl interface. The `AbstractArray` interface is mostly useful with `Cartesian` frames where `LinearAlgebra` plays a major role.

> [@Ronis\_BR](#):
>
> There are a lot of ECEF reference frames. You selected PEF from IAU-76 convention, but another application might require the ITRF or another one from the IAU-2010 convertion.

Also handled in CoordRefSystems.jl? This is the datum type parameter that we store in the type at compile time.

---

<div class="post-metadata">

### Author: ![Ronis\_BR](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ronis_br/32/50999_2.png) [@Ronis\_BR](https://discourse.julialang.org/u/Ronis_BR)
#### Post date: [December 23, 2024, 1:23am UTC](https://discourse.julialang.org/t/julia-and-the-gps-payload-onboard-waratah-seed-1-satellite/123795/14 "2024-12-23T01:23:45Z")

</div>

Hi @juliohm !

Yes, I know! However, last time I checked, CoordRefSystem.jl could not fit our applications here. We need something more “low-level” when representing reference system transformations.

For example, I think it is not possible to obtain the quaternion, or DCM, that rotates the True-of-Date frame at some epoch to the True-Equator, Mean-Equinox frame in another epoch.

SatelliteToolboxTransformations.jl together with ReferenceFrameRotations.jl were designed since the beginning to take into account the features we need to simulate satellite attitude dynamics and also perform tasks related to mission analysis.

Currently, we obtain the rotation entities (DCM, Quaternion, etc) and the user must track the vector representation. What I want to do is the add a layer so that the reference in which each vector is represented is annotated. This modification will not make everything automatic, but it will decrease the probability of errors.

---

<div class="post-metadata">

### Author: ![juliohm](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/juliohm/32/215266_2.png) [@juliohm](https://discourse.julialang.org/u/juliohm)
#### Post date: [December 23, 2024, 2:46am UTC](https://discourse.julialang.org/t/julia-and-the-gps-payload-onboard-waratah-seed-1-satellite/123795/15 "2024-12-23T02:46:53Z")

</div>

Hi @Ronis_BR !

> [@Ronis\_BR](#):
>
> For example, I think it is not possible to obtain the quaternion, or DCM, that rotates the True-of-Date frame at some epoch to the True-Equator, Mean-Equinox frame in another epoch.

Appreciate it if you could elaborate on this feature request. We do handle dynamic frames and epochs in CoordRefSystems.jl `convert` methods.

---

<div class="post-metadata">

### Author: ![Ronis\_BR](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ronis_br/32/50999_2.png) [@Ronis\_BR](https://discourse.julialang.org/u/Ronis_BR)
#### Post date: [December 23, 2024, 2:13pm UTC](https://discourse.julialang.org/t/julia-and-the-gps-payload-onboard-waratah-seed-1-satellite/123795/16 "2024-12-23T14:13:59Z")

</div>

Hi @juliohm!

What we need is basically all the transformations described here:

> **[ECI and ECEF · SatelliteToolboxTransformations.jl](https://juliaspace.github.io/SatelliteToolboxTransformations.jl/stable/man/ecef_eci/)**
>
> Documentation for SatelliteToolboxTransformations.jl.

And we need to obtain the transformed vectors and the entities as well (DCM and Quaternions).

---

<div class="post-metadata">

### Author: ![minetest2048](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/minetest2048/32/45961_2.png) [@minetest2048](https://discourse.julialang.org/u/minetest2048)
#### Post date: [December 24, 2024, 2:52am UTC](https://discourse.julialang.org/t/julia-and-the-gps-payload-onboard-waratah-seed-1-satellite/123795/17 "2024-12-24T02:52:41Z")

</div>

What’s currently missing from CoordRefSystems.jl representation is time, and time reference frame

Currently I’m working with several time frames/representations:

- PositionVelocityTime.jl uses `AstroTime.TAI` from navigation solution
- Our Kea GPS receiver outputs GPS time as `(week_number, tow)` tuple in the NMEA message
- SatelliteToolbox.jl uses Julian day UTC in unitless `Float64`
- We print using `DateTime` UTC

If we’re off by several milliseconds, at 7 km/s my satellite will be off by several hundred meters as shown here:

> <https://github.com/JuliaGNSS/PositionVelocityTime.jl/issues/8>
>
> Kaplan & Hegarty defines PVT problem as this:
> 
> !\[image\](https://github.com/Jul…iaGNSS/PositionVelocityTime.jl/assets/2445636/429f1d44-1457-4a4c-91a9-00742a19f683)
> 
> so ξ\[4\] (https://github.com/JuliaGNSS/PositionVelocityTime.jl/blob/master/src/PositionVelocityTime.jl#L170) is equal to -c\*Δt.
> 
> So time correction from reference time Δt should be ξ\[4\]/(-c) 
> 
> https://github.com/JuliaGNSS/PositionVelocityTime.jl/blob/master/src/PositionVelocityTime.jl#L171 have the wrong sign, time correction is positive instead of negative:
> \`\`\`
> corrected\_reference\_time = reference\_time + time\_correction / SPEEDOFLIGHT
> \`\`\`
> 
> It should be
> \`\`\`
> corrected\_reference\_time = reference\_time + time\_correction / (-SPEEDOFLIGHT)
> \`\`\`
> 
> The result of this bug is that we have a position solution accurate to ~3m as expected (when stationary), but the time solution (as in \`PVTSolution\` output) is ~130ms earlier then the actual time. This doesn't show up in stationary scenarios, but if the receiver is moving very fast, like in low Earth orbit, this results in 500m position error
> 
> This is a plot of position error before this fix:
> 
> !\[broken\](https://github.com/JuliaGNSS/PositionVelocityTime.jl/assets/2445636/242c5795-48ab-4989-b4d3-3ea1b170f104)
> 
> and after:
> 
> !\[error-good\](https://github.com/JuliaGNSS/PositionVelocityTime.jl/assets/2445636/fd141ab0-c6c8-4d03-a6c4-654f464b373b)
> 
> Input signal was generated using \[Skydel software defined GNSS simulator\](https://safran-navigation-timing.com/product/skydel-simulation-engine/?model\_interest\_\_c=Skydel&product\_interest\_\_\_single\_select=GNSS+Simulation), on the default low Earth orbit satellite scenario (~400km orbit), then we check position error by comparing position outputs that Skydel generates and JuliaGNSS \`PVTSolution\`

@zsoerenm please fix your sign!

GPS broadcasts conversion factors between GPS time and UTC, but for my use case its negligible.

The thing with ECI and ECEF conversion is that the conversion DCM changes every second, unlike geodetic datum conversion where the agency releases new datum every year or so. At least that’s what I understand from SatelliteToolbox [ISS tutorial](https://juliaspace.github.io/SatelliteToolbox.jl/stable/tutorials/iss_observation/)

What’s currently missing is a `StateVector` struct, parameterized on time type and reference frame type for position and its derivatives:

```julia
struct StateVector{T,P,V,reference_frame}
     time::T
     position::P 
     velocity::V 
    #higher order derivatives if necessary 
end

```

This is more tricky then I first thought…

---

<div class="post-metadata">

### Author: ![mkitti](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mkitti/32/12459_2.png) [@mkitti](https://discourse.julialang.org/u/mkitti)
#### Post date: [December 25, 2024, 7:48pm UTC](https://discourse.julialang.org/t/julia-and-the-gps-payload-onboard-waratah-seed-1-satellite/123795/18 "2024-12-25T19:48:04Z")

</div>

> [@xiaoxi](#):
>
> Could the first OP post be modified to become a Julia-lang blog post?
> 
> I wish Julia-lang blog could also post successful use cases of Julia like this one.

To add a blog post, just create a pull request:

> <https://github.com/JuliaLang/www.julialang.org/pull/2145>
>
> Let's see how this looks. Comments please!

---

<div class="post-metadata">

### Author: ![Ronis\_BR](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ronis_br/32/50999_2.png) [@Ronis\_BR](https://discourse.julialang.org/u/Ronis_BR)
#### Post date: [December 26, 2024, 12:17am UTC](https://discourse.julialang.org/t/julia-and-the-gps-payload-onboard-waratah-seed-1-satellite/123795/19 "2024-12-26T00:17:10Z")

</div>

> [@minetest2048](#):
>
> The thing with ECI and ECEF conversion is that the conversion DCM changes every second, unlike geodetic datum conversion where the agency releases new datum every year or so. At least that’s what I understand from SatelliteToolbox [ISS tutorial](https://juliaspace.github.io/SatelliteToolbox.jl/stable/tutorials/iss_observation/)

Yes! You are completely right.

> [@minetest2048](#):
>
> What’s currently missing is a `StateVector` struct, parameterized on time type and reference frame type for position and its derivatives:

We really need to annotate the reference frame, but we already have a state vector representation that you can use to convert between ECI and ECEF. It also transforms the velocity as it was measured by an observer in the ECEF reference frame:

```julia
julia> using SatelliteToolbox

julia> f = create_tle_fetcher(CelestrakTleFetcher)
CelestrakTleFetcher("https://celestrak.org/NORAD/elements/gp.php")

julia> tles = fetch_tles(f; satellite_name = "ISS (ZARYA)")
[ Info: Fetch TLEs from Celestrak using satellite name: "ISS (ZARYA)" ...
1-element Vector{TLE}:
 TLE: ISS (ZARYA) (Epoch = 2024-12-25T11:54:31.088)

julia> iss_tle = tles[1]
TLE:
                      Name : ISS (ZARYA)
          Satellite number : 25544
  International designator : 98067A
        Epoch (Year / Day) : 24 / 360.49619315 (2024-12-25T11:54:31.088)
        Element set number : 999
              Eccentricity : 0.00056820
               Inclination : 51.63780000 deg
                      RAAN : 87.51690000 deg
       Argument of perigee : 4.67930000 deg
              Mean anomaly : 355.42490000 deg
           Mean motion (n) : 15.50207956 revs / day
         Revolution number : 48822
                        B* : 0.00042581 1 / er
                     ṅ / 2 : 0.00024109 rev / day²
                     n̈ / 6 : 0 rev / day³

julia> orbp = Propagators.init(Val(:SGP4), iss_tle)
OrbitPropagatorSgp4{Float64, Float64}:
   Propagator name : SGP4 Orbit Propagator
  Propagator epoch : 2024-12-25T11:54:31.088
  Last propagation : 2024-12-25T11:54:31.088

julia> r_teme, v_teme = Propagators.propagate!(orbp, 0)
([294198.57439655927, 6.7847714223184595e6, 32.68505834064143], [-4751.8787639694765, 199.06599097725888, 6013.0710696574815])

julia> sv_teme = OrbitStateVector(Propagators.epoch(orbp), r_teme, v_teme)
OrbitStateVector{Float64, Float64}:
  epoch : 2.46067e6 (2024-12-25T11:54:31.088)
      r : [294.199, 6784.77, 0.0326851] km
      v : [-4.75188, 0.199066, 6.01307] km/s

julia> sv_eci_to_ecef(sv_teme, TEME(), PEF(), Propagators.epoch(orbp))
OrbitStateVector{Float64, Float64}:
  epoch : 2.46067e6 (2024-12-25T11:54:31.088)
      r : [-6758.72, 662.88, 0.0326851] km
      v : [-0.408953, -4.24116, 6.01307] km/s

```

The last output is the position and velocity vector of the ISS as measured by an observer in the PEF reference frame.

You can also add the acceleration to the state vector if you want and the `sv_eci_to_ecef` will convert it for you.

---

<div class="post-metadata">

### Author: ![minetest2048](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/minetest2048/32/45961_2.png) [@minetest2048](https://discourse.julialang.org/u/minetest2048)
#### Post date: [December 26, 2024, 1:08pm UTC](https://discourse.julialang.org/t/julia-and-the-gps-payload-onboard-waratah-seed-1-satellite/123795/20 "2024-12-26T13:08:00Z")

</div>

`OrbitStateVector` is exactly what I wanted! If only we can get `Propagators.propagate!` to spit out `OrbitStateVector` automatically instead of `(position,velocity)` tuple

[Next page](https://discourse.julialang.org/t/julia-and-the-gps-payload-onboard-waratah-seed-1-satellite/123795.md?page=2)
