mirror of
https://github.com/acamarata/solar-spa.git
synced 2026-07-02 11:50:42 +00:00
style: fix prettier table formatting in wiki
This commit is contained in:
parent
f21be803fe
commit
a57b4502b2
7 changed files with 256 additions and 258 deletions
|
|
@ -6,49 +6,49 @@ Returns a `Promise<SpaResult>` with raw numeric values.
|
||||||
|
|
||||||
### Parameters
|
### Parameters
|
||||||
|
|
||||||
| Name | Type | Description |
|
| Name | Type | Description |
|
||||||
| --- | --- | --- |
|
| ----------- | -------- | ------------------------------------------------- |
|
||||||
| `date` | `Date` | Date and time for the calculation |
|
| `date` | `Date` | Date and time for the calculation |
|
||||||
| `latitude` | `number` | Observer latitude, -90 to 90 (negative = south) |
|
| `latitude` | `number` | Observer latitude, -90 to 90 (negative = south) |
|
||||||
| `longitude` | `number` | Observer longitude, -180 to 180 (negative = west) |
|
| `longitude` | `number` | Observer longitude, -180 to 180 (negative = west) |
|
||||||
| `options` | `object` | Optional. See below |
|
| `options` | `object` | Optional. See below |
|
||||||
|
|
||||||
### Options
|
### Options
|
||||||
|
|
||||||
| Option | Type | Default | Description |
|
| Option | Type | Default | Description |
|
||||||
| --- | --- | --- | --- |
|
| --------------- | -------- | --------- | ------------------------------------------------------------- |
|
||||||
| `timezone` | `number` | auto | Hours from UTC. Auto-detected from the Date object if omitted |
|
| `timezone` | `number` | auto | Hours from UTC. Auto-detected from the Date object if omitted |
|
||||||
| `elevation` | `number` | `0` | Meters above sea level |
|
| `elevation` | `number` | `0` | Meters above sea level |
|
||||||
| `pressure` | `number` | `1013.25` | Atmospheric pressure in millibars |
|
| `pressure` | `number` | `1013.25` | Atmospheric pressure in millibars |
|
||||||
| `temperature` | `number` | `15` | Temperature in Celsius |
|
| `temperature` | `number` | `15` | Temperature in Celsius |
|
||||||
| `delta_ut1` | `number` | `0` | UT1-UTC correction in seconds |
|
| `delta_ut1` | `number` | `0` | UT1-UTC correction in seconds |
|
||||||
| `delta_t` | `number` | `67` | TT-UTC difference in seconds |
|
| `delta_t` | `number` | `67` | TT-UTC difference in seconds |
|
||||||
| `slope` | `number` | `0` | Surface slope in degrees from horizontal |
|
| `slope` | `number` | `0` | Surface slope in degrees from horizontal |
|
||||||
| `azm_rotation` | `number` | `0` | Surface azimuth rotation in degrees from south |
|
| `azm_rotation` | `number` | `0` | Surface azimuth rotation in degrees from south |
|
||||||
| `atmos_refract` | `number` | `0.5667` | Atmospheric refraction in degrees |
|
| `atmos_refract` | `number` | `0.5667` | Atmospheric refraction in degrees |
|
||||||
| `function` | `number` | `3` | SPA function code (see below) |
|
| `function` | `number` | `3` | SPA function code (see below) |
|
||||||
|
|
||||||
### Result Fields
|
### Result Fields
|
||||||
|
|
||||||
| Field | Type | Unit | Description |
|
| Field | Type | Unit | Description |
|
||||||
| --- | --- | --- | --- |
|
| ----------------- | -------- | ---------------- | ------------------------------------------------------------------ |
|
||||||
| `zenith` | `number` | degrees | Topocentric zenith angle (0 = directly overhead) |
|
| `zenith` | `number` | degrees | Topocentric zenith angle (0 = directly overhead) |
|
||||||
| `azimuth` | `number` | degrees | Topocentric azimuth, eastward from north (navigational convention) |
|
| `azimuth` | `number` | degrees | Topocentric azimuth, eastward from north (navigational convention) |
|
||||||
| `azimuth_astro` | `number` | degrees | Topocentric azimuth, westward from south (astronomical convention) |
|
| `azimuth_astro` | `number` | degrees | Topocentric azimuth, westward from south (astronomical convention) |
|
||||||
| `incidence` | `number` | degrees | Surface incidence angle |
|
| `incidence` | `number` | degrees | Surface incidence angle |
|
||||||
| `sunrise` | `number` | fractional hours | Local sunrise time |
|
| `sunrise` | `number` | fractional hours | Local sunrise time |
|
||||||
| `sunset` | `number` | fractional hours | Local sunset time |
|
| `sunset` | `number` | fractional hours | Local sunset time |
|
||||||
| `suntransit` | `number` | fractional hours | Solar noon (sun transit) |
|
| `suntransit` | `number` | fractional hours | Solar noon (sun transit) |
|
||||||
| `sun_transit_alt` | `number` | degrees | Sun altitude at transit |
|
| `sun_transit_alt` | `number` | degrees | Sun altitude at transit |
|
||||||
| `eot` | `number` | minutes | Equation of time |
|
| `eot` | `number` | minutes | Equation of time |
|
||||||
| `error_code` | `number` | integer | 0 on success |
|
| `error_code` | `number` | integer | 0 on success |
|
||||||
|
|
||||||
### Timezone Auto-detection
|
### Timezone Auto-detection
|
||||||
|
|
||||||
When `timezone` is omitted, the value is derived from the `Date` object's local timezone offset:
|
When `timezone` is omitted, the value is derived from the `Date` object's local timezone offset:
|
||||||
|
|
||||||
```js
|
```js
|
||||||
timezone = -(date.getTimezoneOffset() / 60)
|
timezone = -(date.getTimezoneOffset() / 60);
|
||||||
```
|
```
|
||||||
|
|
||||||
This works correctly in most cases. Provide an explicit value when computing for a location whose timezone differs from the machine's local timezone.
|
This works correctly in most cases. Provide an explicit value when computing for a location whose timezone differs from the machine's local timezone.
|
||||||
|
|
@ -72,16 +72,14 @@ A null result pointer (WASM memory allocation failure) also throws.
|
||||||
Same parameters and behavior as `spa()`. Returns a result object with the same fields, but `sunrise`, `sunset`, and `suntransit` are `HH:MM:SS` strings instead of fractional hours. During polar day or polar night, these strings are `"N/A"`:
|
Same parameters and behavior as `spa()`. Returns a result object with the same fields, but `sunrise`, `sunset`, and `suntransit` are `HH:MM:SS` strings instead of fractional hours. During polar day or polar night, these strings are `"N/A"`:
|
||||||
|
|
||||||
```js
|
```js
|
||||||
const result = await spaFormatted(
|
const result = await spaFormatted(new Date(2025, 5, 21, 12, 0, 0), 40.7128, -74.006, {
|
||||||
new Date(2025, 5, 21, 12, 0, 0),
|
timezone: -4,
|
||||||
40.7128, -74.006,
|
});
|
||||||
{ timezone: -4 }
|
|
||||||
);
|
|
||||||
|
|
||||||
console.log(result.sunrise); // "05:25:12"
|
console.log(result.sunrise); // "05:25:12"
|
||||||
console.log(result.sunset); // "20:30:42"
|
console.log(result.sunset); // "20:30:42"
|
||||||
console.log(result.suntransit); // "12:57:54"
|
console.log(result.suntransit); // "12:57:54"
|
||||||
console.log(result.zenith); // 27.08 (still a number)
|
console.log(result.zenith); // 27.08 (still a number)
|
||||||
```
|
```
|
||||||
|
|
||||||
## `formatTime(hours)`
|
## `formatTime(hours)`
|
||||||
|
|
@ -89,9 +87,9 @@ console.log(result.zenith); // 27.08 (still a number)
|
||||||
Converts fractional hours to an `HH:MM:SS` string. Returns `"N/A"` for non-finite or negative values, which occur during polar day or polar night when sunrise or sunset does not happen. Values at or above 24 hours wrap to the next day (e.g., 24.5 becomes `"00:30:00"`).
|
Converts fractional hours to an `HH:MM:SS` string. Returns `"N/A"` for non-finite or negative values, which occur during polar day or polar night when sunrise or sunset does not happen. Values at or above 24 hours wrap to the next day (e.g., 24.5 becomes `"00:30:00"`).
|
||||||
|
|
||||||
```js
|
```js
|
||||||
formatTime(6.5); // "06:30:00"
|
formatTime(6.5); // "06:30:00"
|
||||||
formatTime(12); // "12:00:00"
|
formatTime(12); // "12:00:00"
|
||||||
formatTime(Infinity); // "N/A"
|
formatTime(Infinity); // "N/A"
|
||||||
```
|
```
|
||||||
|
|
||||||
## `init()`
|
## `init()`
|
||||||
|
|
@ -116,12 +114,12 @@ Calling `init()` multiple times is safe. The second and subsequent calls return
|
||||||
|
|
||||||
The `function` option controls which outputs the SPA computes. Lower codes skip the rise/transit/set and incidence calculations, which are the most expensive part.
|
The `function` option controls which outputs the SPA computes. Lower codes skip the rise/transit/set and incidence calculations, which are the most expensive part.
|
||||||
|
|
||||||
| Constant | Value | Computes |
|
| Constant | Value | Computes |
|
||||||
| --- | --- | --- |
|
| ------------ | ----- | ------------------------------------------- |
|
||||||
| `SPA_ZA` | `0` | Zenith and azimuth only |
|
| `SPA_ZA` | `0` | Zenith and azimuth only |
|
||||||
| `SPA_ZA_INC` | `1` | Zenith, azimuth, and incidence angle |
|
| `SPA_ZA_INC` | `1` | Zenith, azimuth, and incidence angle |
|
||||||
| `SPA_ZA_RTS` | `2` | Zenith, azimuth, and rise/transit/set times |
|
| `SPA_ZA_RTS` | `2` | Zenith, azimuth, and rise/transit/set times |
|
||||||
| `SPA_ALL` | `3` | All output values (default) |
|
| `SPA_ALL` | `3` | All output values (default) |
|
||||||
|
|
||||||
```js
|
```js
|
||||||
import { spa, SPA_ZA } from 'solar-spa';
|
import { spa, SPA_ZA } from 'solar-spa';
|
||||||
|
|
|
||||||
|
|
@ -22,23 +22,23 @@ The C source is compiled with Emscripten to produce a single JavaScript file tha
|
||||||
|
|
||||||
### Build flags
|
### Build flags
|
||||||
|
|
||||||
| Flag | Purpose |
|
| Flag | Purpose |
|
||||||
| --- | --- |
|
| --------------------------------- | --------------------------------------------------------------------------------------------------------------------------------- |
|
||||||
| `-O3 -flto` | Maximum optimization with link-time optimization. The compiler inlines across translation units and eliminates dead code |
|
| `-O3 -flto` | Maximum optimization with link-time optimization. The compiler inlines across translation units and eliminates dead code |
|
||||||
| `--no-entry` | No `main()` function exists. The module exposes only the exported wrapper functions |
|
| `--no-entry` | No `main()` function exists. The module exposes only the exported wrapper functions |
|
||||||
| `-sSINGLE_FILE=1` | Inlines the WASM binary as a base64 string inside the JavaScript file. Eliminates the `.wasm` file entirely |
|
| `-sSINGLE_FILE=1` | Inlines the WASM binary as a base64 string inside the JavaScript file. Eliminates the `.wasm` file entirely |
|
||||||
| `-sMODULARIZE=1` | Wraps the output in a factory function (`createSpaModule()`) instead of executing immediately. Prevents global `Module` pollution |
|
| `-sMODULARIZE=1` | Wraps the output in a factory function (`createSpaModule()`) instead of executing immediately. Prevents global `Module` pollution |
|
||||||
| `-sEXPORT_NAME=createSpaModule` | Names the factory function |
|
| `-sEXPORT_NAME=createSpaModule` | Names the factory function |
|
||||||
| `-sEXPORTED_FUNCTIONS` | Exposes `_spa_calculate_wrapper`, `_spa_free_result`, `_malloc`, and `_free` to JavaScript |
|
| `-sEXPORTED_FUNCTIONS` | Exposes `_spa_calculate_wrapper`, `_spa_free_result`, `_malloc`, and `_free` to JavaScript |
|
||||||
| `-sEXPORTED_RUNTIME_METHODS` | Makes `cwrap` and `getValue` available on the module instance |
|
| `-sEXPORTED_RUNTIME_METHODS` | Makes `cwrap` and `getValue` available on the module instance |
|
||||||
| `-sNO_FILESYSTEM=1` | Excludes the virtual filesystem API. SPA does not read files. Saves ~15KB |
|
| `-sNO_FILESYSTEM=1` | Excludes the virtual filesystem API. SPA does not read files. Saves ~15KB |
|
||||||
| `-sINITIAL_MEMORY=1048576` | 1MB fixed memory. SPA allocates one 80-byte struct per call, so this is more than sufficient |
|
| `-sINITIAL_MEMORY=1048576` | 1MB fixed memory. SPA allocates one 80-byte struct per call, so this is more than sufficient |
|
||||||
| `-sALLOW_MEMORY_GROWTH=0` | Disables dynamic memory growth. Fixed memory avoids the overhead of growable ArrayBuffers and detached buffer checks |
|
| `-sALLOW_MEMORY_GROWTH=0` | Disables dynamic memory growth. Fixed memory avoids the overhead of growable ArrayBuffers and detached buffer checks |
|
||||||
| `-sSTACK_SIZE=65536` | 64KB stack. Default is 5MB, which is wasteful for a pure computation |
|
| `-sSTACK_SIZE=65536` | 64KB stack. Default is 5MB, which is wasteful for a pure computation |
|
||||||
| `-sENVIRONMENT='node,web,worker'` | Includes runtime support for Node.js, browsers, and web workers |
|
| `-sENVIRONMENT='node,web,worker'` | Includes runtime support for Node.js, browsers, and web workers |
|
||||||
| `-sASSERTIONS=0` | Removes debug assertions. Smaller output, no runtime checks |
|
| `-sASSERTIONS=0` | Removes debug assertions. Smaller output, no runtime checks |
|
||||||
| `-sDISABLE_EXCEPTION_CATCHING=1` | Disables C++ exception support. SPA is plain C, so this strips dead code |
|
| `-sDISABLE_EXCEPTION_CATCHING=1` | Disables C++ exception support. SPA is plain C, so this strips dead code |
|
||||||
| `-sWASM_BIGINT=0` | Disables BigInt integration for 64-bit integers. SPA uses only doubles and 32-bit ints |
|
| `-sWASM_BIGINT=0` | Disables BigInt integration for 64-bit integers. SPA uses only doubles and 32-bit ints |
|
||||||
|
|
||||||
The `SINGLE_FILE` flag is the critical one. Most WASM packages ship a separate `.wasm` file and resolve its path at runtime using `__dirname`, `import.meta.url`, or `URL` constructors. This breaks in bundlers (Webpack rewrites paths), edge runtimes (no filesystem), and testing environments (different module resolution). By inlining the binary, the module is self-contained. It works anywhere JavaScript runs.
|
The `SINGLE_FILE` flag is the critical one. Most WASM packages ship a separate `.wasm` file and resolve its path at runtime using `__dirname`, `import.meta.url`, or `URL` constructors. This breaks in bundlers (Webpack rewrites paths), edge runtimes (no filesystem), and testing environments (different module resolution). By inlining the binary, the module is self-contained. It works anywhere JavaScript runs.
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -28,16 +28,16 @@ For single calls, the difference is negligible. See [Performance](Performance) f
|
||||||
import { spa } from 'solar-spa';
|
import { spa } from 'solar-spa';
|
||||||
|
|
||||||
const result = await spa(
|
const result = await spa(
|
||||||
new Date(2025, 5, 21, 12, 0, 0), // June 21, 2025 at noon
|
new Date(2025, 5, 21, 12, 0, 0), // June 21, 2025 at noon
|
||||||
40.7128, // latitude (NYC)
|
40.7128, // latitude (NYC)
|
||||||
-74.0060, // longitude
|
-74.006, // longitude
|
||||||
{ timezone: -4, elevation: 10 } // EDT (UTC-4), 10m elevation
|
{ timezone: -4, elevation: 10 }, // EDT (UTC-4), 10m elevation
|
||||||
);
|
);
|
||||||
|
|
||||||
console.log(result.zenith); // ~27 (degrees from vertical)
|
console.log(result.zenith); // ~27 (degrees from vertical)
|
||||||
console.log(result.azimuth); // ~179 (degrees from north)
|
console.log(result.azimuth); // ~179 (degrees from north)
|
||||||
console.log(result.sunrise); // ~5.4 (fractional hours)
|
console.log(result.sunrise); // ~5.4 (fractional hours)
|
||||||
console.log(result.sunset); // ~20.5 (fractional hours)
|
console.log(result.sunset); // ~20.5 (fractional hours)
|
||||||
```
|
```
|
||||||
|
|
||||||
CommonJS works too:
|
CommonJS works too:
|
||||||
|
|
|
||||||
|
|
@ -80,25 +80,25 @@ The SPA's accuracy far exceeds the precision of any practical measurement system
|
||||||
|
|
||||||
The SPA validates all inputs and returns a non-zero error code if any are out of range:
|
The SPA validates all inputs and returns a non-zero error code if any are out of range:
|
||||||
|
|
||||||
| Parameter | Valid range |
|
| Parameter | Valid range |
|
||||||
| --- | --- |
|
| ---------------------- | --------------------------- |
|
||||||
| Year | -2000 to 6000 |
|
| Year | -2000 to 6000 |
|
||||||
| Month | 1 to 12 |
|
| Month | 1 to 12 |
|
||||||
| Day | 1 to 31 |
|
| Day | 1 to 31 |
|
||||||
| Hour | 0 to 24 |
|
| Hour | 0 to 24 |
|
||||||
| Minute | 0 to 59 |
|
| Minute | 0 to 59 |
|
||||||
| Second | 0 to less than 60 |
|
| Second | 0 to less than 60 |
|
||||||
| Timezone | -18 to 18 |
|
| Timezone | -18 to 18 |
|
||||||
| Latitude | -90 to 90 |
|
| Latitude | -90 to 90 |
|
||||||
| Longitude | -180 to 180 |
|
| Longitude | -180 to 180 |
|
||||||
| Elevation | -6500000 or higher (meters) |
|
| Elevation | -6500000 or higher (meters) |
|
||||||
| Pressure | 0 to 5000 |
|
| Pressure | 0 to 5000 |
|
||||||
| Temperature | -273 to 6000 |
|
| Temperature | -273 to 6000 |
|
||||||
| Delta UT1 | -1 to 1 |
|
| Delta UT1 | -1 to 1 |
|
||||||
| Delta T | -8000 to 8000 |
|
| Delta T | -8000 to 8000 |
|
||||||
| Slope | -360 to 360 |
|
| Slope | -360 to 360 |
|
||||||
| Azimuth rotation | -360 to 360 |
|
| Azimuth rotation | -360 to 360 |
|
||||||
| Atmospheric refraction | -5 to 5 |
|
| Atmospheric refraction | -5 to 5 |
|
||||||
|
|
||||||
The solar-spa package propagates these error codes as thrown JavaScript errors.
|
The solar-spa package propagates these error codes as thrown JavaScript errors.
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -26,7 +26,7 @@ Use `init()` at application startup to pay the initialization cost early:
|
||||||
|
|
||||||
```js
|
```js
|
||||||
import { init } from 'solar-spa';
|
import { init } from 'solar-spa';
|
||||||
await init(); // ~5-15ms, happens once
|
await init(); // ~5-15ms, happens once
|
||||||
```
|
```
|
||||||
|
|
||||||
## Memory footprint
|
## Memory footprint
|
||||||
|
|
@ -45,12 +45,12 @@ Memory growth is disabled (`ALLOW_MEMORY_GROWTH=0`). This means the ArrayBuffer
|
||||||
|
|
||||||
Not all callers need every output. The `function` option controls how much work the SPA does:
|
Not all callers need every output. The `function` option controls how much work the SPA does:
|
||||||
|
|
||||||
| Code | Computation | Relative cost |
|
| Code | Computation | Relative cost |
|
||||||
| --- | --- | --- |
|
| ---------------- | ------------------ | -------------------------------- |
|
||||||
| `SPA_ZA` (0) | Zenith and azimuth | ~1x |
|
| `SPA_ZA` (0) | Zenith and azimuth | ~1x |
|
||||||
| `SPA_ZA_INC` (1) | + incidence angle | ~1x (incidence is cheap) |
|
| `SPA_ZA_INC` (1) | + incidence angle | ~1x (incidence is cheap) |
|
||||||
| `SPA_ZA_RTS` (2) | + rise/transit/set | ~3x (three position evaluations) |
|
| `SPA_ZA_RTS` (2) | + rise/transit/set | ~3x (three position evaluations) |
|
||||||
| `SPA_ALL` (3) | All outputs | ~3x |
|
| `SPA_ALL` (3) | All outputs | ~3x |
|
||||||
|
|
||||||
The sunrise/sunset calculation is the expensive part. It evaluates the full position algorithm three times (for transit, sunrise, and sunset). If you only need the current sun position, use `SPA_ZA` for a roughly 3x speed improvement.
|
The sunrise/sunset calculation is the expensive part. It evaluates the full position algorithm three times (for transit, sunrise, and sunset). If you only need the current sun position, use `SPA_ZA` for a roughly 3x speed improvement.
|
||||||
|
|
||||||
|
|
@ -69,14 +69,14 @@ These flags together produce a ~60KB output file, down from the ~150KB that a de
|
||||||
|
|
||||||
## When to use solar-spa vs nrel-spa
|
## When to use solar-spa vs nrel-spa
|
||||||
|
|
||||||
| Scenario | Recommended |
|
| Scenario | Recommended |
|
||||||
| --- | --- |
|
| ------------------------------------------------------ | -------------------------------------------------------------------- |
|
||||||
| Single position lookup (e.g., sunrise for today) | Either. Both are fast enough |
|
| Single position lookup (e.g., sunrise for today) | Either. Both are fast enough |
|
||||||
| Batch computation (hundreds or thousands of positions) | solar-spa (WASM) |
|
| Batch computation (hundreds or thousands of positions) | solar-spa (WASM) |
|
||||||
| Animation or real-time tracking | solar-spa (WASM) |
|
| Animation or real-time tracking | solar-spa (WASM) |
|
||||||
| Synchronous API required | [nrel-spa](https://github.com/acamarata/nrel-spa) (pure JS, sync) |
|
| Synchronous API required | [nrel-spa](https://github.com/acamarata/nrel-spa) (pure JS, sync) |
|
||||||
| Environments without WASM support | [nrel-spa](https://github.com/acamarata/nrel-spa) |
|
| Environments without WASM support | [nrel-spa](https://github.com/acamarata/nrel-spa) |
|
||||||
| Minimal dependency footprint | [nrel-spa](https://github.com/acamarata/nrel-spa) (zero deps, ~30KB) |
|
| Minimal dependency footprint | [nrel-spa](https://github.com/acamarata/nrel-spa) (zero deps, ~30KB) |
|
||||||
|
|
||||||
Both packages implement the same NREL algorithm and produce identical results within floating-point rounding tolerance.
|
Both packages implement the same NREL algorithm and produce identical results within floating-point rounding tolerance.
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -6,15 +6,15 @@ Pre-release validation of the solar-spa v2.0.0 WASM implementation. All results
|
||||||
|
|
||||||
100 scenarios covering seven categories:
|
100 scenarios covering seven categories:
|
||||||
|
|
||||||
| Category | Scenarios | Description |
|
| Category | Scenarios | Description |
|
||||||
| --- | --- | --- |
|
| ------------------------- | --------- | --------------------------------------------------------------- |
|
||||||
| Cities worldwide | 1-40 | 20 cities across every continent, summer and winter solstice |
|
| Cities worldwide | 1-40 | 20 cities across every continent, summer and winter solstice |
|
||||||
| Boundary conditions | 41-55 | Poles, equator, date line, extreme elevation, date range limits |
|
| Boundary conditions | 41-55 | Poles, equator, date line, extreme elevation, date range limits |
|
||||||
| Polar regions | 56-65 | Polar day, polar night, midnight sun, Antarctic stations |
|
| Polar regions | 56-65 | Polar day, polar night, midnight sun, Antarctic stations |
|
||||||
| Time edge cases | 66-75 | Midnight, dawn, dusk, leap year, fractional seconds |
|
| Time edge cases | 66-75 | Midnight, dawn, dusk, leap year, fractional seconds |
|
||||||
| Function code consistency | 76-80 | All four function codes produce identical zenith/azimuth |
|
| Function code consistency | 76-80 | All four function codes produce identical zenith/azimuth |
|
||||||
| Atmospheric conditions | 81-90 | Pressure, temperature, refraction, vacuum, high altitude |
|
| Atmospheric conditions | 81-90 | Pressure, temperature, refraction, vacuum, high altitude |
|
||||||
| Historical/future dates | 91-100 | Year -2000 to 6000, Gregorian switch, Apollo era |
|
| Historical/future dates | 91-100 | Year -2000 to 6000, Gregorian switch, Apollo era |
|
||||||
|
|
||||||
**Result: 100/100 passed.**
|
**Result: 100/100 passed.**
|
||||||
|
|
||||||
|
|
@ -22,48 +22,48 @@ Pre-release validation of the solar-spa v2.0.0 WASM implementation. All results
|
||||||
|
|
||||||
20 major cities tested at both the June 21 and December 21 solstices, 2025, local noon. Each scenario validates that the zenith angle falls within a physically reasonable range for the latitude and season.
|
20 major cities tested at both the June 21 and December 21 solstices, 2025, local noon. Each scenario validates that the zenith angle falls within a physically reasonable range for the latitude and season.
|
||||||
|
|
||||||
| # | City | Season | Zenith | Azimuth | Time |
|
| # | City | Season | Zenith | Azimuth | Time |
|
||||||
| --- | --- | --- | --- | --- | --- |
|
| --- | ------------ | ------ | ------ | ------- | ----- |
|
||||||
| 1 | New York | Summer | 21.12 | 140.47 | 242us |
|
| 1 | New York | Summer | 21.12 | 140.47 | 242us |
|
||||||
| 2 | New York | Winter | 65.35 | 166.30 | 168us |
|
| 2 | New York | Winter | 65.35 | 166.30 | 168us |
|
||||||
| 3 | London | Summer | 30.52 | 150.96 | 110us |
|
| 3 | London | Summer | 30.52 | 150.96 | 110us |
|
||||||
| 4 | London | Winter | 75.98 | 166.15 | 110us |
|
| 4 | London | Winter | 75.98 | 166.15 | 110us |
|
||||||
| 5 | Tokyo | Summer | 12.77 | 197.73 | 102us |
|
| 5 | Tokyo | Summer | 12.77 | 197.73 | 102us |
|
||||||
| 6 | Tokyo | Winter | 59.29 | 185.50 | 99us |
|
| 6 | Tokyo | Winter | 59.29 | 185.50 | 99us |
|
||||||
| 7 | Sydney | Summer | 57.29 | 359.16 | 100us |
|
| 7 | Sydney | Summer | 57.29 | 359.16 | 100us |
|
||||||
| 8 | Sydney | Winter | 10.54 | 351.37 | 112us |
|
| 8 | Sydney | Winter | 10.54 | 351.37 | 112us |
|
||||||
| 9 | Cairo | Summer | 6.64 | 186.17 | 115us |
|
| 9 | Cairo | Summer | 6.64 | 186.17 | 115us |
|
||||||
| 10 | Cairo | Winter | 53.49 | 181.94 | 101us |
|
| 10 | Cairo | Winter | 53.49 | 181.94 | 101us |
|
||||||
| 11 | Mumbai | Summer | 10.35 | 63.31 | 109us |
|
| 11 | Mumbai | Summer | 10.35 | 63.31 | 109us |
|
||||||
| 12 | Mumbai | Winter | 43.43 | 167.76 | 96us |
|
| 12 | Mumbai | Winter | 43.43 | 167.76 | 96us |
|
||||||
| 13 | Sao Paulo | Summer | 47.02 | 2.64 | 94us |
|
| 13 | Sao Paulo | Summer | 47.02 | 2.64 | 94us |
|
||||||
| 14 | Sao Paulo | Winter | 1.10 | 84.39 | 137us |
|
| 14 | Sao Paulo | Winter | 1.10 | 84.39 | 137us |
|
||||||
| 15 | Moscow | Summer | 32.82 | 166.65 | 71us |
|
| 15 | Moscow | Summer | 32.82 | 166.65 | 71us |
|
||||||
| 16 | Moscow | Winter | 79.33 | 173.55 | 56us |
|
| 16 | Moscow | Winter | 79.33 | 173.55 | 56us |
|
||||||
| 17 | Beijing | Summer | 16.81 | 167.09 | 54us |
|
| 17 | Beijing | Summer | 16.81 | 167.09 | 54us |
|
||||||
| 18 | Beijing | Winter | 63.38 | 176.82 | 50us |
|
| 18 | Beijing | Winter | 63.38 | 176.82 | 50us |
|
||||||
| 19 | Nairobi | Summer | 26.11 | 18.24 | 56us |
|
| 19 | Nairobi | Summer | 26.11 | 18.24 | 56us |
|
||||||
| 20 | Nairobi | Winter | 23.37 | 161.93 | 55us |
|
| 20 | Nairobi | Winter | 23.37 | 161.93 | 55us |
|
||||||
| 21 | Reykjavik | Summer | 43.28 | 149.34 | 49us |
|
| 21 | Reykjavik | Summer | 43.28 | 149.34 | 49us |
|
||||||
| 22 | Reykjavik | Winter | 88.81 | 160.36 | 47us |
|
| 22 | Reykjavik | Winter | 88.81 | 160.36 | 47us |
|
||||||
| 23 | Singapore | Summer | 27.34 | 34.86 | 34us |
|
| 23 | Singapore | Summer | 27.34 | 34.86 | 34us |
|
||||||
| 24 | Singapore | Winter | 29.10 | 149.34 | 25us |
|
| 24 | Singapore | Winter | 29.10 | 149.34 | 25us |
|
||||||
| 25 | Cape Town | Summer | 58.47 | 12.97 | 22us |
|
| 25 | Cape Town | Summer | 58.47 | 12.97 | 22us |
|
||||||
| 26 | Cape Town | Winter | 14.29 | 45.72 | 22us |
|
| 26 | Cape Town | Winter | 14.29 | 45.72 | 22us |
|
||||||
| 27 | Buenos Aires | Summer | 59.49 | 14.77 | 22us |
|
| 27 | Buenos Aires | Summer | 59.49 | 14.77 | 22us |
|
||||||
| 28 | Buenos Aires | Winter | 15.87 | 48.72 | 21us |
|
| 28 | Buenos Aires | Winter | 15.87 | 48.72 | 21us |
|
||||||
| 29 | Dubai | Summer | 5.04 | 109.42 | 22us |
|
| 29 | Dubai | Summer | 5.04 | 109.42 | 22us |
|
||||||
| 30 | Dubai | Winter | 48.80 | 174.81 | 25us |
|
| 30 | Dubai | Winter | 48.80 | 174.81 | 25us |
|
||||||
| 31 | Toronto | Summer | 25.98 | 134.65 | 22us |
|
| 31 | Toronto | Summer | 25.98 | 134.65 | 22us |
|
||||||
| 32 | Toronto | Winter | 69.27 | 161.43 | 24us |
|
| 32 | Toronto | Winter | 69.27 | 161.43 | 24us |
|
||||||
| 33 | Mexico City | Summer | 9.80 | 64.18 | 23us |
|
| 33 | Mexico City | Summer | 9.80 | 64.18 | 23us |
|
||||||
| 34 | Mexico City | Winter | 43.69 | 168.40 | 23us |
|
| 34 | Mexico City | Winter | 43.69 | 168.40 | 23us |
|
||||||
| 35 | Seoul | Summer | 15.88 | 150.42 | 46us |
|
| 35 | Seoul | Summer | 15.88 | 150.42 | 46us |
|
||||||
| 36 | Seoul | Winter | 61.38 | 172.14 | 31us |
|
| 36 | Seoul | Winter | 61.38 | 172.14 | 31us |
|
||||||
| 37 | Rome | Summer | 23.76 | 135.39 | 26us |
|
| 37 | Rome | Summer | 23.76 | 135.39 | 26us |
|
||||||
| 38 | Rome | Winter | 67.18 | 163.05 | 24us |
|
| 38 | Rome | Winter | 67.18 | 163.05 | 24us |
|
||||||
| 39 | Anchorage | Summer | 43.13 | 137.26 | 25us |
|
| 39 | Anchorage | Summer | 43.13 | 137.26 | 25us |
|
||||||
| 40 | Anchorage | Winter | 87.67 | 153.13 | 23us |
|
| 40 | Anchorage | Winter | 87.67 | 153.13 | 23us |
|
||||||
|
|
||||||
Note: "Summer" and "Winter" refer to Northern Hemisphere seasons. For Southern Hemisphere cities (Sydney, Sao Paulo, Cape Town, Buenos Aires, Nairobi), the seasons are reversed. A high zenith in "summer" (June) for Sydney is correct because June is winter there.
|
Note: "Summer" and "Winter" refer to Northern Hemisphere seasons. For Southern Hemisphere cities (Sydney, Sao Paulo, Cape Town, Buenos Aires, Nairobi), the seasons are reversed. A high zenith in "summer" (June) for Sydney is correct because June is winter there.
|
||||||
|
|
||||||
|
|
@ -71,23 +71,23 @@ Note: "Summer" and "Winter" refer to Northern Hemisphere seasons. For Southern H
|
||||||
|
|
||||||
Tests at the mathematical limits of the algorithm's input domain.
|
Tests at the mathematical limits of the algorithm's input domain.
|
||||||
|
|
||||||
| # | Scenario | Zenith | Note |
|
| # | Scenario | Zenith | Note |
|
||||||
| --- | --- | --- | --- |
|
| --- | ------------------------- | ------ | ----------------------------------- |
|
||||||
| 41 | North Pole, June solstice | 66.53 | Midnight sun: zenith < 90 |
|
| 41 | North Pole, June solstice | 66.53 | Midnight sun: zenith < 90 |
|
||||||
| 42 | North Pole, Dec solstice | 113.44 | Polar night: zenith > 90 |
|
| 42 | North Pole, Dec solstice | 113.44 | Polar night: zenith > 90 |
|
||||||
| 43 | South Pole, Dec solstice | 66.53 | Midnight sun (southern summer) |
|
| 43 | South Pole, Dec solstice | 66.53 | Midnight sun (southern summer) |
|
||||||
| 44 | South Pole, June solstice | 113.44 | Polar night (southern winter) |
|
| 44 | South Pole, June solstice | 113.44 | Polar night (southern winter) |
|
||||||
| 45 | Equator, March equinox | 1.84 | Near-overhead sun |
|
| 45 | Equator, March equinox | 1.84 | Near-overhead sun |
|
||||||
| 46 | Equator, Sept equinox | 1.84 | Near-overhead sun |
|
| 46 | Equator, Sept equinox | 1.84 | Near-overhead sun |
|
||||||
| 47 | Equator, June solstice | 23.44 | Sun 23.44 north of equator |
|
| 47 | Equator, June solstice | 23.44 | Sun 23.44 north of equator |
|
||||||
| 48 | Equator, Dec solstice | 23.44 | Sun 23.44 south of equator |
|
| 48 | Equator, Dec solstice | 23.44 | Sun 23.44 south of equator |
|
||||||
| 49 | Date line +180 | 23.44 | Longitude boundary |
|
| 49 | Date line +180 | 23.44 | Longitude boundary |
|
||||||
| 50 | Date line -180 | 23.43 | Longitude boundary |
|
| 50 | Date line -180 | 23.43 | Longitude boundary |
|
||||||
| 51 | Mt Everest (8849m) | 4.55 | Thin atmosphere (314 mbar, -20C) |
|
| 51 | Mt Everest (8849m) | 4.55 | Thin atmosphere (314 mbar, -20C) |
|
||||||
| 52 | Dead Sea (-430m) | 11.95 | Dense atmosphere (1065 mbar, 40C) |
|
| 52 | Dead Sea (-430m) | 11.95 | Dense atmosphere (1065 mbar, 40C) |
|
||||||
| 53 | Year -2000 | 7.90 | Earliest valid date |
|
| 53 | Year -2000 | 7.90 | Earliest valid date |
|
||||||
| 54 | Year 6000 | 7.27 | Latest valid date |
|
| 54 | Year 6000 | 7.27 | Latest valid date |
|
||||||
| 55 | Year 6001 | throws | Correctly rejects out-of-range year |
|
| 55 | Year 6001 | throws | Correctly rejects out-of-range year |
|
||||||
|
|
||||||
The equinox results confirm the algorithm's accuracy: a zenith of 1.84 degrees at the equator on the March equinox at solar noon on the prime meridian is consistent with the small angular offset between the vernal equinox and the actual date (March 20 vs. the instant the sun crosses the celestial equator).
|
The equinox results confirm the algorithm's accuracy: a zenith of 1.84 degrees at the equator on the March equinox at solar noon on the prime meridian is consistent with the small angular offset between the vernal equinox and the actual date (March 20 vs. the instant the sun crosses the celestial equator).
|
||||||
|
|
||||||
|
|
@ -95,62 +95,62 @@ The equinox results confirm the algorithm's accuracy: a zenith of 1.84 degrees a
|
||||||
|
|
||||||
Polar day/night conditions test the algorithm's handling of non-standard sunrise/sunset scenarios.
|
Polar day/night conditions test the algorithm's handling of non-standard sunrise/sunset scenarios.
|
||||||
|
|
||||||
| # | Location | Condition | Zenith |
|
| # | Location | Condition | Zenith |
|
||||||
| --- | --- | --- | --- |
|
| --- | ------------------------- | -------------------------- | ------ |
|
||||||
| 56 | Tromso, Norway (69.6N) | Polar day (June) | 46.70 |
|
| 56 | Tromso, Norway (69.6N) | Polar day (June) | 46.70 |
|
||||||
| 57 | Tromso, Norway | Polar night (Dec) | 93.14 |
|
| 57 | Tromso, Norway | Polar night (Dec) | 93.14 |
|
||||||
| 58 | Murmansk, Russia (69.0N) | Polar day (June) | 46.12 |
|
| 58 | Murmansk, Russia (69.0N) | Polar day (June) | 46.12 |
|
||||||
| 59 | Murmansk, Russia | Polar night (Dec) | 92.77 |
|
| 59 | Murmansk, Russia | Polar night (Dec) | 92.77 |
|
||||||
| 60 | Utqiagvik, AK (71.3N) | Polar day (June) | 52.32 |
|
| 60 | Utqiagvik, AK (71.3N) | Polar day (June) | 52.32 |
|
||||||
| 61 | Utqiagvik, AK | Polar night (Dec) | 95.90 |
|
| 61 | Utqiagvik, AK | Polar night (Dec) | 95.90 |
|
||||||
| 62 | McMurdo Station (-77.9S) | Summer (Dec) | 55.95 |
|
| 62 | McMurdo Station (-77.9S) | Summer (Dec) | 55.95 |
|
||||||
| 63 | McMurdo Station | Winter (June) | 101.62 |
|
| 63 | McMurdo Station | Winter (June) | 101.62 |
|
||||||
| 64 | Svalbard (78.2N) | Midnight sun (June, 00:00) | 77.90 |
|
| 64 | Svalbard (78.2N) | Midnight sun (June, 00:00) | 77.90 |
|
||||||
| 65 | South Pole Station (-90S) | Summer (Jan) | 67.01 |
|
| 65 | South Pole Station (-90S) | Summer (Jan) | 67.01 |
|
||||||
|
|
||||||
Scenario 64 is notable: at Svalbard at midnight on the June solstice, the sun is still 12.1 degrees above the horizon (90 - 77.9 = 12.1). This is correct for 78N latitude during continuous polar daylight.
|
Scenario 64 is notable: at Svalbard at midnight on the June solstice, the sun is still 12.1 degrees above the horizon (90 - 77.9 = 12.1). This is correct for 78N latitude during continuous polar daylight.
|
||||||
|
|
||||||
## Category 4: Time Edge Cases (66-75)
|
## Category 4: Time Edge Cases (66-75)
|
||||||
|
|
||||||
| # | Scenario | Zenith | Note |
|
| # | Scenario | Zenith | Note |
|
||||||
| --- | --- | --- | --- |
|
| --- | --------------------------------- | ------ | -------------------------------- |
|
||||||
| 66 | Exact midnight UTC (London, June) | 105.05 | Sun well below horizon |
|
| 66 | Exact midnight UTC (London, June) | 105.05 | Sun well below horizon |
|
||||||
| 67 | Dawn, 5 AM summer London | 88.47 | Near horizon |
|
| 67 | Dawn, 5 AM summer London | 88.47 | Near horizon |
|
||||||
| 68 | Dusk, 9 PM summer London | 87.93 | Near horizon |
|
| 68 | Dusk, 9 PM summer London | 87.93 | Near horizon |
|
||||||
| 69 | Solar noon NYC (13:00 EDT) | 17.28 | Azimuth 181.6 (nearly due south) |
|
| 69 | Solar noon NYC (13:00 EDT) | 17.28 | Azimuth 181.6 (nearly due south) |
|
||||||
| 70 | UTC midnight Jan 1, equator | 156.99 | Deep below horizon |
|
| 70 | UTC midnight Jan 1, equator | 156.99 | Deep below horizon |
|
||||||
| 71 | Fractional seconds | 18.24 | Handles sub-minute times |
|
| 71 | Fractional seconds | 18.24 | Handles sub-minute times |
|
||||||
| 72 | End of day 23:59 | 114.40 | Late night |
|
| 72 | End of day 23:59 | 114.40 | Late night |
|
||||||
| 73 | Feb 29 leap year (2024) | 48.33 | Leap day handled correctly |
|
| 73 | Feb 29 leap year (2024) | 48.33 | Leap day handled correctly |
|
||||||
| 74 | Prime meridian equator noon | 1.84 | Most symmetric case |
|
| 74 | Prime meridian equator noon | 1.84 | Most symmetric case |
|
||||||
| 75 | New Year's Eve midnight | 162.37 | Deep below horizon |
|
| 75 | New Year's Eve midnight | 162.37 | Deep below horizon |
|
||||||
|
|
||||||
## Category 5: Function Code Consistency (76-80)
|
## Category 5: Function Code Consistency (76-80)
|
||||||
|
|
||||||
All four function codes (`SPA_ZA`, `SPA_ZA_INC`, `SPA_ZA_RTS`, `SPA_ALL`) produce identical zenith and azimuth values within 0.01 degree tolerance. This confirms that the function code parameter only affects which outputs are computed, not the core position algorithm.
|
All four function codes (`SPA_ZA`, `SPA_ZA_INC`, `SPA_ZA_RTS`, `SPA_ALL`) produce identical zenith and azimuth values within 0.01 degree tolerance. This confirms that the function code parameter only affects which outputs are computed, not the core position algorithm.
|
||||||
|
|
||||||
| # | Test | Result |
|
| # | Test | Result |
|
||||||
| --- | --- | --- |
|
| --- | ------------------------------------- | ------------------------------------- |
|
||||||
| 76 | SPA_ZA matches SPA_ALL | zenith identical |
|
| 76 | SPA_ZA matches SPA_ALL | zenith identical |
|
||||||
| 77 | SPA_ZA_INC matches SPA_ALL | zenith, azimuth, incidence identical |
|
| 77 | SPA_ZA_INC matches SPA_ALL | zenith, azimuth, incidence identical |
|
||||||
| 78 | SPA_ZA_RTS matches SPA_ALL | zenith, azimuth identical |
|
| 78 | SPA_ZA_RTS matches SPA_ALL | zenith, azimuth identical |
|
||||||
| 79 | SPA_ALL fields all finite | All 9 numeric fields populated |
|
| 79 | SPA_ALL fields all finite | All 9 numeric fields populated |
|
||||||
| 80 | azimuth = (azimuth_astro + 180) % 360 | Navigational/astronomical consistency |
|
| 80 | azimuth = (azimuth_astro + 180) % 360 | Navigational/astronomical consistency |
|
||||||
|
|
||||||
## Category 6: Atmospheric Conditions (81-90)
|
## Category 6: Atmospheric Conditions (81-90)
|
||||||
|
|
||||||
| # | Condition | Zenith | Note |
|
| # | Condition | Zenith | Note |
|
||||||
| --- | --- | --- | --- |
|
| --- | --------------------------------------- | ------ | ------------------------------ |
|
||||||
| 81 | Standard atmosphere (1013.25 mbar, 15C) | 21.12 | Reference baseline |
|
| 81 | Standard atmosphere (1013.25 mbar, 15C) | 21.12 | Reference baseline |
|
||||||
| 82 | Low pressure (300 mbar, -30C, 9000m) | 21.12 | High altitude conditions |
|
| 82 | Low pressure (300 mbar, -30C, 9000m) | 21.12 | High altitude conditions |
|
||||||
| 83 | High pressure (1100 mbar) | 21.12 | Dense atmosphere |
|
| 83 | High pressure (1100 mbar) | 21.12 | Dense atmosphere |
|
||||||
| 84 | Extreme cold (-40C) | 43.28 | Reykjavik test |
|
| 84 | Extreme cold (-40C) | 43.28 | Reykjavik test |
|
||||||
| 85 | Extreme heat (+50C) | 5.04 | Dubai test |
|
| 85 | Extreme heat (+50C) | 5.04 | Dubai test |
|
||||||
| 86 | Zero pressure (vacuum) | 21.13 | No refraction correction |
|
| 86 | Zero pressure (vacuum) | 21.13 | No refraction correction |
|
||||||
| 87 | Custom refraction (0 deg) | 21.12 | Override default 0.5667 |
|
| 87 | Custom refraction (0 deg) | 21.12 | Override default 0.5667 |
|
||||||
| 88 | Custom refraction (2 deg) | 21.12 | Large refraction override |
|
| 88 | Custom refraction (2 deg) | 21.12 | Large refraction override |
|
||||||
| 89 | Pressure effect on zenith | varies | Low != high pressure confirmed |
|
| 89 | Pressure effect on zenith | varies | Low != high pressure confirmed |
|
||||||
| 90 | High elevation + low pressure | 4.55 | Everest base camp |
|
| 90 | High elevation + low pressure | 4.55 | Everest base camp |
|
||||||
|
|
||||||
Scenario 89 confirms that different atmospheric pressures produce measurably different zenith values. The difference is small (sub-arc-second at high solar elevations) but present, which validates that the atmospheric refraction correction is active and working.
|
Scenario 89 confirms that different atmospheric pressures produce measurably different zenith values. The difference is small (sub-arc-second at high solar elevations) but present, which validates that the atmospheric refraction correction is active and working.
|
||||||
|
|
||||||
|
|
@ -158,18 +158,18 @@ Scenario 89 confirms that different atmospheric pressures produce measurably dif
|
||||||
|
|
||||||
The SPA is valid for years -2000 to 6000. These scenarios confirm correct behavior across the full range, with era-appropriate delta_t values.
|
The SPA is valid for years -2000 to 6000. These scenarios confirm correct behavior across the full range, with era-appropriate delta_t values.
|
||||||
|
|
||||||
| # | Year | Context | Zenith | delta_t |
|
| # | Year | Context | Zenith | delta_t |
|
||||||
| --- | --- | --- | --- | --- |
|
| --- | ---------------------- | ------------------------------ | ------ | ------- |
|
||||||
| 91 | 1000 CE | Medieval era | 17.25 | 1574s |
|
| 91 | 1000 CE | Medieval era | 17.25 | 1574s |
|
||||||
| 92 | 1582 | Gregorian calendar switch | 50.37 | 120s |
|
| 92 | 1582 | Gregorian calendar switch | 50.37 | 120s |
|
||||||
| 93 | 1900 | Turn of century | 25.45 | -3s |
|
| 93 | 1900 | Turn of century | 25.45 | -3s |
|
||||||
| 94 | 1969 | Apollo 11 era, Cape Canaveral | 10.31 | 40s |
|
| 94 | 1969 | Apollo 11 era, Cape Canaveral | 10.31 | 40s |
|
||||||
| 95 | 2050 | Near future | 21.13 | 93s |
|
| 95 | 2050 | Near future | 21.13 | 93s |
|
||||||
| 96 | 2100 | Far future | 74.88 | 200s |
|
| 96 | 2100 | Far future | 74.88 | 200s |
|
||||||
| 97 | 3000 | Distant future | 12.77 | 0s |
|
| 97 | 3000 | Distant future | 12.77 | 0s |
|
||||||
| 98 | 5000 | Deep future | 0.67 | 0s |
|
| 98 | 5000 | Deep future | 0.67 | 0s |
|
||||||
| 99 | -1000 (1001 BCE) | Ancient Athens | 15.07 | 0s |
|
| 99 | -1000 (1001 BCE) | Ancient Athens | 15.07 | 0s |
|
||||||
| 100 | -2000 (earliest valid) | Ancient Cairo, winter solstice | 53.00 | 0s |
|
| 100 | -2000 (earliest valid) | Ancient Cairo, winter solstice | 53.00 | 0s |
|
||||||
|
|
||||||
Delta_t values for historical dates follow published estimates. For dates beyond ~2050, delta_t is not well predicted. The scenarios use conservative values to avoid introducing error from the correction itself.
|
Delta_t values for historical dates follow published estimates. For dates beyond ~2050, delta_t is not well predicted. The scenarios use conservative values to avoid introducing error from the correction itself.
|
||||||
|
|
||||||
|
|
@ -182,13 +182,13 @@ Measured on Apple Silicon (Node.js), single-threaded.
|
||||||
From the 100 validation scenarios:
|
From the 100 validation scenarios:
|
||||||
|
|
||||||
| Metric | Value |
|
| Metric | Value |
|
||||||
| --- | --- |
|
| ------ | ----- |
|
||||||
| Min | 7us |
|
| Min | 7us |
|
||||||
| Max | 242us |
|
| Max | 242us |
|
||||||
| Mean | 46us |
|
| Mean | 46us |
|
||||||
| Median | 33us |
|
| Median | 33us |
|
||||||
| P95 | 110us |
|
| P95 | 110us |
|
||||||
| P99 | 168us |
|
| P99 | 168us |
|
||||||
|
|
||||||
The first call is slowest (242us) because it includes WASM module initialization. Subsequent calls settle into the 20-40us range for `SPA_ALL` computations.
|
The first call is slowest (242us) because it includes WASM module initialization. Subsequent calls settle into the 20-40us range for `SPA_ALL` computations.
|
||||||
|
|
||||||
|
|
@ -196,10 +196,10 @@ The first call is slowest (242us) because it includes WASM module initialization
|
||||||
|
|
||||||
10,000 consecutive calls to the same location and date:
|
10,000 consecutive calls to the same location and date:
|
||||||
|
|
||||||
| Function Code | Time | Throughput |
|
| Function Code | Time | Throughput |
|
||||||
| --- | --- | --- |
|
| ------------- | ----- | ------------------ |
|
||||||
| SPA_ALL | 201ms | ~50,000 calls/sec |
|
| SPA_ALL | 201ms | ~50,000 calls/sec |
|
||||||
| SPA_ZA | 46ms | ~219,000 calls/sec |
|
| SPA_ZA | 46ms | ~219,000 calls/sec |
|
||||||
|
|
||||||
`SPA_ZA` is roughly 4x faster than `SPA_ALL` because it skips the sunrise/sunset iterative solver, which requires three full position evaluations per call.
|
`SPA_ZA` is roughly 4x faster than `SPA_ALL` because it skips the sunrise/sunset iterative solver, which requires three full position evaluations per call.
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -40,7 +40,7 @@ Emscripten supports a `locateFile` callback that lets the consumer specify where
|
||||||
|
|
||||||
```js
|
```js
|
||||||
const Module = await createModule({
|
const Module = await createModule({
|
||||||
locateFile: (path) => '/static/wasm/' + path
|
locateFile: (path) => '/static/wasm/' + path,
|
||||||
});
|
});
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
@ -54,10 +54,8 @@ Webpack can be configured to copy `.wasm` files to the output directory and rewr
|
||||||
// webpack.config.js
|
// webpack.config.js
|
||||||
module.exports = {
|
module.exports = {
|
||||||
module: {
|
module: {
|
||||||
rules: [
|
rules: [{ test: /\.wasm$/, type: 'asset/resource' }],
|
||||||
{ test: /\.wasm$/, type: 'asset/resource' }
|
},
|
||||||
]
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
@ -90,13 +88,15 @@ let _pending: Promise<void> | null = null;
|
||||||
export function init(): Promise<void> {
|
export function init(): Promise<void> {
|
||||||
if (_module) return Promise.resolve();
|
if (_module) return Promise.resolve();
|
||||||
if (_pending) return _pending;
|
if (_pending) return _pending;
|
||||||
_pending = createSpaModule().then((mod) => {
|
_pending = createSpaModule()
|
||||||
_module = mod;
|
.then((mod) => {
|
||||||
_pending = null;
|
_module = mod;
|
||||||
}).catch((err) => {
|
_pending = null;
|
||||||
_pending = null; // Allow retry on next call
|
})
|
||||||
throw err;
|
.catch((err) => {
|
||||||
});
|
_pending = null; // Allow retry on next call
|
||||||
|
throw err;
|
||||||
|
});
|
||||||
return _pending;
|
return _pending;
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
@ -117,13 +117,13 @@ For small to medium WASM binaries (under a few hundred KB), inlining as base64 i
|
||||||
|
|
||||||
## Summary
|
## Summary
|
||||||
|
|
||||||
| Approach | Universal? | Consumer config? | Size overhead |
|
| Approach | Universal? | Consumer config? | Size overhead |
|
||||||
| --- | --- | --- | --- |
|
| ------------------------------------- | ----------- | ----------------- | ------------- |
|
||||||
| Separate `.wasm` + default resolution | No | No | None |
|
| Separate `.wasm` + default resolution | No | No | None |
|
||||||
| `locateFile` callback | Yes* | Yes (per-bundler) | None |
|
| `locateFile` callback | Yes\* | Yes (per-bundler) | None |
|
||||||
| Bundler-specific config | Per-bundler | Yes | None |
|
| Bundler-specific config | Per-bundler | Yes | None |
|
||||||
| `import.meta.url` | Partial | No | None |
|
| `import.meta.url` | Partial | No | None |
|
||||||
| **SINGLE_FILE (base64 inline)** | **Yes** | **No** | **~33%** |
|
| **SINGLE_FILE (base64 inline)** | **Yes** | **No** | **~33%** |
|
||||||
|
|
||||||
solar-spa uses the last approach. It works in every tested environment without any consumer configuration.
|
solar-spa uses the last approach. It works in every tested environment without any consumer configuration.
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue