374 lines
8.3 KiB
Markdown
374 lines
8.3 KiB
Markdown
# WCS and Other Astropy Modules
|
|
|
|
## World Coordinate System (astropy.wcs)
|
|
|
|
The WCS module manages transformations between pixel coordinates in images and world coordinates (e.g., celestial coordinates).
|
|
|
|
### Reading WCS from FITS
|
|
|
|
```python
|
|
from astropy.wcs import WCS
|
|
from astropy.io import fits
|
|
|
|
# Read WCS from FITS header
|
|
with fits.open('image.fits') as hdul:
|
|
wcs = WCS(hdul[0].header)
|
|
```
|
|
|
|
### Pixel to World Transformations
|
|
|
|
```python
|
|
# Single pixel to world coordinates
|
|
world = wcs.pixel_to_world(100, 200) # Returns SkyCoord
|
|
print(f"RA: {world.ra}, Dec: {world.dec}")
|
|
|
|
# Arrays of pixels
|
|
import numpy as np
|
|
x_pixels = np.array([100, 200, 300])
|
|
y_pixels = np.array([150, 250, 350])
|
|
world_coords = wcs.pixel_to_world(x_pixels, y_pixels)
|
|
```
|
|
|
|
### World to Pixel Transformations
|
|
|
|
```python
|
|
from astropy.coordinates import SkyCoord
|
|
import astropy.units as u
|
|
|
|
# Single coordinate
|
|
coord = SkyCoord(ra=10.5*u.degree, dec=41.2*u.degree)
|
|
x, y = wcs.world_to_pixel(coord)
|
|
|
|
# Array of coordinates
|
|
coords = SkyCoord(ra=[10, 11, 12]*u.degree, dec=[41, 42, 43]*u.degree)
|
|
x_pixels, y_pixels = wcs.world_to_pixel(coords)
|
|
```
|
|
|
|
### WCS Information
|
|
|
|
```python
|
|
# Print WCS details
|
|
print(wcs)
|
|
|
|
# Access key properties
|
|
print(wcs.wcs.crpix) # Reference pixel
|
|
print(wcs.wcs.crval) # Reference value (world coords)
|
|
print(wcs.wcs.cd) # CD matrix
|
|
print(wcs.wcs.ctype) # Coordinate types
|
|
|
|
# Pixel scale
|
|
pixel_scale = wcs.proj_plane_pixel_scales() # Returns Quantity array
|
|
```
|
|
|
|
### Creating WCS
|
|
|
|
```python
|
|
from astropy.wcs import WCS
|
|
|
|
# Create new WCS
|
|
wcs = WCS(naxis=2)
|
|
wcs.wcs.crpix = [512.0, 512.0] # Reference pixel
|
|
wcs.wcs.crval = [10.5, 41.2] # RA, Dec at reference pixel
|
|
wcs.wcs.ctype = ['RA---TAN', 'DEC--TAN'] # Projection type
|
|
wcs.wcs.cdelt = [-0.0001, 0.0001] # Pixel scale (degrees/pixel)
|
|
wcs.wcs.cunit = ['deg', 'deg']
|
|
```
|
|
|
|
### Footprint and Coverage
|
|
|
|
```python
|
|
# Calculate image footprint (corner coordinates)
|
|
footprint = wcs.calc_footprint()
|
|
# Returns array of [RA, Dec] for each corner
|
|
```
|
|
|
|
## NDData (astropy.nddata)
|
|
|
|
Container for n-dimensional datasets with metadata, uncertainty, and masking.
|
|
|
|
### Creating NDData
|
|
|
|
```python
|
|
from astropy.nddata import NDData
|
|
import numpy as np
|
|
import astropy.units as u
|
|
|
|
# Basic NDData
|
|
data = np.random.random((100, 100))
|
|
ndd = NDData(data)
|
|
|
|
# With units
|
|
ndd = NDData(data, unit=u.electron/u.s)
|
|
|
|
# With uncertainty
|
|
from astropy.nddata import StdDevUncertainty
|
|
uncertainty = StdDevUncertainty(np.sqrt(data))
|
|
ndd = NDData(data, uncertainty=uncertainty, unit=u.electron/u.s)
|
|
|
|
# With mask
|
|
mask = data < 0.1 # Mask low values
|
|
ndd = NDData(data, mask=mask)
|
|
|
|
# With WCS
|
|
from astropy.wcs import WCS
|
|
ndd = NDData(data, wcs=wcs)
|
|
```
|
|
|
|
### CCDData for CCD Images
|
|
|
|
```python
|
|
from astropy.nddata import CCDData
|
|
|
|
# Create CCDData
|
|
ccd = CCDData(data, unit=u.adu, meta={'object': 'M31'})
|
|
|
|
# Read from FITS
|
|
ccd = CCDData.read('image.fits', unit=u.adu)
|
|
|
|
# Write to FITS
|
|
ccd.write('output.fits', overwrite=True)
|
|
```
|
|
|
|
## Modeling (astropy.modeling)
|
|
|
|
Framework for creating and fitting models to data.
|
|
|
|
### Common Models
|
|
|
|
```python
|
|
from astropy.modeling import models, fitting
|
|
import numpy as np
|
|
|
|
# 1D Gaussian
|
|
gauss = models.Gaussian1D(amplitude=10, mean=5, stddev=1)
|
|
x = np.linspace(0, 10, 100)
|
|
y = gauss(x)
|
|
|
|
# 2D Gaussian
|
|
gauss_2d = models.Gaussian2D(amplitude=10, x_mean=50, y_mean=50,
|
|
x_stddev=5, y_stddev=3)
|
|
|
|
# Polynomial
|
|
poly = models.Polynomial1D(degree=3)
|
|
|
|
# Power law
|
|
power_law = models.PowerLaw1D(amplitude=10, x_0=1, alpha=2)
|
|
```
|
|
|
|
### Fitting Models to Data
|
|
|
|
```python
|
|
# Generate noisy data
|
|
true_model = models.Gaussian1D(amplitude=10, mean=5, stddev=1)
|
|
x = np.linspace(0, 10, 100)
|
|
y_true = true_model(x)
|
|
y_noisy = y_true + np.random.normal(0, 0.5, x.shape)
|
|
|
|
# Fit model
|
|
fitter = fitting.LevMarLSQFitter()
|
|
initial_model = models.Gaussian1D(amplitude=8, mean=4, stddev=1.5)
|
|
fitted_model = fitter(initial_model, x, y_noisy)
|
|
|
|
print(f"Fitted amplitude: {fitted_model.amplitude.value}")
|
|
print(f"Fitted mean: {fitted_model.mean.value}")
|
|
print(f"Fitted stddev: {fitted_model.stddev.value}")
|
|
```
|
|
|
|
### Compound Models
|
|
|
|
```python
|
|
# Add models
|
|
double_gauss = models.Gaussian1D(amp=5, mean=3, stddev=1) + \
|
|
models.Gaussian1D(amp=8, mean=7, stddev=1.5)
|
|
|
|
# Compose models
|
|
composite = models.Gaussian1D(amp=10, mean=5, stddev=1) | \
|
|
models.Scale(factor=2) # Scale output
|
|
```
|
|
|
|
## Visualization (astropy.visualization)
|
|
|
|
Tools for visualizing astronomical images and data.
|
|
|
|
### Image Normalization
|
|
|
|
```python
|
|
from astropy.visualization import simple_norm
|
|
import matplotlib.pyplot as plt
|
|
|
|
# Load image
|
|
from astropy.io import fits
|
|
data = fits.getdata('image.fits')
|
|
|
|
# Normalize for display
|
|
norm = simple_norm(data, 'sqrt', percent=99)
|
|
|
|
# Display
|
|
plt.imshow(data, norm=norm, cmap='gray', origin='lower')
|
|
plt.colorbar()
|
|
plt.show()
|
|
```
|
|
|
|
### Stretching and Intervals
|
|
|
|
```python
|
|
from astropy.visualization import (MinMaxInterval, AsinhStretch,
|
|
ImageNormalize, ZScaleInterval)
|
|
|
|
# Z-scale interval
|
|
interval = ZScaleInterval()
|
|
vmin, vmax = interval.get_limits(data)
|
|
|
|
# Asinh stretch
|
|
stretch = AsinhStretch()
|
|
norm = ImageNormalize(data, interval=interval, stretch=stretch)
|
|
|
|
plt.imshow(data, norm=norm, cmap='gray', origin='lower')
|
|
```
|
|
|
|
### PercentileInterval
|
|
|
|
```python
|
|
from astropy.visualization import PercentileInterval
|
|
|
|
# Show data between 5th and 95th percentiles
|
|
interval = PercentileInterval(90) # 90% of data
|
|
vmin, vmax = interval.get_limits(data)
|
|
|
|
plt.imshow(data, vmin=vmin, vmax=vmax, cmap='gray', origin='lower')
|
|
```
|
|
|
|
## Constants (astropy.constants)
|
|
|
|
Physical and astronomical constants with units.
|
|
|
|
```python
|
|
from astropy import constants as const
|
|
|
|
# Speed of light
|
|
c = const.c
|
|
print(f"c = {c}")
|
|
print(f"c in km/s = {c.to(u.km/u.s)}")
|
|
|
|
# Gravitational constant
|
|
G = const.G
|
|
|
|
# Astronomical constants
|
|
M_sun = const.M_sun # Solar mass
|
|
R_sun = const.R_sun # Solar radius
|
|
L_sun = const.L_sun # Solar luminosity
|
|
au = const.au # Astronomical unit
|
|
pc = const.pc # Parsec
|
|
|
|
# Fundamental constants
|
|
h = const.h # Planck constant
|
|
hbar = const.hbar # Reduced Planck constant
|
|
k_B = const.k_B # Boltzmann constant
|
|
m_e = const.m_e # Electron mass
|
|
m_p = const.m_p # Proton mass
|
|
e = const.e # Elementary charge
|
|
N_A = const.N_A # Avogadro constant
|
|
```
|
|
|
|
### Using Constants in Calculations
|
|
|
|
```python
|
|
# Calculate Schwarzschild radius
|
|
M = 10 * const.M_sun
|
|
r_s = 2 * const.G * M / const.c**2
|
|
print(f"Schwarzschild radius: {r_s.to(u.km)}")
|
|
|
|
# Calculate escape velocity
|
|
M = const.M_earth
|
|
R = const.R_earth
|
|
v_esc = np.sqrt(2 * const.G * M / R)
|
|
print(f"Earth escape velocity: {v_esc.to(u.km/u.s)}")
|
|
```
|
|
|
|
## Convolution (astropy.convolution)
|
|
|
|
Convolution kernels for image processing.
|
|
|
|
```python
|
|
from astropy.convolution import Gaussian2DKernel, convolve
|
|
|
|
# Create Gaussian kernel
|
|
kernel = Gaussian2DKernel(x_stddev=2)
|
|
|
|
# Convolve image
|
|
smoothed_image = convolve(data, kernel)
|
|
|
|
# Handle NaNs
|
|
from astropy.convolution import convolve_fft
|
|
smoothed = convolve_fft(data, kernel, nan_treatment='interpolate')
|
|
```
|
|
|
|
## Stats (astropy.stats)
|
|
|
|
Statistical functions for astronomical data.
|
|
|
|
```python
|
|
from astropy.stats import sigma_clip, sigma_clipped_stats
|
|
|
|
# Sigma clipping
|
|
clipped_data = sigma_clip(data, sigma=3, maxiters=5)
|
|
|
|
# Get statistics with sigma clipping
|
|
mean, median, std = sigma_clipped_stats(data, sigma=3.0)
|
|
|
|
# Robust statistics
|
|
from astropy.stats import mad_std, biweight_location, biweight_scale
|
|
robust_std = mad_std(data)
|
|
robust_mean = biweight_location(data)
|
|
robust_scale = biweight_scale(data)
|
|
```
|
|
|
|
## Utils
|
|
|
|
### Data Downloads
|
|
|
|
```python
|
|
from astropy.utils.data import download_file
|
|
|
|
# Download file (caches locally)
|
|
url = 'https://example.com/data.fits'
|
|
local_file = download_file(url, cache=True)
|
|
```
|
|
|
|
### Progress Bars
|
|
|
|
```python
|
|
from astropy.utils.console import ProgressBar
|
|
|
|
with ProgressBar(len(data_list)) as bar:
|
|
for item in data_list:
|
|
# Process item
|
|
bar.update()
|
|
```
|
|
|
|
## SAMP (Simple Application Messaging Protocol)
|
|
|
|
Interoperability with other astronomy tools.
|
|
|
|
```python
|
|
from astropy.samp import SAMPIntegratedClient
|
|
|
|
# Connect to SAMP hub
|
|
client = SAMPIntegratedClient()
|
|
client.connect()
|
|
|
|
# Broadcast table to other applications
|
|
message = {
|
|
'samp.mtype': 'table.load.votable',
|
|
'samp.params': {
|
|
'url': 'file:///path/to/table.xml',
|
|
'table-id': 'my_table',
|
|
'name': 'My Catalog'
|
|
}
|
|
}
|
|
client.notify_all(message)
|
|
|
|
# Disconnect
|
|
client.disconnect()
|
|
```
|