antex

package
v0.38.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Feb 23, 2026 License: Apache-2.0 Imports: 8 Imported by: 0

README

ANTEX Package

This package provides reading and writing support for ANTEX (Antenna Exchange Format) files.

Overview

ANTEX files contain GNSS antenna calibration data including:

  • Phase Center Offsets (PCO) for different frequencies
  • Phase Center Variations (PCV) as a function of elevation and azimuth
  • Antenna type, serial number, and calibration information

Structure

  • antex.go - Core data structures (ANTEX, Header, Antenna, PCO, PCV)
  • reader.go - Reading and parsing ANTEX files
  • writer.go - Writing ANTEX files

Usage

Reading ANTEX Files
import (
	"log/slog"
	"os"
	"gitlab.com/earthscope/gnsstools/pkg/encoding/antex"
	"gitlab.com/earthscope/gnsstools/pkg/common/logging"
)

file, _ := os.Open("antenna.atx")
defer file.Close()

reader := antex.NewReader(file)
if err := reader.ReadAll(); err != nil {
    logging.Fatal("Failed to read ANTEX file", "error", err)
}

antex := reader.GetANTEX()
for _, antenna := range antex.Antennas {
    fmt.Printf("Antenna: %s / %s\n", antenna.Type, antenna.SerialNumber)
}
Writing ANTEX Files
import (
	"log/slog"
	"os"
	"time"
	"gitlab.com/earthscope/gnsstools/pkg/encoding/antex"
	"gitlab.com/earthscope/gnsstools/pkg/common/logging"
)

antex := &antex.ANTEX{
    Header: antex.Header{
        Version: "1.4",
        Program: "gnsstools",
        Agency:  "EarthScope",
        Date:    time.Now(),
        Type:    "ANTEX",
    },
    Antennas: []antex.Antenna{
        // ... antenna data
    },
}

file, _ := os.Create("output.atx")
defer file.Close()

writer := antex.NewWriter(file)
if err := writer.WriteHeader(&antex.Header); err != nil {
    logging.Fatal("Failed to write header", "error", err)
}
for _, antenna := range antex.Antennas {
    if err := writer.WriteAntenna(&antenna); err != nil {
        logging.Fatal("Failed to write antenna", "error", err)
    }
}

ANTEX Format

ANTEX files are ASCII text files with fixed-width columns:

  • Lines are 80 characters wide
  • Label field: 60 characters (left-aligned)
  • Value field: 20 characters (right-aligned for labels)
Key Records
  • ANTEX VERSION / TYPE - Format version and file type
  • TYPE / SERIAL NO - Antenna type and serial number
  • START OF ANTENNA - Marks beginning of antenna entry
  • END OF ANTENNA - Marks end of antenna entry
  • Phase center offset records (per frequency)
  • Phase center variation records (per frequency)

Status

⚠️ Work in Progress - Basic structure is in place, but parsing and writing logic needs to be completed based on the ANTEX specification.

Documentation

Overview

Package antex provides reading and writing of ANTEX (Antenna Exchange) format files.

ANTEX is the standard format for GNSS antenna calibration data, containing phase center offsets (PCO) and phase center variations (PCV) for both receiver and satellite antennas.

Reading ANTEX Files

Use NewReader to create a reader, then call ReadHeader and ReadAntenna:

file, _ := os.Open("igs20.atx")
defer file.Close()

reader := antex.NewReader(file)
if err := reader.ReadHeader(); err != nil {
    log.Fatal(err)
}

for {
    antenna, err := reader.ReadAntenna()
    if err == io.EOF {
        break
    }
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("Antenna: %s\n", antenna.Type)
}

Or use ReadAll to read all antennas at once:

reader := antex.NewReader(file)
if err := reader.ReadAll(); err != nil {
    log.Fatal(err)
}
antexData := reader.GetANTEX()
fmt.Printf("Read %d antennas\n", len(antexData.Antennas))

Writing ANTEX Files

Use NewWriter to create a writer, then write the header and antennas:

file, _ := os.Create("output.atx")
defer file.Close()

writer := antex.NewWriter(file)
if err := writer.WriteHeader(&header); err != nil {
    log.Fatal(err)
}

for _, antenna := range antennas {
    if err := writer.WriteAntenna(&antenna); err != nil {
        log.Fatal(err)
    }
}

Data Structure

The ANTEX type contains the header and a list of antennas. Each Antenna contains phase center offsets and variations for multiple frequencies.

Grid parameters (DAZI, ZenithStart, ZenithEnd, ZenithDelta) are stored at the antenna level and shared by all frequencies, as specified in ANTEX 1.4. Use antenna.AzimuthGrid() and antenna.ElevationGrid() to compute the actual grid points.

Phase center variations have two components:

  • NoAziElevation: Non-azimuth-dependent pattern (always present)
  • PCVValues: Azimuth-dependent pattern (only when DAZI > 0)

See the ANTEX 1.4 specification for details on the format.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type ANTEX

type ANTEX struct {
	Header   Header
	Antennas []Antenna
}

ANTEX represents an ANTEX file containing antenna calibration data

func (*ANTEX) FindAntennaByID

func (a *ANTEX) FindAntennaByID(id string, t *time.Time) (*Antenna, error)

FindAntennaByID finds an antenna by its identifier. The identifier can be:

  • SVN code (e.g., "G032", "G049")
  • SINEX code (e.g., "IGS20_2388")
  • Type (e.g., "BLOCK IIA")
  • COSPAR ID (e.g., "1992-079A")

Returns the first antenna matching the identifier. For time-dependent lookup by SVN, provide the time parameter.

func (*ANTEX) FindAntennaByPRN

func (a *ANTEX) FindAntennaByPRN(prn string, sys gnss.System, t time.Time) (*Antenna, error)

FindAntennaByPRN finds the antenna for a given PRN at a specific time. This uses the VALID FROM / VALID UNTIL dates in the ANTEX file to determine which satellite (SVN) was using the PRN at the given time.

For satellite antennas, the SerialNumber field contains the PRN. Returns the first antenna matching the PRN and time constraints.

func (*ANTEX) FindAntennaByType

func (a *ANTEX) FindAntennaByType(antennaType string) (*Antenna, error)

FindAntennaByType finds an antenna by its type string. This is useful for receiver antennas or block-type satellite antennas.

For receiver antennas, type format is: "ANTENNA_TYPE RADOME" For satellite antennas, type is the block: "BLOCK IIA", "BLOCK IIR-M", etc.

Returns the first antenna matching the type.

func (*ANTEX) FindAntennasByPRN

func (a *ANTEX) FindAntennasByPRN(prn string) []*Antenna

FindAntennasByPRN returns all antennas that have used a specific PRN, sorted by ValidFrom date. This is useful for seeing the complete history of a PRN slot.

type Antenna

type Antenna struct {
	Type              string    // Antenna type (A20)
	SerialNumber      string    // Serial number (A20)
	CalibrationMethod string    // Calibration method (A20)
	CalibrationAgency string    // Calibration agency (A20)
	CalibrationDate   time.Time // Calibration date
	ValidFrom         time.Time // Valid from date
	ValidUntil        time.Time // Valid until date
	SinexCode         string    // SINEX code (A10)
	SVNCode           string    // Space Vehicle Number (A10) - for satellites
	COSPARCode        string    // COSPAR ID (A10) - for satellites

	// Grid parameters define the elevation and azimuth sampling grid.
	// These are shared by all frequencies in this antenna per ANTEX 1.4 spec.
	DAZI        float64 // Azimuth increment (degrees), 0 = NOAZI only
	ZenithStart float64 // Starting zenith/elevation angle (degrees)
	ZenithEnd   float64 // Ending zenith/elevation angle (degrees)
	ZenithDelta float64 // Zenith increment (degrees)

	// Phase Center Offsets (PCO) per frequency
	PhaseCenterOffsets []PhaseCenterOffset

	// Phase Center Variations (PCV) per frequency
	PhaseCenterVariations []PhaseCenterVariation
}

Antenna represents a single antenna calibration entry

func (*Antenna) AzimuthGrid

func (a *Antenna) AzimuthGrid() []float64

AzimuthGrid computes the azimuth grid from DAZI. Returns nil if DAZI == 0 (NOAZI-only antenna).

func (*Antenna) ElevationGrid

func (a *Antenna) ElevationGrid() []float64

ElevationGrid computes the elevation (zenith) grid from zenith parameters.

func (*Antenna) FindPCOForFrequency

func (a *Antenna) FindPCOForFrequency(sys gnss.System, freqCode string) *PhaseCenterOffset

FindPCOForFrequency finds the PCO data for a specific frequency in an antenna. Returns nil if the frequency is not found.

func (*Antenna) FindPCVForFrequency

func (a *Antenna) FindPCVForFrequency(sys gnss.System, freqCode string) *PhaseCenterVariation

FindPCVForFrequency finds the PCV data for a specific frequency in an antenna. Returns nil if the frequency is not found.

func (*Antenna) InterpolatePCV

func (a *Antenna) InterpolatePCV(pcv *PhaseCenterVariation, elevation, azimuth float64) (float64, error)

InterpolatePCV computes the PCV correction at a given elevation and azimuth angle. Elevation and azimuth are in degrees.

For NOAZI antennas (DAZI == 0), only elevation is used. For AZI antennas (DAZI > 0), bilinear interpolation is performed.

Elevation is measured from zenith (0° = zenith, 90° = horizon). Azimuth is measured clockwise from north (0° = north, 90° = east).

Returns the PCV correction in millimeters and an error if interpolation fails.

func (*Antenna) Validate

func (a *Antenna) Validate() error

Validate performs consistency checks on antenna data. Should be called before writing to ensure valid ANTEX files.

type Header struct {
	Version     string    // ANTEX format version (e.g., "1.4")
	Program     string    // Program that created the file
	Agency      string    // Agency that created the file
	Date        time.Time // File creation date
	Comment     []string  // Comments
	Type        string    // Type of data (usually "ANTEX")
	PCVType     string    // Type of PCV data (ABS/REL)
	NumAntennas int       // Number of antennas in file
}

Header contains the ANTEX file header information

type PhaseCenterOffset

type PhaseCenterOffset struct {
	System      gnss.System // GNSS system (G/R/E/C/J/I/S)
	Frequency   string      // Frequency identifier (e.g., "G01", "G02", "R01", etc.)
	NorthOffset float64     // North offset (mm)
	EastOffset  float64     // East offset (mm)
	UpOffset    float64     // Up offset (mm)
}

PhaseCenterOffset represents phase center offset for a specific frequency

func (*PhaseCenterOffset) GetPCOVector

func (pco *PhaseCenterOffset) GetPCOVector() [3]float64

GetPCOVector returns the phase center offset as a 3D vector [North, East, Up] in millimeters.

func (*PhaseCenterOffset) Magnitude

func (pco *PhaseCenterOffset) Magnitude() float64

Magnitude returns the magnitude of the PCO vector in millimeters.

type PhaseCenterVariation

type PhaseCenterVariation struct {
	System    gnss.System // GNSS constellation
	Frequency string      // Frequency identifier (e.g., "G01" for GPS L1)

	// Non-azimuth-dependent pattern (NOAZI)
	// Always present per spec, even when DAZI > 0
	// Values correspond to Antenna.ElevationGrid() points
	NoAziElevation []float64

	// Azimuth-dependent pattern (AZI)
	// Only present when Antenna.DAZI > 0
	// Dimensions: [num_azimuth][num_elevation]
	//   num_azimuth = len(Antenna.AzimuthGrid()) = 360 / DAZI
	//   num_elevation = len(Antenna.ElevationGrid())
	PCVValues [][]float64
}

PhaseCenterVariation represents phase center variation as a function of elevation/azimuth.

Per ANTEX 1.4 specification (lines 275-278 in antex14.txt):

  • NoAziElevation values are ALWAYS present (even when DAZI > 0)
  • PCVValues (azimuth-dependent) are only present when DAZI > 0

Use Antenna.ElevationGrid() and Antenna.AzimuthGrid() to get the corresponding grid points for the values.

type Reader

type Reader struct {
	// contains filtered or unexported fields
}

Reader reads ANTEX files

func NewReader

func NewReader(r io.Reader) *Reader

NewReader creates a new ANTEX reader

func (*Reader) GetANTEX

func (r *Reader) GetANTEX() *ANTEX

GetANTEX returns the parsed ANTEX structure

func (*Reader) ReadAll

func (r *Reader) ReadAll() error

ReadAll reads all antennas from the ANTEX file

func (*Reader) ReadAntenna

func (r *Reader) ReadAntenna() (*Antenna, error)

ReadAntenna reads a single antenna entry from the ANTEX file The scanner should be positioned at or before the START OF ANTENNA line

func (*Reader) ReadHeader

func (r *Reader) ReadHeader() error

ReadHeader reads the ANTEX file header

type Writer

type Writer struct {
	// contains filtered or unexported fields
}

Writer writes ANTEX files

func NewWriter

func NewWriter(w io.Writer) *Writer

NewWriter creates a new ANTEX writer

func (*Writer) WriteAntenna

func (w *Writer) WriteAntenna(antenna *Antenna) error

WriteAntenna writes a single antenna entry

func (*Writer) WriteHeader

func (w *Writer) WriteHeader(header *Header) error

WriteHeader writes the ANTEX file header

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL