如何解决Astropy Units equivalencies - 使用类和 SI 前缀的干涉测量基线
作为 Astropy Units equivalencies - interferometry baselines 的后续。我想问一下如何为我的自定义单位使用 SI 前缀。到目前为止,按照附加链接中的建议,我从 astropy Quantity 创建了一个子类,然后覆盖了 .to 方法。
这是我的代码:
class uWavelength(un.Quantity):
def __new__(cls,value,freq=None,dtype=None,copy=True,**kwargs):
unit = un.Unit(un.def_unit('lambdas',format={'format': r'\lambda'},prefixes=True))
self = super().__new__(cls,value=value,unit=unit,dtype=dtype,copy=copy,**kwargs)
self.freq = freq
if self.freq is not None:
self.equivalencies = self.lambdas_equivalencies()
return self
@property
def freq(self):
return self._freq
@freq.setter
def freq(self,val):
if val is not None:
self._equivalencies = self.lambdas_equivalencies(restfreq=val)
self._freq = val
@property
def equivalencies(self):
return self._equivalencies
@equivalencies.setter
def equivalencies(self,val):
self._equivalencies = val
def lambdas_equivalencies(self,restfreq=None):
if self.freq is not None:
restfreq_hz = self.freq.to(un.Hz,equivalencies=un.spectral())
elif restfreq is not None:
restfreq_hz = restfreq.to(un.Hz,equivalencies=un.spectral())
else:
sys.exit("Frequency not provided")
eq = [
(self.unit,un.s,lambda x: x / restfreq_hz,lambda x: x * restfreq_hz),(self.unit,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,lambda x: x / co.c.to(un.m / un.s).value,lambda x: x * co.c.to(un.m / un.s).value),]
return eq
def to(self,unit,restfreq=None,copy=True):
equiv = []
if restfreq is None:
equiv = self.equivalencies
else:
equiv = self.lambdas_equivalencies(restfreq=restfreq)
unit = un.Unit(unit)
if copy:
# Avoid using to_value to ensure that we make a copy. We also
# don't want to slow down this method (esp. the scalar case).
value = self._to_value(unit,equiv)
else:
# to_value only copies if necessary
value = self.to_value(unit,equiv)
return self._new_view(value,unit)class uWavelength(un.Quantity):
def __new__(cls,unit)
但是,当我使用该类时,我只能使用单位 lambda,但我想使用 klambda 或 mega-lambda 等。根据 astropy,这可以通过使用参数 prefixes=True
来完成,但是这似乎不起作用。
解决方法
我认为您实际上不应该定义类的 __new__
内的单位,因为它不允许您在实例化 uWavelength
时实际设置单位.
而是把它放在你的课堂之外:
lambdas = u.def_unit('lambdas',format={'format': r'\lambda'})
我认为文档并没有说清楚的一点是,当您使用 prefixes=True
时,除非您还提供 namespace=
参数,否则它不会真正做任何事情,即使如此,文档也没有非常清楚如何使用命名空间。我认为最好采用 astrofrog 的建议,明确声明所需的前缀单位,例如:
klambdas = u.def_unit('kilolambdas',represents=u.CompositeUnit(1e3,[lambdas],[1]),format={'format' : r'k\lambda'})```
unless you *really* need every imaginable SI prefix,you could try:
lambdas = u.def_unit('lambdas',format={'format': r'\lambda'},prefixes=True,namespace=globals())
and it will inject every prefixed unit into your module namespace.
Then,since you want your default unit for `uWavelength` to be `lambdas`,then both to reduce confusion,and also add some documentation of this fact (through the signature of `__new__`) specify:
```python
class uWavelength(un.Quantity):
def __new__(cls,value,freq=None,unit=lambdas,dtype=None,copy=True,**kwargs):
此外,如果您愿意,可以添加如下检查:
unit = u.Unit(unit)
assert unit.is_equivalent(lambdas),'unit must be equivalent to lambdas'
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。