pray-calc-ml/.wiki/API-Reference.md
Aric Camarata bbe1bf5cbc v1.0.0 — initial release
Weighted least-squares calibration of Islamic prayer time depression
angles from observed mosque announcement data. Uses golden-section
search to minimize the sum of squared residuals independently for
Fajr and Isha. Internal Jean Meeus solar ephemeris — zero runtime
dependencies.

API: calibrateAngles, scoreAngles, predictFajr, predictIsha.
Full TypeScript, dual CJS/ESM via tsup.
32 ESM tests, 6 CJS tests, all passing on Node 20/22/24.
2026-02-25 18:48:07 -05:00

150 lines
4.4 KiB
Markdown

# API Reference
## `calibrateAngles(observations, options?)`
Finds the Fajr and Isha depression angles that minimize the weighted sum of squared residuals across all observations.
```ts
function calibrateAngles(
observations: Observation[],
options?: CalibrationOptions,
): CalibrationResult
```
### Parameters
**`observations: Observation[]`**
An array of recorded prayer times. Each entry may supply a Fajr time, an Isha time, or both. Entries missing a field are ignored for the corresponding angle.
At least 2 observations are required per prayer. If one prayer has fewer than 2 observations, that angle falls back to the initial guess (`fajrAngle0` or `ishaAngle0`). If both prayers have fewer than 2, the function throws.
**`options?: CalibrationOptions`**
| Field | Type | Default | Description |
| --- | --- | --- | --- |
| `fajrAngle0` | `number` | `15.0` | Initial Fajr angle guess in degrees |
| `ishaAngle0` | `number` | `15.0` | Initial Isha angle guess in degrees |
| `fajrMin` | `number` | `10.0` | Minimum allowed Fajr angle |
| `fajrMax` | `number` | `22.0` | Maximum allowed Fajr angle |
| `ishaMin` | `number` | `10.0` | Minimum allowed Isha angle |
| `ishaMax` | `number` | `22.0` | Maximum allowed Isha angle |
| `maxIter` | `number` | `200` | Maximum solver iterations |
| `tol` | `number` | `1e-5` | Convergence tolerance in degrees |
### Returns `CalibrationResult`
| Field | Type | Description |
| --- | --- | --- |
| `angles` | `CalibratedAngles` | Best-fit `fajrAngle` and `ishaAngle` in degrees |
| `rmsMinutes` | `number` | Weighted RMS residual in minutes |
| `observationCount` | `number` | Effective count (dual=1, single=0.5) |
| `residuals` | `Array<{fajrMin, ishaMin}>` | Per-observation residuals in minutes |
Residuals are signed: positive means the model predicted later than the observation.
### Throws
- If neither Fajr nor Isha has at least 2 observations.
---
## `scoreAngles(observations, fajrAngle, ishaAngle)`
Evaluates a fixed pair of depression angles against observation data without fitting.
```ts
function scoreAngles(
observations: Observation[],
fajrAngle: number,
ishaAngle: number,
): ScoreResult
```
### Returns `ScoreResult`
| Field | Type | Description |
| --- | --- | --- |
| `rmsMinutes` | `number` | Weighted RMS error in minutes |
| `fajrBiasMinutes` | `number` | Signed mean Fajr error (positive: angle predicts Fajr too late) |
| `ishaBiasMinutes` | `number` | Signed mean Isha error |
| `residuals` | `Array<{fajrMin, ishaMin}>` | Per-observation residuals |
Use this to compare multiple standard methods against your data:
```ts
import { scoreAngles } from 'pray-calc-ml';
const obs = [/* ... */];
const isna = scoreAngles(obs, 15, 15); // ISNA
const mwl = scoreAngles(obs, 18, 17); // MWL
const uoif = scoreAngles(obs, 12, 12); // UOIF
console.log('ISNA RMS:', isna.rmsMinutes.toFixed(2));
console.log('MWL RMS:', mwl.rmsMinutes.toFixed(2));
console.log('UOIF RMS:', uoif.rmsMinutes.toFixed(2));
```
---
## `predictFajr(date, lat, lng, tz, fajrAngle)`
Predict the Fajr time for a given date, location, and depression angle.
```ts
function predictFajr(
date: Date,
lat: number,
lng: number,
tz: number,
fajrAngle: number,
): number // fractional hours, local time; NaN at polar extremes
```
---
## `predictIsha(date, lat, lng, tz, ishaAngle)`
Predict the Isha time for a given date, location, and depression angle.
```ts
function predictIsha(
date: Date,
lat: number,
lng: number,
tz: number,
ishaAngle: number,
): number // fractional hours, local time; NaN at polar extremes
```
---
## `Observation` type
```ts
interface Observation {
date: Date; // local calendar date
lat: number; // decimal degrees, south = negative
lng: number; // decimal degrees, west = negative
tz: number; // UTC offset in hours (e.g. -5 for EST, +3 for AST)
fajr?: number; // fractional hours local time (e.g. 4.5 = 4:30 AM)
isha?: number; // fractional hours local time (e.g. 21.25 = 9:15 PM)
weight?: number; // relative weight, default 1.0
}
```
---
## `CalibratedAngles` type
```ts
interface CalibratedAngles {
fajrAngle: number; // degrees below horizon (positive)
ishaAngle: number; // degrees below horizon (positive)
}
```
---
*[Home](Home) | [Architecture](Architecture) | [Guide: Collecting Observations](Guide-Collecting-Observations) | [Guide: Integrating with pray-calc](Guide-Integrating-with-pray-calc)*