Astrology Engine

Measure the approximation error

A curve can look smooth and still approximate its input poorly. Before writing a dataset, the builder compares each fitted curve with its angular sampling function. It also reports how adjoining curves meet. We will calculate both measurements and follow the retry ladder without turning a sampled fit difference into a claim of astronomical truth.

Before this lesson

Read “Compress the angular samples.” You need the time map to [−1, +1], coefficient evaluation and the longitude seam. One degree contains 3600 arcseconds. All numerical comparisons here use invented inputs.

Read the preceding lesson.

What you will learn

Calculate scalar and circular residuals, measure seam jumps, and decide which ladder attempt the current builder accepts.

Dotted-underlined terms open a definition beside the text. Select one to read more, then close it to continue.

Each step has its own check. Pass every step to complete the lesson. Your answers and checked steps are saved in this browser, so you can continue after leaving or reloading.

1. Evaluate angular and scalar residuals

After fitting, ask a concrete question: how far is the stored curve from the function that supplied its angles? The difference at a tested time is a residual. We will measure its size, then keep the largest size found across each segment and the series.

Suppose an invented source longitude is 359.99999° and the approximation is 0.00001°. Direct subtraction gives −359.99998°, but those directions are only 0.00002° apart across zero. Multiplying by 3600 converts this short distance to 0.072 arcsecond. For source declination −12° and approximation −11.99998°, ordinary subtraction and absolute value also give 0.00002°, or 0.072 arcsecond. These are differences between individual coordinates, not a 3D vector separation.

Declination uses Absolute value The unsigned size of a number. Vertical bars mark this operation: |−0.00002| = 0.00002. It measures the size of a scalar difference without keeping its direction. : discard the sign of p − f, where p is the prediction and f is the supplied angle. Longitude requires the shorter distance around a circle. Reduce p − f into [0, 360), call that result r, and use 360 − r if r exceeds 180. In either case the residual is unsigned.

scalar residual = |p − f| × 3600 arcsec

longitude residual = min(r, 360 − r) × 3600 arcsec, r = (p − f) modulo 360

The builder checks 60 evenly spaced times per segment, including both endpoints. For an interval from 0 to 118 seconds, 60 points create 59 gaps, each 118/59 = 2 seconds long. More generally, point i is placed as follows, for i = 0 through 59.

tᵢ = lo + (hi − lo)i/59, i = 0…59

At each time, evaluate the source function f(t) and the fitted polynomial p(x), using x = 2(t − lo)/(hi − lo) − 1. The implementation uses Clenshaw’s recurrence to evaluate the coefficients; a later runtime lesson develops that calculation. Keep the largest converted residual over the 60 points, then the largest over all segments. Fitting minimized a sum of squares on its cosine grid; this measurement asks for a largest absolute difference on a different grid.

See the teaching TypeScript
const circularResidualArcsec = (approx: number, source: number): number => {
  const r = ((approx - source) % 360 + 360) % 360;
  return Math.min(r, 360 - r) * 3600;
};
const scalarResidualArcsec = (approx: number, source: number): number =>
  Math.abs(approx - source) * 3600;

Finite, correctly labeled inputs are assumed. This demonstrates the arithmetic; it does not fetch data or replace the engine.

Connect this step to the source

tools/dataset-builder/src/cheb/fit.rs

max_residual_arcsec; wrapped_abs_deg

Paths refer to the astrology-engine repository. Examples use invented inputs; a successful exercise is not an astronomical-accuracy test.

Sources for this section

Apply this step

Answer every part, then check. You can retry as often as you like.

Enter a number in arcseconds; absolute tolerance ±0.000001. Accepted tolerance: ±0.000001 arcseconds. Omit units and commas.

Enter a number in arcseconds; absolute tolerance ±0.000001. Accepted tolerance: ±0.000001 arcseconds. Omit units and commas.

Enter a number in seconds; absolute tolerance ±0.000001. Accepted tolerance: ±0.000001 seconds. Omit units and commas.

4. What does a measured maximum of 0.08 arcsecond establish?

2. Measure adjoining-segment jumps

A curve may follow its source closely within a segment yet meet the next curve with a small step. To inspect that join, compare both predictions at their shared time. This checks how the curves meet each other, a different question from how either follows its source.

Take invented degree-1 longitude lists [359, 1] and [1.00002, 1]. The preceding curve ends at x = +1, giving 359 + 1 = 360°. The next begins at x = −1, giving 1.00002 − 1 = 0.00002°. Their short circular distance is 0.00002° = 0.072 arcsecond. Subtracting without wrapping would misleadingly suggest almost a full turn.

This difference at the join is called a Seam jump The distance between two segment predictions at their shared endpoint. This compares one curve with the next; a residual instead compares a curve with its source function. National Institute of Standards and Technology: Digital Library of Mathematical Functions — polynomial approximation. Both values describe the same time, although that time has a different normalized coordinate in each segment. For degree 1, p(x) = c₀ + c₁x, so its end is c₀ + c₁ and its start is c₀ − c₁.

left = p_previous(+1); right = p_next(−1)

jump = short circular or scalar endpoint distance × 3600

Use the same short circular distance for longitude and absolute difference for declination. Evaluate every consecutive pair, convert to arcseconds, and report the largest jump. Fewer than two segments leave no pairs, so the reported maximum remains zero. Unwrapped longitude values separated by a whole turn also have zero circular jump.

Zero jump does not tell us whether the curves follow their reference. Two adjoining longitude curves can agree perfectly with each other while both remaining 1° from the source. Their seam measurement is zero, while their source residual is large.

Connect this step to the source

tools/dataset-builder/src/cheb/fit.rs

boundary_jump_arcsec

Paths refer to the astrology-engine repository. Examples use invented inputs; a successful exercise is not an astronomical-accuracy test.

Sources for this section

Apply this step

Answer every part, then check. You can retry as often as you like.

Enter a number in arcseconds; absolute tolerance ±0.000001. Accepted tolerance: ±0.000001 arcseconds. Omit units and commas.

2. A row has residual 0.09″, gate 0.1″ and reported seam 0.15″. Does the implemented row decision accept it?
3. Two adjoining longitude curves are identical but both 1° from the source. What can their seam show?

3. Try the fit ladder

When a curve misses its residual limit, there are two straightforward adjustments to try: give its polynomial more coefficients, or ask each polynomial to cover a shorter interval. The builder tries those adjustments in a fixed order and measures each result, rather than assuming an adjustment improves it.

For an initial 32-day, degree-10 specification, the attempts are 32/10, 32/12, 16/10, 16/12. Suppose their measured maxima begin 0.16″, 0.11″, 0.09″ against a 0.1″ limit. The third passes; the fourth is never run. The third attempt returns to the initial degree 10, even though the preceding attempt used degree 12.

The configured acceptance limit is a Residual gate The configured largest permitted measured residual for a row. In this builder equality passes, and the first passing ladder attempt is retained. It is a sampled workflow condition, not a continuous or independent accuracy guarantee. . Body longitude and declination use 0.1 arcsecond; NodeOmega longitude uses 1 arcsecond. At exactly the limit, the row passes. For NodeOmega beginning at 8 days/degree 10, residuals 1.1″ and then exactly 1.0″ select 8 days/degree 12. The remaining 4-day attempts are skipped. A body longitude residual of 1.0″ would fail its smaller gate.

attempts = (S,d), (S,d+2), (S/2,d), (S/2,d+2)

row passes when measured residual ≤ configured gate

Here S is the initial segment length in days and d is the initial degree. Each attempt refits the entire series; the builder stops at the first passing result rather than seeking the smallest possible residual. A shorter segment length can also change the series’ actual fitted end.

The comparison is a direct ≤ test, not a separate finite-data audit. The teaching gate function below takes a supplied measured maximum; it does not reproduce every way the current accumulator handles nonfinite source values. The ladder and thresholds are engineering choices in this repository, not a published astronomical accuracy standard.

See the teaching TypeScript
const ladder = (days: number, degree: number): [number, number][] =>
  [[days, degree], [days, degree + 2], [days / 2, degree], [days / 2, degree + 2]];
const passesMeasuredResidual = (residualArcsec: number, gateArcsec: number): boolean =>
  residualArcsec <= gateArcsec;

Finite, correctly labeled inputs are assumed. This demonstrates the arithmetic; it does not fetch data or replace the engine.

Connect this step to the source

tools/dataset-builder/src/main.rs

fit_with_ladder; fit

Paths refer to the astrology-engine repository. Examples use invented inputs; a successful exercise is not an astronomical-accuracy test.

Sources for this section

Apply this step

Answer every part, then check. You can retry as often as you like.

Enter a number in days; absolute tolerance ±0. Accepted tolerance: ±0 days. Omit units and commas.

Enter a number in degree; absolute tolerance ±0. Accepted tolerance: ±0 degree. Omit units and commas.

3. For gate 0.1″, the successive residuals are 0.2″, exactly 0.1″, and a hypothetical 0.01″. Which fit is kept?
4. One series fails all four attempts while the others pass. What happens next?

Your lesson checks

0 of 3 steps passed.

Use the feedback beside each check to retry any unfinished step.