from life import experience as wisdom

~/posts/Panchanga computation from first principles

<<< 2025/Oct/01 · tools, astronomy, hobbies >>>
Computing the five elements of a Vedic panchanga from planetary positions using VSOP87 solar theory and lunar ephemeris.

Introduction

A panchanga is a Hindu calendar that encodes five (pancha) elements (anga) for any given moment: tithi, vara, nakshatra, yoga and karana. Each derives from a specific astronomical quantity and computing them correctly requires accurate solar and lunar positions.

I needed to compute all five from first principles for drikganit. No lookup tables, no pre-computed almanacs. Raw planetary theory to calendar output.

Tithi: Sun-Moon elongation

Tithi is the angular separation between the Sun and Moon, divided into 30 units of 12 degrees each. When the Moon is exactly conjunct with the Sun (new moon, 0 degrees separation), that is Amavasya. When the separation reaches 180 degrees (full moon), that is Purnima. The 15 tithis from new to full are Shukla Paksha (waxing). The 15 from full back to new are Krishna Paksha (waning).

30 tithis arranged around the Sun-Moon angular relationship
30 tithis arranged around the Sun-Moon angular relationship

Let's have a look at the actual implementation in drikganit:

def calculate_tithi(sun_lon, moon_lon):
  """calculate tithi from sun and moon longitudes"""
  # elongation (moon - sun)
  delta = (moon_lon - sun_lon) % 360

  # tithi index (1-30)
  index = int(delta / 12) + 1

  # progress within tithi
  progress = (delta % 12) / 12 * 100

  # paksha
  paksha = "Śukla" if index <= 15 else "Kṛṣṇa"

  return {
    'index': index,
    'name_iast': tithi_names[index - 1],
    'paksha': paksha,
    'progress': round(progress, 1),
  }

The modulo 360 handles wrap-around at conjunction. Floor division by 12 maps the continuous angular separation onto 30 discrete tithis. The fractional part (progress) tells you how far into the current tithi you are: useful for muhurta (auspicious timing) calculations.

Accuracy matters here. A 0.1 degree error in either the Sun or Moon position shifts the tithi boundary by about 20 minutes. For a panchanga reporting tithi transitions to the minute, the ephemeris has to hold sub-arcminute accuracy.

Vara: the simple one

Vara is the weekday. It follows a fixed seven-day cycle with no astronomical computation needed beyond knowing the Julian Day Number. Sunday = 0, Monday = 1 and so on. The only subtlety is the local sunrise time, because the Hindu day starts at sunrise, not midnight. A moment at 3am on a Tuesday in civil time might still be Monday in panchanga terms if sunrise has not occurred.

Nakshatra: lunar mansion

The ecliptic is divided into 27 nakshatras, each spanning 13 degrees 20 minutes (13.333 degrees). The nakshatra at any moment is determined by the Moon's sidereal longitude. Here is the implementation:

def calculate_nakshatra(longitude):
  """calculate nakshatra from longitude"""
  nakshatra_span = 360 / 27  # 13.333...°
  index = int(longitude / nakshatra_span) + 1
  position_in_nakshatra = longitude % nakshatra_span
  pada = int(position_in_nakshatra / (nakshatra_span / 4)) + 1
  progress = (position_in_nakshatra / nakshatra_span) * 100

  return {
    'index': index,
    'name_iast': nakshatra_names[index - 1],
    'pada': pada,
    'progress': round(progress, 1)
  }

Each nakshatra is further divided into 4 padas (quarters), each spanning 3 degrees 20 minutes. The pada matters for jyotish calculations.

The sidereal part matters. Western astronomy uses tropical longitude (referenced to the vernal equinox, which precesses). Indian astronomy uses sidereal longitude (referenced to fixed stars). The difference between the two is the ayanamsha, currently about 24 degrees and slowly increasing. drikganit configures this at startup:

swe.set_sid_mode(swe.SIDM_LAHIRI)  # vedic sidereal ayanamsa

Lahiri ayanamsha is the Indian government's official standard.

Yoga: combined longitude

Yoga is the sum of solar and lunar sidereal longitudes, divided into 27 segments of 13 degrees 20 minutes each. The same 13.333 degree division as nakshatras, but applied to the sum rather than the Moon alone. There are 27 yogas, each with a name and a traditional characterization (auspicious, neutral, inauspicious).

The implementation in drikganit:

def calculate_yoga_element(sun_lon, moon_lon):
  """calculate yoga from sun and moon longitudes"""
  # sum of longitudes
  total = (sun_lon + moon_lon) % 360

  # yoga span
  yoga_span = 360 / 27  # 13.333...°

  # yoga index (1-27)
  index = int(total / yoga_span) + 1

  # progress within yoga
  progress = (total % yoga_span) / yoga_span * 100

  return {
    'index': index,
    'name_iast': yoga_names[index - 1],
    'progress': round(progress, 1),
  }

Karana: half-tithi

A karana is half a tithi, so there are 60 karanas in a synodic month. The first and last karanas (Kimstughna and the four fixed karanas) are fixed. The remaining 56 cycle through seven repeating karanas. The computation follows directly from the tithi calculation: multiply the tithi index by 2 and you have the karana index.

The ephemeris: VSOP87 and lunar series

For solar longitude, I use VSOP87 truncated to terms that give sub-arcsecond accuracy over several centuries. The full VSOP87 series has thousands of terms. For panchanga accuracy (which needs about 1 arcminute), a few hundred terms suffice.

For lunar longitude, I use Jean Meeus's adaptation of the lunar ephemeris from "Astronomical Algorithms." The Moon's orbit is complex. The main terms are the mean anomaly, mean elongation and the argument of latitude, plus about 60 periodic correction terms. Getting sub-arcminute lunar longitude is harder than solar because the Moon moves faster (about 13 degrees per day vs. 1 degree for the Sun) and its orbit has more perturbation terms.

Accuracy testing

I tested drikganit's panchanga output against Drik Panchang, which is the most widely used online panchanga and is based on Swiss Ephemeris. Let's have a look at a sample comparison for Ujjain on 2026-03-02:

drikganit:                          Drik Panchang:
  Tithi:   Caturdaśī (Śukla)         Chaturdashi (Shukla)     
   Pūrṇimā @ 17:56                  Purnima @ ~17:55        (1m delta)
  Nakṣatra: Āśleṣā/4                 Ashlesha                 
   Maghā/1 @ 07:52                   Magha @ ~07:50          (2m delta)
  Yoga:    Atigaṇḍa                  Atiganda                 
   Sukarman @ 12:19                  Sukarma @ ~12:18        (1m delta)
  Karaṇa:  Vaṇija                    Vanija                   

For a year of daily comparisons, tithi transitions matched to within 2 minutes. Nakshatra boundaries matched to within 3 minutes. Yoga boundaries were within 4 minutes.

The remaining discrepancies come from two sources: ayanamsha value (Lahiri has multiple published precision levels) and the sunrise calculation (which depends on atmospheric refraction and observer altitude). Both are configurable in drikganit.

Conclusion

The five panchanga elements are formulas applied to accurate planetary positions. The math is well-understood. Getting the positions right is the real work, and the sub-arcminute accuracy requirements for tithi and nakshatra boundaries leave little room for ephemeris shortcuts.