Ascendant Calculation
1. Interfaces and Constants
We start by defining the necessary constants and the expected structure for the input data.
// - – 1. CONSTANTS AND INTERFACES – -
interface Coordinates {
latitude: number;
longitude: number;
}
interface BirthData extends Coordinates {
year: number;
month: number;
day: number;
hour: number; // Local Time (24-hour)
minute: number;
timeZoneOffset: number; // e.g., 5.5 for IST
}
interface LagnaResult {
siderealAscendant: number;
jd: number; // Julian Day (for subsequent planet calculations)
ayanamshaDeg: number;
}
// Lahiri Ayanamsha Constants (Simplified Linear Model for Demonstration)
const AYANAMSHA_CONSTANTS = {
// Approx Lahiri value on J2000 (JD 2451545.0)
EPOCH_AYANAMSHA: 23.0 + 15.0 / 60.0 + 32.74 / 3600.0,
// Rate of precession (approx. 50.38 seconds per year converted to degrees per day)
AYANAMSHA_RATE: 50.38 / 3600.0 / 365.25
};
const J2000_JD = 2451545.0; // JD for January 1, 2000, 12:00 UT 2. Ayanamsha Function
This function calculates the Lahiri Ayanamsha for any given Julian Day.
// - – 2. AYANAMSHA CALCULATION – -
/**
* Calculates the Lahiri Ayanamsha for a given Julian Day (JD) using a linear approximation.
* @param jd Julian Day
* @returns The Lahiri Ayanamsha value in degrees.
*/
function calculateAyanamsha(jd: number): number {
const ayanamsha = AYANAMSHA_CONSTANTS.EPOCH_AYANAMSHA + AYANAMSHA_CONSTANTS.AYANAMSHA_RATE * (jd - J2000_JD);
return ayanamsha % 360;
} 3. Core Lagna Calculation Function
This function handles the time conversion, Julian Day, and the final Tropical-to-Sidereal conversion.
// - – 3. CORE VEDIC ASCENDANT (LAGNA) CALCULATION – -
/**
* Calculates the Sidereal Ascendant (Lagna) for a Vedic chart.
*
* @param data The birth details including date, time, coordinates, and time zone.
* @returns An object containing the Sidereal Ascendant degree, Julian Day, and Ayanamsha.
*/
function calculateVedicAscendant(data: BirthData): LagnaResult {
const { year, month, day, hour, minute, latitude, longitude, timeZoneOffset } = data;
// - – 3a. TIME ZONE CORRECTION & JD CALCULATION – -
let localTimeHours = hour + minute / 60.0;
let ut = localTimeHours - timeZoneOffset;
let y = year;
let m = month;
let d = day;
// Adjust date/day if UT pushes time back past midnight
if (ut < 0) {
ut += 24.0;
d -= 1;
if (d < 1) {
m -= 1;
if (m < 1) { m = 12; y -= 1; }
// Get last day of the new month
d = new Date(y, m, 0).getDate();
}
}
// Standard JD calculation (Handles Gregorian Calendar corrections)
if (m <= 2) { y -= 1; m += 12; }
const a = Math.floor(y / 100);
const b = 2 - a + Math.floor(a / 4);
const jd = Math.floor(365.25 * (y + 4716)) +
Math.floor(30.6001 * (m + 1)) +
d + ut / 24.0 + b - 1524.5;
// - – 3b. TROPICAL ASCENDANT CALCULATION – -
const T = (jd - J2000_JD) / 36525.0; // Time in Julian Centuries
// Greenwich Sidereal Time (GST)
let gst = 280.46061837 + 360.98564736629 * (jd - J2000_JD) +
0.000387933 * T * T - (T * T * T) / 38710000.0;
gst = gst % 360; if (gst < 0) gst += 360;
// Local Sidereal Time (LST)
let lst = gst + longitude;
lst = lst % 360; if (lst < 0) lst += 360;
// Obliquity of the Ecliptic (Mean Epsilon)
const epsilon = 23.439291 - 0.0130042 * T;
const epsilonRad = epsilon * Math.PI / 180;
const latRad = latitude * Math.PI / 180;
const lstRad = lst * Math.PI / 180;
// Tropical Ascendant Formula (Spherical Trigonometry)
const y_asc = -Math.cos(lstRad);
const x_asc = Math.sin(lstRad) * Math.cos(epsilonRad) -
Math.tan(latRad) * Math.sin(epsilonRad);
let tropicalAscendant = Math.atan2(y_asc, x_asc) * 180 / Math.PI;
if (tropicalAscendant < 0) tropicalAscendant += 360;
// - – 3c. AYANAMSHA CORRECTION (Tropical -> Sidereal) – -
const ayanamshaDeg = calculateAyanamsha(jd);
let siderealAscendant = tropicalAscendant - ayanamshaDeg;
if (siderealAscendant < 0) {
siderealAscendant += 360;
}
return {
siderealAscendant,
jd,
ayanamshaDeg
};
} 4. Core Lagna Calculation Function
// - – EXAMPLE USAGE – -
const subratBirthData: BirthData = {
year: 1991,
month: 7,
day: 29,
hour: 15,
minute: 30,
latitude: 20.5000,
longitude: 86.42,
timeZoneOffset: 5.5 // IST is UTC + 5.5
};
const result = calculateVedicAscendant(subratBirthData);
// Helper function to convert degree to Sign Name (Rashi)
function getSignName(longitude: number): string {
const signs = ["Aries", "Taurus", "Gemini", "Cancer", "Leo", "Virgo", "Libra", "Scorpio", "Sagittarius", "Capricorn", "Aquarius", "Pisces"];
return signs[Math.floor(longitude / 30)];
}
const lagnaSign = getSignName(result.siderealAscendant);
const lagnaDegree = result.siderealAscendant % 30;
console.log(`\n*** VEDIC LAGNA CALCULATION RESULTS ***`);
console.log(`Date: ${subratBirthData.year}-${subratBirthData.month}-${subratBirthData.day} @ ${subratBirthData.hour}:${subratBirthData.minute} IST`);
console.log(`----------------------------------------`);
console.log(`Julian Day (JD): ${result.jd.toFixed(4)}`);
console.log(`Lahiri Ayanamsha: ${result.ayanamshaDeg.toFixed(3)}°`);
console.log(`\nSIDEREAL ASCENDANT (LAGNA): ${lagnaSign} ${lagnaDegree.toFixed(2)}°`);
// Expected output confirms Sagittarius, matching the earlier assessment:
// Expected: Sagittarius ~22° 