Bu bölümün laboratuvarı, kitaptaki örnekleri yeniden üretmek ve sayısal sonuçları incelemek için hazırlanmıştır. Matematiksel tanımlar, ispatlar ve sorular kitapta yer alır.
Laboratuvar kodu
"""Bölüm 15: kutupsal ve rasyonel konik laboratuvarı.
Uygulama, bir odağı merkez alan sentetik ideal bir eliptik yörünge
geometrisidir. Dinamik, zaman yasası, kütleçekim parametresi, efemeris,
bozucu etkiler, koordinat zamanı ve görev güvenliği modele dahil değildir.
"""
from __future__ import annotations
import numpy as np
from agbook import (
canonical_array_sha256,
focus_directrix_residuals,
polar_conic_algebraic_residuals,
polar_conic_diagnostics,
polar_conic_frame,
polar_conic_points,
rational_conic_points,
rotation_matrix_2d,
)
def main() -> None:
length_unit = "km"
focus_km = np.array([0.0, 0.0])
periapsis_direction_deg = 35.0
angle_rad = np.deg2rad(periapsis_direction_deg)
axis_direction = np.array([np.cos(angle_rad), np.sin(angle_rad)])
eccentricity = 0.4
semilatus_rectum_km = 8400.0
frame = polar_conic_frame(
focus_km,
axis_direction,
eccentricity,
semilatus_rectum_km,
)
semi_major_km = semilatus_rectum_km / (1.0 - eccentricity**2)
semi_minor_km = semilatus_rectum_km / np.sqrt(1.0 - eccentricity**2)
focal_distance_km = eccentricity * semi_major_km
center_km = focus_km - focal_distance_km * frame.axis_direction
second_focus_km = center_km - focal_distance_km * frame.axis_direction
characteristic_angles_rad = np.deg2rad([0.0, 60.0, 90.0, 120.0, 180.0])
diagnosis = polar_conic_diagnostics(
frame.focus,
frame.axis_direction,
frame.eccentricity,
frame.semilatus_rectum,
characteristic_angles_rad,
)
periapsis_km = diagnosis.radii[0]
apoapsis_km = diagnosis.radii[-1]
comparison_angles_rad = np.deg2rad([-140.0, -90.0, -30.0, 0.0, 45.0, 110.0])
tangent_half_angles = np.tan(comparison_angles_rad / 2.0)
polar_points_km = polar_conic_points(
frame.focus,
frame.axis_direction,
frame.eccentricity,
frame.semilatus_rectum,
comparison_angles_rad,
)
rational_points_km = rational_conic_points(
frame.focus,
frame.axis_direction,
frame.eccentricity,
frame.semilatus_rectum,
tangent_half_angles,
)
representation_gap_km = np.linalg.norm(
polar_points_km - rational_points_km,
axis=1,
)
uniform_angles_rad = np.linspace(-np.pi, np.pi, 145)
uniform_points_km = polar_conic_points(
frame.focus,
frame.axis_direction,
frame.eccentricity,
frame.semilatus_rectum,
uniform_angles_rad,
)
chord_lengths_km = np.linalg.norm(np.diff(uniform_points_km, axis=0), axis=1)
chord_ratio = float(np.max(chord_lengths_km) / np.min(chord_lengths_km))
rotation = rotation_matrix_2d(np.deg2rad(23.0))
translation_km = np.array([1300.0, -700.0])
moved_focus_km = rotation @ frame.focus + translation_km
moved_axis = rotation @ frame.axis_direction
moved_points_km = polar_conic_points(
moved_focus_km,
moved_axis,
frame.eccentricity,
frame.semilatus_rectum,
comparison_angles_rad,
)
expected_moved_points_km = polar_points_km @ rotation.T + translation_km
rigid_gap_km = np.linalg.norm(moved_points_km - expected_moved_points_km, axis=1)
points_m = 1000.0 * polar_points_km
residual_km = polar_conic_algebraic_residuals(
polar_points_km,
frame.focus,
frame.axis_direction,
frame.eccentricity,
frame.semilatus_rectum,
)
residual_m = polar_conic_algebraic_residuals(
points_m,
1000.0 * frame.focus,
frame.axis_direction,
frame.eccentricity,
1000.0 * frame.semilatus_rectum,
)
np.testing.assert_allclose(semi_major_km, 10000.0, atol=1e-12)
np.testing.assert_allclose(periapsis_km, 6000.0, atol=1e-12)
np.testing.assert_allclose(apoapsis_km, 14000.0, atol=3e-12)
np.testing.assert_allclose(polar_points_km, rational_points_km, atol=4e-12)
np.testing.assert_allclose(rigid_gap_km, 0.0, atol=4e-12)
np.testing.assert_allclose(residual_m, residual_km, atol=3e-15)
assert diagnosis.maximum_absolute_algebraic_residual < 2e-15
assert diagnosis.maximum_absolute_focus_directrix_residual < 4e-12
assert chord_ratio > 1.5
rational_algebraic = polar_conic_algebraic_residuals(
rational_points_km,
frame.focus,
frame.axis_direction,
frame.eccentricity,
frame.semilatus_rectum,
)
rational_geometric_km = focus_directrix_residuals(
rational_points_km,
frame.focus,
frame.directrix,
frame.eccentricity,
)
signature_values = np.concatenate(
[
focus_km,
axis_direction,
np.array([eccentricity, semilatus_rectum_km]),
frame.directrix,
np.array([semi_major_km, semi_minor_km, focal_distance_km]),
center_km,
second_focus_km,
characteristic_angles_rad,
diagnosis.radii,
diagnosis.points.ravel(),
comparison_angles_rad,
tangent_half_angles,
polar_points_km.ravel(),
rational_points_km.ravel(),
uniform_angles_rad,
chord_lengths_km,
rotation.ravel(),
translation_km,
moved_points_km.ravel(),
residual_km,
residual_m,
]
)
print("uzunluk_birimi:", length_unit)
print("model: sentetik_ideal_eliptik_yorunge_geometrisi")
print("dinamik_ve_efemeris_modeli_mi: False")
print("gercek_gorev_veya_guvenlik_hesabi_mi: False")
print("odak_km:", frame.focus)
print("periapsis_yonu_derece:", periapsis_direction_deg)
print("dismerkezlik:", frame.eccentricity)
print("yari_odak_kirisi_km:", frame.semilatus_rectum)
print("yari_buyuk_eksen_km:", f"{semi_major_km:.6f}")
print("yari_kucuk_eksen_km:", f"{semi_minor_km:.6f}")
print("merkez_km:", center_km)
print("ikinci_odak_km:", second_focus_km)
print("periapsis_uzakligi_km:", f"{periapsis_km:.6f}")
print("apoapsis_uzakligi_km:", f"{apoapsis_km:.6f}")
print("ornek_acilar_derece:", np.rad2deg(characteristic_angles_rad))
print("ornek_yaricaplar_km:", diagnosis.radii)
print(
"en_buyuk_cebirsel_artik:",
f"{max(diagnosis.maximum_absolute_algebraic_residual, np.max(np.abs(rational_algebraic))):.3e}",
)
print(
"en_buyuk_odak_dogrultman_artigi_km:",
f"{max(diagnosis.maximum_absolute_focus_directrix_residual, np.max(np.abs(rational_geometric_km))):.3e}",
)
print("en_buyuk_kutupsal_rasyonel_fark_km:", f"{np.max(representation_gap_km):.3e}")
print("esit_aci_adimi_kiris_orani:", f"{chord_ratio:.6f}")
print("rijit_hareket_kovaryant_mi:", bool(np.max(rigid_gap_km) < 4e-12))
print("ortak_olcekte_boyutsuz_artik_korundu_mu:", bool(np.allclose(residual_m, residual_km, atol=3e-15)))
print("bilimsel_imza:", canonical_array_sha256(signature_values))
if __name__ == "__main__":
main()
Doğrulama çalıştırmasının çıktısı
uzunluk_birimi: km
model: sentetik_ideal_eliptik_yorunge_geometrisi
dinamik_ve_efemeris_modeli_mi: False
gercek_gorev_veya_guvenlik_hesabi_mi: False
odak_km: [0. 0.]
periapsis_yonu_derece: 35.0
dismerkezlik: 0.4
yari_odak_kirisi_km: 8400.0
yari_buyuk_eksen_km: 10000.000000
yari_kucuk_eksen_km: 9165.151390
merkez_km: [-3276.60817716 -2294.3057454 ]
ikinci_odak_km: [-6553.21635431 -4588.61149081]
periapsis_uzakligi_km: 6000.000000
apoapsis_uzakligi_km: 14000.000000
ornek_acilar_derece: [ 0. 60. 90. 120. 180.]
ornek_yaricaplar_km: [ 6000. 7000. 8400. 10500. 14000.]
en_buyuk_cebirsel_artik: 1.332e-15
en_buyuk_odak_dogrultman_artigi_km: 1.819e-12
en_buyuk_kutupsal_rasyonel_fark_km: 3.666e-12
esit_aci_adimi_kiris_orani: 2.332477
rijit_hareket_kovaryant_mi: True
ortak_olcekte_boyutsuz_artik_korundu_mu: True
bilimsel_imza: 8893fc148539ace0802c8faf06277665066ac08e5de25a7d076120c83ff9a280
Metindeki Python kodları
# Kitaptaki kod blokları; bu dosya içinde sırayla çalıştırılır.
# --- 1. Birleşik kutupsal konik tanısı ---
import numpy as np
from agbook import polar_conic_diagnostics
cases = [
(0.5, np.linspace(-np.pi, np.pi, 41)),
(1.0, np.linspace(-2.5, 2.5, 41)),
(2.0, np.linspace(-1.9, 1.9, 41)),
]
for e, theta in cases:
result = polar_conic_diagnostics(
[0., 0.], [1., 0.], e, 3., theta
)
print(
e,
np.min(result.denominators),
result.maximum_absolute_algebraic_residual,
result.maximum_absolute_focus_directrix_residual,
)
assert np.min(result.denominators) > 0.
assert result.maximum_absolute_algebraic_residual < 4e-13
assert result.maximum_absolute_focus_directrix_residual < 5e-14
Kaydedilen çıktı
1. Birleşik kutupsal konik tanısı
0.5 0.5 8.881784197001252e-16 8.881784197001252e-16
1.0 0.1988563844530663 1.7763568394002505e-15 1.7763568394002505e-15
2.0 0.3534208662729933 2.220446049250313e-15 8.881784197001252e-16
Çözümlerdeki Python kodları
# Kitaptaki kod blokları; bu dosya içinde sırayla çalıştırılır.
# --- 1. Üç konik türünde payda ve artık tanısı ---
import numpy as np
from agbook import polar_conic_diagnostics
cases = {
"ellipse": (0.5, np.linspace(-np.pi, np.pi, 41)),
"parabola": (1.0, np.linspace(-2.5, 2.5, 41)),
"hyperbola": (2.0, np.linspace(-1.9, 1.9, 41)),
}
for name, (e, theta) in cases.items():
d = polar_conic_diagnostics([0., 0.], [1., 0.], e, 3., theta)
print(
name,
"payda_marji=", np.min(d.denominators),
"cebirsel=", d.maximum_absolute_algebraic_residual,
"odak_dogrultman=", d.maximum_absolute_focus_directrix_residual,
)
assert np.min(d.denominators) > 0.
assert d.maximum_absolute_algebraic_residual < 4e-13
assert d.maximum_absolute_focus_directrix_residual < 5e-14
# --- 2. Kutupsal ve rasyonel elipsin eşleştirilmesi ---
import numpy as np
from agbook import (
polar_conic_frame,
polar_conic_points,
rational_conic_points,
)
F = np.array([1., -2.])
u = np.array([3., 4.])
e, ell = 0.6, 5.
theta = np.deg2rad([-150., -90., -20., 0., 45., 130.])
t = np.tan(theta / 2.)
p_polar = polar_conic_points(F, u, e, ell, theta)
p_rational = rational_conic_points(F, u, e, ell, t)
gap = np.linalg.norm(p_polar - p_rational, axis=1)
assert np.max(gap) < 3e-14
frame = polar_conic_frame(F, u, e, ell)
closed_samples = np.vstack([p_rational, frame.rational_limit_point])
print("en_buyuk_fark:", np.max(gap))
print("t_sonsuz_noktasi:", frame.rational_limit_point)
print("tamamlanmis_boyut:", closed_samples.shape)
# --- 3. Hiperbol dalları ve açık sınır hataları ---
import numpy as np
from agbook import (
polar_conic_frame,
polar_conic_points,
rational_conic_points,
)
e, ell = 2., 3.
alpha = np.arccos(-1. / e)
beta = np.arccos(1. / e)
near = polar_conic_points(
[0., 0.], [1., 0.], e, ell,
np.linspace(-alpha + 0.1, alpha - 0.1, 101),
)
far = polar_conic_points(
[0., 0.], [1., 0.], e, ell,
np.linspace(-beta + 0.1, beta - 0.1, 101),
branch="far_side",
)
frame = polar_conic_frame([0., 0.], [1., 0.], e, ell)
tau = frame.rational_singular_parameters[1]
intervals = [
np.linspace(-4., -tau - 0.1, 80),
np.linspace(-tau + 0.1, tau - 0.1, 160),
np.linspace(tau + 0.1, 4., 80),
]
rational_parts = [
rational_conic_points([0., 0.], [1., 0.], e, ell, values)
for values in intervals
]
assert near.shape == (101, 2)
assert far.shape == (101, 2)
assert sum(part.shape[0] for part in rational_parts) == 320
bad_calls = [
lambda: polar_conic_points(
[0., 0.], [1., 0.], e, ell, np.pi
),
lambda: rational_conic_points(
[0., 0.], [1., 0.], e, ell, tau,
denominator_tolerance=1e-14,
),
]
for call in bad_calls:
try:
call()
except ValueError as error:
print(type(error).__name__, str(error))
else:
raise AssertionError("Geçersiz girdi sessizce kabul edildi.")
# --- 4. Rijit hareket ve metre--milimetre ölçeği ---
import numpy as np
from agbook import (
polar_conic_algebraic_residuals,
polar_conic_frame,
polar_conic_points,
rotation_matrix_2d,
)
F = np.array([2., -1.])
u = np.array([3., 4.])
e, ell = 0.7, 5. # ell metre cinsinde
theta = np.array([-1.2, 0., 0.8])
points_m = polar_conic_points(F, u, e, ell, theta)
Q = rotation_matrix_2d(np.deg2rad(31.))
q = np.array([7., -3.])
moved = polar_conic_points(Q @ F + q, Q @ u, e, ell, theta)
assert np.allclose(moved, points_m @ Q.T + q)
scale = 1000. # metre -> milimetre
points_mm = polar_conic_points(scale * F, u, e, scale * ell, theta)
assert np.allclose(points_mm, scale * points_m)
frame_m = polar_conic_frame(F, u, e, ell)
frame_mm = polar_conic_frame(scale * F, u, e, scale * ell)
assert frame_mm.eccentricity == frame_m.eccentricity
assert np.isclose(frame_mm.semilatus_rectum, scale * ell)
r_m = polar_conic_algebraic_residuals(points_m, F, u, e, ell)
r_mm = polar_conic_algebraic_residuals(
points_mm, scale * F, u, e, scale * ell
)
assert np.allclose(r_mm, r_m, atol=3e-15)
Kaydedilen çıktı
1. Üç konik türünde payda ve artık tanısı
ellipse payda_marji= 0.5 cebirsel= 8.881784197001252e-16 odak_dogrultman= 8.881784197001252e-16
parabola payda_marji= 0.1988563844530663 cebirsel= 1.7763568394002505e-15 odak_dogrultman= 1.7763568394002505e-15
hyperbola payda_marji= 0.3534208662729933 cebirsel= 2.220446049250313e-15 odak_dogrultman= 8.881784197001252e-16
2. Kutupsal ve rasyonel elipsin eşleştirilmesi
en_buyuk_fark: 1.3322676295501878e-15
t_sonsuz_noktasi: [ -6.5 -12. ]
tamamlanmis_boyut: (7, 2)
3. Hiperbol dalları ve açık sınır hataları
ValueError Seçilen açı için kutupsal payda pozitif toleransın üstünde olmalıdır.
ValueError Rasyonel konik paydası sıfır toleransından uzak olmalıdır.
4. Rijit hareket ve metre--milimetre ölçeği
Çalıştırma rehberi
Önce tam Python paketini indirin ve arşivi açın. Aşağıdaki komutları arşivin üst klasöründen başlatın. İlk kurulum internet bağlantısı ve Python 3.12 veya 3.13 gerektirir. Bağımlılıklar sabittir; sistem Python'unu değiştirmemek için ayrı sanal ortam kullanılır.
macOS / Linux
cd analitik-geometri-python-v1.0
python3 -m venv .venv
source .venv/bin/activate
python -m pip install -e ".[dev]"
python labs/bolum_15_kutupsal_konikler.py
python -m pytestWindows PowerShell
cd analitik-geometri-python-v1.0
py -3.13 -m venv .venv
.venv\Scripts\python.exe -m pip install -e ".[dev]"
.venv\Scripts\python.exe labs/bolum_15_kutupsal_konikler.py
.venv\Scripts\python.exe -m pytest