Эквиваленты единиц астропии - базовые параметры интерферометрии

Я пытаюсь создать эквивалент astropy.units для преобразования между различными единицами UV-координат при работе с интерферометрическими астрономическими данными. Самый распространенный способ сохранения координат - в секундах, однако я обычно конвертирую непосредственно в лямбды (в зависимости от длины волны / частоты покоя). Я хочу иметь возможность выбирать между: (нано) секундами - (килограммами) лямбда-метрами. Входными данными, которые необходимы для преобразования, является частота покоя отдельных наблюдений.

Первоначальное описание метода:

На данный момент я придумал следующее.

import astropy.units as un
import astropy.constants as co

restfreq_hz = 203e9 #203 Ghz
lambdas = un.def_unit('lambdas', format={'format' : r'\lambda'})
klambdas = un.def_unit('kilolambdas', format={'format' : r'k\lambda'})

# equivalency (from_unit, to_unit, forward, backward)
lambdas_equivalencies = [
    (lambdas, un.s, lambda x: x/restfreq_hz, lambda x: x*restfreq_hz),
    (lambdas, un.m, lambda x: x/restfreq_hz * co.c.to(un.m/un.s).value, lambda x: x/co.c.to(un.m/un.s).value * restfreq_hz),
    (lambdas, un.ns, lambda x: x/restfreq_hz * 1e9, lambda x: x / 1e-9*restfreq_hz ),
    (lambdas, klambdas, lambda x: x*1e-3, lambda x: x*1e3),
    (klambdas, un.s, lambda x: 1e3*x/restfreq_hz, lambda x: 1e-3*x*restfreq_hz),
    (klambdas, un.m, lambda x: 1e3*x/restfreq_hz * co.c.to(un.m/un.s).value, lambda x: 1e-3*x/co.c.to(un.m/un.s).value * restfreq_hz),
    (klambdas, un.ns, lambda x: 1e3*x/restfreq_hz * 1e9, lambda x: 1e-3*x / 1e-9*restfreq_hz ),
    (un.m, un.s, lambda x: x/co.c.to(un.m/un.s).value, lambda x: x*co.c.to(un.m/un.s).value),
    (un.m, un.ns, lambda x: x/co.c.to(un.m/un.ns).value, lambda x: x*co.c.to(un.m/un.ns).value)
]

Итак, в качестве примера я могу сделать следующее:

In [10]: (100.*klambdas).to(un.m ,equivalencies=lambdas_equivalencies)
Out[10]: <Quantity 147.68101379310343 m>

In [13]: (12 * un.m).to(lambdas, equivalencies=lambdas_equivalencies)
Out[13]: <Quantity 8125.621359026984 lambdas>

In [29]: (1000000*un.ns).to(lambdas, equivalencies=lambdas_equivalencies)
Out[29]: <Quantity 203000000.0 lambdas>

Это предпочтительный / лучший способ сделать это, или я чего-то упускаю? Любые дополнительные настройки / советы приветствуются!

Дополнительные проблемы:

Я хочу включить это в объект. Итак, я определяю массив (атрибут объекта) с единицей измерения «кламбда». Затем я хочу иметь возможность преобразовать это на лету в «лямбда» или «м». Могу ли я сделать это, не переопределяя класс массива?


person Magnus Persson    schedule 16.01.2015    source источник


Ответы (1)


То, что у вас есть в настоящее время, работает, но вы можете немного упростить его. В частности, если astropy.units уже умеет конвертировать, например s в ns, тогда вам не нужно определять одновременно m в s и m в ns, он сможет это выяснить. Для дальнейшего упрощения вы можете определить klambdas как кратное lambdas. Это дает:

lambdas = un.def_unit('lambdas', format={'format' : r'\lambda'})
klambdas = un.def_unit('kilolambdas', 1e3 * lambdas, format={'format' : r'k\lambda'})

# equivalency (from_unit, to_unit, forward, backward)
lambdas_equivalencies = [
    (lambdas, un.s, lambda x: x/restfreq_hz, lambda x: x*restfreq_hz),
    (lambdas, un.m, lambda x: x/restfreq_hz * co.c.to(un.m/un.s).value, lambda x: x/co.c.to(un.m/un.s).value * restfreq_hz),
    (un.m, un.s, lambda x: x/co.c.to(un.m/un.s).value, lambda x: x*co.c.to(un.m/un.s).value),
]

На самом деле у вас, вероятно, должна быть функция эквивалентности, которая принимает частоту:

def lambdas_equivalencies(restfreq_hz):
    eq = [
    (lambdas, un.s, lambda x: x/restfreq_hz, lambda x: x*restfreq_hz),
    (lambdas, un.m, lambda x: x/restfreq_hz * co.c.to(un.m/un.s).value, lambda x: x/co.c.to(un.m/un.s).value * restfreq_hz),
    (un.m, un.s, lambda x: x/co.c.to(un.m/un.s).value, lambda x: x*co.c.to(un.m/un.s).value),
    ]
    return eq

затем используйте его как

(100.*klambdas).to(un.m ,equivalencies=lambdas_equivalencies(restfreq_hz))

и вы также должны иметь возможность вместо restfreq_hz быть количеством, которое вы можете преобразовать в Hz, если это необходимо внутри функции ::

def lambdas_equivalencies(restfreq):
    restfreq_hz = restfreq.to(u.Hz, equivalencies=u.spectral())
    ...

тогда вы даже можете передавать длины волн и т. д.

Что касается вашего второго вопроса, я думаю, вам, возможно, придется создать новый класс количества, который наследуется от Quantity и просто перегружает to.

person astrofrog    schedule 16.01.2015
comment
Приятно спасибо! Возможность добавлять единицы к вещам просто делает вещи намного лучше. Возможно, полезно и для кого-то другого. - person Magnus Persson; 16.01.2015
comment
Что касается моего второго вопроса, я решил его просто, определив lambdas_equivalencies глобально, и в объекте, где я хочу, чтобы количество было, я сначала определяю u.add_enabled_equivalencies(lambdas_equivalencies(restfreq_unit)), где значение restfreq_unit индивидуально для каждого объекта. После некоторого тестирования кажется, что u.add_enabled_equivalencies определяет эквивалентности только локально, т.е. я могу создать несколько объектов с разными restfreq_unit, и преобразование сохраняется правильным для каждого объекта. - person Magnus Persson; 16.01.2015
comment
klambdas = un.def_unit('kilolambdas', 1e3 * lambdas, format={'format' : r'k\lambda'}) Не могли ли они также просто определить «лямбды» для приема префиксов SI? Может быть, перебор, но это не будет пересекаться ни с чем другим, о чем я могу думать. - person Iguananaut; 19.01.2015