diff --git a/.github/wiki/examples/solar-position.md b/.github/wiki/examples/solar-position.md new file mode 100644 index 0000000..957c944 --- /dev/null +++ b/.github/wiki/examples/solar-position.md @@ -0,0 +1,40 @@ +# Example: Solar Position Logger + +Print solar position every 30 minutes throughout a day. + +```js +import { calcSpa } from 'nrel-spa'; + +const LAT = 40.7128; // New York +const LON = -74.0060; +const TZ = -4; // EDT + +const date = new Date('2025-06-21T00:00:00-04:00'); + +console.log('Time (local) Zenith Azimuth'); +console.log('──────────── ──────── ────────'); + +for (let hour = 4; hour <= 21; hour++) { + for (const min of [0, 30]) { + const d = new Date(date); + d.setHours(hour, min, 0, 0); + const r = calcSpa(d, LAT, LON, TZ); + const timeStr = `${String(hour).padStart(2, '0')}:${String(min).padStart(2, '0')}`; + const zenith = Number(r.zenith).toFixed(1).padStart(7); + const azimuth = Number(r.azimuth).toFixed(1).padStart(7); + console.log(`${timeStr} ${zenith}° ${azimuth}°`); + } +} +``` + +Sample output (abbreviated): + +``` +Time (local) Zenith Azimuth +──────────── ──────── ──────── +05:30 89.3° 60.2° +06:00 83.1° 68.4° +12:00 24.6° 185.1° +13:00 26.1° 212.3° +20:00 83.8° 293.7° +``` diff --git a/.github/wiki/examples/twilight-times.md b/.github/wiki/examples/twilight-times.md new file mode 100644 index 0000000..a643e4c --- /dev/null +++ b/.github/wiki/examples/twilight-times.md @@ -0,0 +1,33 @@ +# Example: Twilight Times + +Compute civil, nautical, and astronomical twilight for a location. + +```js +import { getSpa, formatTime } from 'nrel-spa'; + +const LAT = 34.0522; // Los Angeles +const LON = -118.2437; +const TZ = -7; // PDT + +const date = new Date('2025-09-15T12:00:00-07:00'); + +const r = getSpa(date, LAT, LON, TZ, {}, [90.833, 96, 102, 108]); + +const labels = ['Sunrise/Sunset', 'Civil', 'Nautical', 'Astronomical']; + +for (let i = 0; i < r.customAngles.length; i++) { + const ca = r.customAngles[i]; + const rise = formatTime(ca.sunrise); + const set = formatTime(ca.sunset); + console.log(`${labels[i].padEnd(16)} dawn: ${rise} dusk: ${set}`); +} +``` + +Sample output: + +``` +Sunrise/Sunset dawn: 06:30:42 dusk: 19:12:18 +Civil dawn: 06:04:11 dusk: 19:38:49 +Nautical dawn: 05:33:07 dusk: 20:09:53 +Astronomical dawn: 05:01:19 dusk: 20:41:41 +``` diff --git a/.github/wiki/guides/advanced.md b/.github/wiki/guides/advanced.md new file mode 100644 index 0000000..1bc22b0 --- /dev/null +++ b/.github/wiki/guides/advanced.md @@ -0,0 +1,78 @@ +# Advanced Usage + +## Twilight calculations + +Pass an array of custom zenith angles to compute additional rise/set events beyond the default solar disk (90.833°). + +```js +import { getSpa } from 'nrel-spa'; + +const result = getSpa(date, lat, lon, tz, {}, [96, 102, 108]); + +for (const ca of result.customAngles) { + const label = ca.angle === 96 ? 'Civil' : ca.angle === 102 ? 'Nautical' : 'Astronomical'; + console.log(`${label} dawn: ${ca.sunrise.toFixed(4)} hours`); + console.log(`${label} dusk: ${ca.sunset.toFixed(4)} hours`); +} +``` + +Zenith reference: +- 90.833° — standard solar disk (default) +- 96° — civil twilight +- 102° — nautical twilight +- 108° — astronomical twilight + +## Batch processing + +`getSpa` is synchronous, making batch work straightforward without async coordination. + +```js +import { getSpa } from 'nrel-spa'; + +const lat = 51.5074; // London +const lon = -0.1278; +const tz = 0; + +let totalDaylight = 0; +for (let doy = 0; doy < 365; doy++) { + const d = new Date(Date.UTC(2025, 0, 1 + doy, 12, 0, 0)); + const r = getSpa(d, lat, lon, tz); + if (isFinite(r.sunrise)) { + totalDaylight += r.sunset - r.sunrise; + } +} +console.log(`Annual daylight: ${totalDaylight.toFixed(0)} hours`); +``` + +## Polar scenarios + +At high latitudes, `sunrise` and `sunset` are `NaN` when the sun does not cross the horizon. Check with `isFinite()`. + +```js +const r = getSpa(new Date('2025-12-21T12:00:00Z'), 89, 0, 0); +console.log(isFinite(r.sunrise)); // false — polar night +``` + +`calcSpa` returns `"N/A"` strings in these cases. + +## vs solar-spa + +Both packages implement the same NREL SPA algorithm. Key differences: + +| | nrel-spa | solar-spa | +|---|---|---| +| Runtime | Pure JS | WebAssembly | +| API | Synchronous | Async (Promise) | +| Custom zenith | Yes | No | +| Bundle size | ~38 KB | ~60 KB | +| Init latency | None | First call | + +Use `nrel-spa` when you need synchronous calls or custom twilight angles. Use `solar-spa` when throughput for very large batches matters. + +## Delta-T + +The default `delta_t` is 67 seconds, accurate for dates near 2025. For historical dates or high-precision work, provide a value from the IERS or USNO tables. + +```js +getSpa(new Date('1900-01-01T12:00:00Z'), lat, lon, tz, { delta_t: -2.72 }); +``` diff --git a/.github/wiki/guides/quickstart.md b/.github/wiki/guides/quickstart.md new file mode 100644 index 0000000..0411567 --- /dev/null +++ b/.github/wiki/guides/quickstart.md @@ -0,0 +1,77 @@ +# Quick Start + +Five minutes from install to solar position. + +## Install + +```sh +npm install nrel-spa +``` + +## Basic usage + +```js +import { getSpa } from 'nrel-spa'; + +const result = getSpa( + new Date('2025-06-21T12:00:00Z'), + 40.7128, // latitude + -74.0060, // longitude + -4, // UTC offset in hours (EDT) +); + +console.log(result.zenith); // solar zenith angle in degrees +console.log(result.azimuth); // solar azimuth in degrees +console.log(result.sunrise); // fractional hours, e.g. 5.42 +console.log(result.sunset); // fractional hours, e.g. 20.58 +console.log(result.solarNoon); // fractional hours, e.g. 13.00 +``` + +`getSpa` is synchronous. There is no initialization step, no WASM loading, no async overhead. + +## Formatted output + +```js +import { calcSpa } from 'nrel-spa'; + +const result = calcSpa( + new Date('2025-06-21T12:00:00Z'), + 40.7128, + -74.0060, + -4, +); + +console.log(result.sunrise); // "05:25:12" +console.log(result.sunset); // "20:34:47" +console.log(result.solarNoon); // "12:59:58" +``` + +## Custom zenith angles (twilight) + +```js +import { getSpa } from 'nrel-spa'; + +const civil = getSpa(date, lat, lon, tz, {}, [96]); // civil twilight +const nautical = getSpa(date, lat, lon, tz, {}, [102]); // nautical twilight +const astro = getSpa(date, lat, lon, tz, {}, [108]); // astronomical twilight + +console.log(civil.customAngles[0].sunrise); // civil dawn +console.log(nautical.customAngles[0].sunrise); // nautical dawn +``` + +## Options + +```js +const result = getSpa(date, lat, lon, tz, { + elevation: 100, // metres above sea level + pressure: 1013.25, // millibars + temperature: 15, // Celsius + delta_t: 67, // ΔT in seconds +}); +``` + +## Next steps + +- [API Reference](../API-Reference) — full function signatures and return types +- [Architecture](../Architecture) — module structure and algorithm notes +- [Advanced Guide](advanced) — twilight, batch calculations, polar scenarios