DiFX 运行和测试结果分析

作者:

DiFX研究整体流程:

图 1:从 VDIF 输入到复可见度分析的完整流程


1. 本次完成了什么

完整流程如下:

源码安装
→ 生成 Synthetic VDIF
→ mpifxcorr 互相关
→ 生成 test-usb.difx
→ difx2fits 生成 test-usb.fits
→ Astropy 读取 UV_DATA
→ 计算幅度和相位

本次结果如下:

项目结果
DiFX 版本2.9.0
输入文件TEST1.vdifTEST2-usb.vdif
模拟台站T1、T2
基线数量1 条
UV_DATA 记录数30
频率通道数4096
FLUX 长度8192
参考频率200 MHz
单通道带宽976.5625 Hz
总带宽约 4 MHz

本次测试证明了软件和数据处理链路已经跑通,但并不代表已经得到真实天体图像。


2. DiFX 安装与环境配置

2.1 下载并固定版本

mkdir -p ~/software
cd ~/software

git clone --recurse-submodules https://github.com/difx/difx.git
cd difx

git checkout V2.9.0
git submodule update --init --recursive
git describe --tags --always

正常情况下应显示:

v2.9.0

2.2 关键环境路径

配置路径
DIFXROOT$HOME/difx-2.9.0
MPICXX/usr/bin/mpicxx
IPPROOT/opt/intel/oneapi/ipp/2022.3
PGPLOTDIR/usr/lib

加载环境:

source ~/software/difx/setup.bash

检查变量:

echo "$DIFXROOT"
echo "$MPICXX"
echo "$IPPROOT"
echo "$PGPLOTDIR"

2.3 编译安装

mkdir -p ~/build/difx-2.9.0
cd ~/build/difx-2.9.0

source ~/software/difx/setup.bash
~/software/difx/install-difx --ipp 2>&1 | tee install.log

检查核心相关器:

which mpifxcorr

test -x "$DIFXROOT/bin/mpifxcorr" \
  && echo "DiFX 核心相关器安装成功"

3. 生成 Synthetic 模拟数据

复制官方测试目录:

mkdir -p ~/difx_work
cp -a ~/software/difx/tests/Synthetic ~/difx_work/
cd ~/difx_work/Synthetic

为了缩短测试时间,将 createData.sh 中的:

export DURATION=1200

改为:

export DURATION=10

运行:

./createData.sh 2>&1 | tee createData.log

本次生成了 8 个 VDIF 文件,总大小约 154 MB,其中测试使用:

TEST1.vdif
TEST2-usb.vdif

VDIF 保存的是带时间标记的数字采样帧,不是图像,也不是最终科学结果。


4. 运行最小互相关测试

执行:

cd ~/difx_work/Synthetic

unset DISPLAY XAUTHORITY WAYLAND_DISPLAY
./run-usb.sh 2>&1 | tee run-usb.log

脚本会自动完成:

生成 test-usb.input / .calc / .threads
→ 调用 mpifxcorr
→ 生成 test-usb.difx
→ 调用 difx2fits
→ 生成 test-usb.fits

成功日志应包含:

Conversion successful
1 of 1 jobs converted to 1 FITS files

检查输入配置:

grep -niE "DATA FORMAT|DATA SOURCE|BASELINE|FILE" test-usb.input

本次关键结果为:

DATA FORMAT:       VDIF
DATA SOURCE:       FILE
BASELINE ENTRIES:  1
FILE 0/0:          TEST1.vdif
FILE 1/0:          TEST2-usb.vdif

这说明相关器确实读取了两路 VDIF,并完成了 T1—T2 一条基线的互相关。


5. 配置文件和输出文件

DiFX 不能只依靠 VDIF 文件运行,还需要配置文件说明台站、时间、频率、边带和时延模型。

文件作用
.vex观测计划、台站、源、频率和扫描
.v2d数据路径与相关参数
.inputmpifxcorr 的核心执行配置
.calc几何时延和台站模型
.threads线程分配
machinesMPI 节点清单

主要输出文件:

输出含义
test-usb.difx/mpifxcorr 原生复可见度结果
DIFX_*.difx 内部的实际相关数据
test-usb.fitsFITS-IDI 标准数据容器

注意:FITS 文件包含二进制表,直接用文本编辑器打开出现乱码。


6. UV_DATA 和 FLUX 的结构

使用 Astropy 读取后,实验结果如下:

图 2:UV_DATA结构

本次 UV_DATA 包含:

  • 30 条记录;
  • 每条 13 个字段;
  • 1 个极化产品;
  • 1 个频带;
  • 4096 个频率通道;
  • 每条 FLUX 长度为 8192。

为什么通道数是 4096,而 FLUX 长度是 8192?

是由于$ N_{\mathrm{FLUX}} = 2\times1\times4096\times1\times1\times1 = 8192 $

其中 COMPLEX = 2,表示每个通道保存实部和虚部:

R₁, I₁, R₂, I₂, R₃, I₃, ...

因此第 (k) 个通道的复可见度为:

$ V_k=R_k+iI_k $

第一条记录如下:

图 3:第一条 UV_DATA 记录

字段实际值含义
BASELINE258$(256\times1+2)$,即 T1—T2
INTTIM1.048576 s单条记录积分时间
WEIGHT0.9892578相关权重,不是准确率
UU/VV/WW基线在空间频率坐标中的投影

7. 幅度、相位和带宽公式

幅度:

$ A_k=\lvert V_k\rvert =\sqrt{R_k^2+I_k^2} $

相位:

$ \phi_k=\operatorname{atan2}(I_k,R_k) $

总带宽:

$ B=N_{\mathrm{chan}}\Delta f $

代入本次参数:

$ B = 4096\times976.5625\ \mathrm{Hz} = 4\ \mathrm{MHz} $

由于当前 FLUX 单位为 UNCALIB,因此幅度只是未标定相关幅度,不能直接写成 Jy。


8. Python 读取与绘图

安装依赖:

python -m pip install astropy numpy matplotlib

核心代码:

from astropy.io import fits
import matplotlib.pyplot as plt
import numpy as np

with fits.open("test-usb.fits") as hdul:
    row = hdul["UV_DATA"].data[0]

    flux = np.asarray(row["FLUX"], dtype=float).ravel()

    real = flux[0::2]
    imag = flux[1::2]

    visibility = real + 1j * imag
    amplitude = np.abs(visibility)
    phase_deg = np.angle(visibility, deg=True)

channel = np.arange(len(visibility))

plt.plot(channel, amplitude)
plt.xlabel("Channel number")
plt.ylabel("Visibility amplitude")
plt.grid()
plt.show()

plt.plot(channel, phase_deg)
plt.xlabel("Channel number")
plt.ylabel("Visibility phase (degrees)")
plt.grid()
plt.show()

完整脚本位于:

scripts/analyze_difx_fits.py

9. 幅度图分析

可见度幅度:

图 4:第一条记录的 4096 通道可见度幅度

主要特征:

  • 频带两端逐渐下降,说明存在通带边缘滚降;
  • 中间多数通道幅度约在 0.02~0.12 范围内波动;
  • 约第 1020 通道出现最高窄峰,幅度约 0.44;
  • 约第 1530 通道出现另一明显窄峰,幅度约 0.36。

这些峰只能称为较强窄带相关分量。由于当前是 Synthetic 数据,不能直接说成真实谱线、RFI 或某个天体信号。

这张图表示的是一条基线、一个时间积分内,不同频率通道上的相关强度。


10. 相位图分析

可见度相位:

图 5:第一条记录的 4096 通道原始包裹相位

相位范围为:

$ -180^\circ\leq\phi_k\leq180^\circ $

相位密集跳变的原因主要包括:

  • 当前只使用第一条记录;
  • 没有筛选高信噪比通道;
  • 没有进行时间平均;
  • 没有相位展开;
  • 低幅度通道的相位更容易受到噪声影响;
  • 相位跨过 (180^\circ) 后会跳回 (-180^\circ)。

因此不能说已经得到稳定条纹。

如果要估计残余时延,应先进行通道筛选、时间平均和相位展开,再拟合:

$ \phi(f)=\phi_0+2\pi f\tau_{\mathrm{res}} $

残余时延为:

$ \tau_{\mathrm{res}} = \frac{1}{2\pi} \frac{\mathrm{d}\phi}{\mathrm{d}f} $


11. 当前结论与下一步

11.1 已经证明

  • DiFX 2.9.0 安装成功;
  • Synthetic VDIF 数据生成成功;
  • T1—T2 一条基线互相关成功;
  • .difx 和 FITS-IDI 输出成功;
  • Astropy 能读取 UV_DATA
  • 4096 通道复可见度能够拆分并绘制幅相图。

11.2 暂时不能证明

  • 当前幅度已经是 Jy;
  • 两个窄峰就是真实天文谱线或 RFI;
  • 原始相位已经稳定;
  • 已经完成条纹搜索和残余时延测量;
  • 已经处理 /data/Difx_data 中的真实数据。

真实数据阶段应先检查是否存在:

.input / .calc / .threads

或者:

.vex / .v2d

随后选择小规模任务运行:

vex2difx experiment.v2d
calcif2 experiment
mpirun -np 4 mpifxcorr experiment.input
difx2fits experiment

12. 总结

本次已经完整跑通:

VDIF 输入
→ mpifxcorr 互相关
→ .difx 输出
→ FITS 转换
→ UV_DATA 读取
→ FLUX 拆分
→ 幅度和相位提取

最终确认:

  • test-usb.fits 中有 30 条 UV_DATA 记录;
  • 每条记录包含 4096 个频率通道;
  • FLUX 中的 8192 个数对应 4096 组实部和虚部;
  • 幅度图显示通带边缘滚降和两个明显窄带峰;
  • 相位图显示原始包裹相位;
  • 幅度尚未标定,相位尚未平均和展开。

最终结论: DiFX 2.9.0 的安装、Synthetic VDIF 生成、基线互相关、.difx 输出、FITS 转换、UV_DATA 读取和幅相提取流程均已正常运行。下一步重点是处理小规模真实数据,并完成配置核验、条纹搜索、相位展开、残余时延拟合和幅相标定。

评论

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注