def doppler_beaming(wave, flux, vrad, vrad_units='km/s'): r""" Apply non-relativistic Doppler beaming effects to a spectrum (boosting). Boosting of a spectrum :math:`(\lambda, F(\lambda))` is defined as (Loeb & Gaudi 2003 :cite:`loeb2003`, Bloemen 2011 :cite:`bloemen2011`): .. math:: \lambda_s = \left(1 + \frac{v_\mathrm{rad}}{c}\right) \lambda \\ F_b(\lambda) = \left(1+5\frac{v_\mathrm{rad}}{c}\right)F(\lambda_s) :parameter wave: wavelength array :type wave: ndarray :parameter vrad: radial velocity (negative shifts towards blue, positive towards red) :type vrad: float (units: km/s) or tuple (float,'units') :parameter vrad_units: units of radial velocity (default: km/s) :type vrad_units: str (interpretable for :py:func:`aspyre.units.conversions.convert`) :return: boosted flux :rtype: ndarray """ cc = constants.cc # Explicitly convert km/s to m/s: giving radial velocity in wavelengths # offers a speed benefit. Choosing flexibility of different units will # require an extra step that uses the conversions module (this is a little # slower than explicit conversion) if vrad_units == 'km/s': cc = cc / 1000.0 else: cc = conversions.convert('m/s', vrad_units, cc) flux_shift = doppler_shift(wave, vrad, flux=flux) flux_boost = flux_shift + 5*vrad/cc * flux_shift return flux_boost
def doppler_shift(wave, vrad, vrad_units='km/s', flux=None, relativistic=False): r""" Shift a spectrum towards the red (+) or blue side (-) with some radial velocity. You can give units with the extra keywords :envvar:`vrad_units`, but a speed increase is offered if you use the default km/s. The units of wavelengths are not important, the shifted wavelengths will be in the same units as the input wave array. The Doppler shift from the original wavelength :math:`\lambda` is to the shifted wavelength :math:`\lambda_s` is implemented as: .. math:: \lambda_s = ( 1 + z ) \lambda with .. math:: z = \frac{v_\mathrm{rad}}{c}\qquad\mbox{in the nonrelativistic case}\\ z = \sqrt{\frac{1+v_\mathrm{rad}/c}{1-v_\mathrm{rad}/c}}-1\qquad\mbox{in the relativistic case}\\ When the keyword :envvar:`flux` is set, the spectrum will be interpolated onto the original wavelength grid (so the original wavelength grid will not change). When the keyword :envvar:`flux` is not set, the wavelength array will be changed (but the fluxes are obviously not): - When :envvar:`flux` is set, fluxes will be returned. - When :envvar:`flux` is not set, wavelengths will be returned. :note: If you want to apply a barycentric (or orbital) correction, you'd probably want to reverse the sign of the radial velocity! .. raw:: html <p class="flip1">Example usage: shift a spectrum to the red (right) with 20 km/s</p> <div class="panel1"> :: wave = np.linspace(3000, 8000, 1000) wave_shift1 = tools.doppler_shift(wave, 20.) wave_shift2 = tools.doppler_shift(wave, 20000., vrad_units='m/s') print(wave_shift1[0], wave_shift1[-1]) (3000.200138457119, 8000.5337025523177) print(wave_shift2[0], wave_shift2[-1]) (3000.200138457119, 8000.5337025523177) Or with a complete line profile:: wave = np.linspace(3000, 8000, 30) flux = 1.0 - 0.5*np.exp( - (wave-5500)**2/(2*500**2)) wave0 = tools.doppler_shift(wave, 5000.,) flux1 = tools.doppler_shift(wave, 5000., flux=flux) Notice how, with the second ('red') version, the original wavelength array can be re-used, while with the first ('blue') version, the original flux array can be re-used. Keep in mind that when the fluxes are shifted, they are linearly interpolated onto the shifted wavelength array, so the shift is not exact:: plt.figure() plt.plot(wave, flux, 'ko-', label='Original data') plt.plot(wave0,flux,'bx-',lw=2,mew=2,ms=10, label='Shifted wavelength grid') plt.plot(wave,flux1,'r+--',lw=2,mew=2,ms=10, label='Original wavelength grid') plt.legend(loc='best') plt.xlabel("Wavelength [$\AA$]") plt.ylabel("Normalised flux") .. image:: ../../images/api/spectra/tools/doppler_shift01.png :scale: 50 % .. raw:: html </div> <br> :parameter wave: wavelength array :type wave: ndarray :parameter vrad: radial velocity (negative shifts towards blue, positive towards red) :type vrad: float (units: km/s) or tuple (float,'units') :parameter vrad_units: units of radial velocity (default: km/s) :type vrad_units: str (interpretable for :py:func:`aspyre.units.conversions.convert`) :parameter relatvistic: apply relativistic Doppler shift :type relativistic: bool :return: shifted wavelength array/shifted flux :rtype: ndarray """ cc = constants.cc # Explicitly convert km/s to m/s: giving radial velocity in wavelengths # offers a speed benefit. Choosing flexibility of different units will # require an extra step that uses the conversions module (this is a little # slower than explicit conversion) if vrad_units == 'km/s': cc = cc / 1000.0 else: cc = conversions.convert('m/s', vrad_units, cc) # Shift wavelengths according to the radial velocity z = vrad/cc if relativistic: z = np.sqrt( (1.0+z) / (1.0-z)) - 1.0 wave_out = wave * (1.0 + z) # If fluxes are give, interpolate them from the original grid onto the new # wavelength grid if flux is not None: flux = np.interp(wave, wave_out, flux) return flux else: return wave_out