以不同频率采样的信号之间的相位差

信息处理 fft 离散信号 采样 阶段
2022-01-27 08:21:15

我想知道是否可以测量在两个不同位置以不同采样频率采样的信号之间的相对相位差?该方法也可以扩展到采样不足的情况吗?

编辑:添加 Matlab 脚本以测试 Dan Boschen 提供的可能解决方案(Eq.3)


clear all
close all
clc

Len = 768/121e6;
Fs1  = 157e6;
t1 = 0:1/(13*Fs1) :Len-1/Fs1; %Time vector for Channel 1
Fs2 = 121e6;
t2 = 0:1/(13*Fs2) :Len-1/Fs2; %Time vector for Channel 1

f=25e6; % Incoming signal frequency

phase_diff_in=0; % Modelling the actual phase difference taking In-Phase for now

% Creating signals
sign1 = cos(2*pi*f*t1);
sign2 = cos(2*pi*f*t2 + deg2rad(phase_diff_in) );
sign1 = sign1(1:13:end);
sign2 = sign2(1:13:end);

% Adding a reference cosine
sig_ref=cos(2*pi*Fs1*t2);% Fs1 sampled by Fs2
sig_ref =sig_ref(1:13:end);

% Test of phase difference formula in time domain
phi1=acos(sign1(1:256));% In first window of 256 points
phi2=acos(sign2(1:256));
phi3=acos(sig_ref(1:256));

T1=1/Fs1;
n=0:255;
phase_diff=2*pi*n*f*( ((T1*phi3(n+1))/(2*pi*n)) -T1)...
    - (phi2(n+1) - phi1(n+1));
phase_diff=wrapToPi(phase_diff);
figure;plot(rad2deg(phase_diff),'-*r')

据我了解,这种情况下的相位差应该是 0,但事实并非如此。相位差(以度为单位)如下所示:

在此处输入图像描述

更新:模拟 Dan 添加的代码

Fs1  = 157e6;
Fs2 = 121e6;
f=500e6;%25e6
samples = 400;
Len = samples;
Phi = 45;
phase_out=phase_scale(Fs1,Fs2,f,Phi,Len);
figure;
plot(phase_out)
mean(phase_out)

对于 f=25e6 和 phi=45 的情况,得到以下结果:

在此处输入图像描述

对于 f=500e6 和 phi=45 的情况,得到以下结果:

在此处输入图像描述

随着频率的进一步增加,误差显着增加。

更新 #2: Dan 修改代码后的模拟结果

对于 f=25MHz 和 phi=45 的情况,得到以下结果:

在此处输入图像描述

这表明相位差的测量非常准确。

同样对于 subnyquist 情况以及@f=600MHz 和 phi=75,得到以下结果:

在此处输入图像描述

这表明这也适用于 subnyquist 案例。因此,给定的解决方案在 Dan 在答案的“实际限制”部分中陈述的假设下有效。

2个回答

解决方案

底线

$$(\theta_2-\theta_1) = 2\pi f(T_2-T_1)n -(\phi_2[n]-\phi_1[n]) \tag{1}$$

$f$ : 相同频率和固定相位偏移的两个音调的频率 (Hz)

$(\theta_2-\theta_1)$:被采样音调的弧度相位差

$T_1$ : 采样率$f_{s1}$以秒为单位的采样时钟 1 的周期

$T_2$ : 采样率$f_{s1}$以秒为单位的采样时钟 2 的周期

$\phi_1[n]$ :以弧度/样本为单位的$f_{s1}$采样色调的相位结果

$\phi_2[n]$ :以弧度/样本为单位的$f_{s2}$采样色调的相位结果

这显示了如何扩展以相同采样率采样的相同频率的两个音调之间的相位的任何标准方法(常见的相位检测器方法,包括乘法、相关等)可以扩展以处理两个采样率不同的情况.

先简单解释一下:

考虑等式 (1) 的指数频率形式:

$$e^{j(\theta_2-\theta_1)} = e^{j2\pi f(T_2-T_1)n}e^{-j(\phi_2[n]-\phi_1[n])} \tag {2}$$

术语$e^{j2\pi f(T_2-T_1)n}$是预测的两个音调之间的频率差异,这是由于以两种不同的采样率对单个音调进行采样(当在相同的归一化频率上观察两者时)规模)。

观察到的两种音调之间的频率差异为$e^{j(\phi_2[n]-\phi_1[n])} $

这两项具有相同的频率,具有固定的相位偏移。该相位偏移是两个连续时间音调之间的实际相位差。通过共轭乘法,我们将两者相减,去除相位斜率和固定相位差结果。

推导

方法是仔细处理具有样本时间轴的所有单元。因此,频域以归一化频率为单位:当时间轴为秒时,周期/样本或弧度/样本对应于周期/秒或弧度/秒。因此,我们的采样率,无论它是以秒为单位的时间,将始终等于$1$周期/样本(或$2\pi$弧度/样本,如果在标准化弧度频率下工作)。

具有相同模拟频率的两个信号一旦在时域中分别以不同的速率被采样,将是各自具有不同归一化频率的两个信号。

这简化了问题,为我们提供了以下结果:

给定我们的原始信号为具有不同相位偏移的相同频率的归一化正弦音:

$$x_1(t) = \cos(2\pi ft + \theta_1) \tag{3}$$ $$x_1(t) = \cos(2\pi ft + \theta_2) \tag{4}$$

一次采样但仍以秒为单位的时间: $$x_1(nT_1) = \cos(2\pi fn T_1 + \theta_1) \tag{5} $$ $$x_2(nT_2) = \cos(2\pi fn T_2 + \theta_2) \标签{6}$$

式(5)和式(6)以样本为单位表示的时间为:

$$x_1[n] = \cos(2\pi f T_1 n+ \theta_1) \tag{7}$$ $$x_2[n] = \cos(2\pi f T_2 n+ \theta_2) \tag{8} $$

转换为复指数形式,以便我们可以使用复共轭乘法轻松提取相位项,(对于单音,我们只需将输入信号拆分为正交分量;$\cos(\phi) \rightarrow [\cos(\ phi),\sin(\phi)]\rightarrow \cos(\phi)+j\sin(\phi) = e^{j\phi}$,这是使用希尔伯特变换描述为$h\{\} $ )

$$h\{x_1[n]\} =e^{-j(\phi_1[n])} = e^{2\pi f T_1 n+ \theta_1} = e^{2\pi f T_1 n}e ^{\theta_1} \tag{9}$$ $$h\{x_2[n]\} = e^{-j(\phi_2[n])} =e^{2\pi f T_2 n+ \theta_2} =e^{2\pi f T_2 n}e^{\theta_2} \tag{10}$$

复共轭乘法为我们提供了我们寻求的差分相位项及其与我们测量结果的关系:

$$e^{-j(\phi_2[n]-\phi_1[n])} = e^{2\pi f T_2 n}e^{\theta_2}e^{-2\pi f T_1 n}e ^{-\theta_1} \tag{11}$$

导致

$$e^{j(\theta_2-\theta_1)} = e^{j2\pi f(T_2-T_1)n}e^{-j(\phi_2[n]-\phi_1[n])} \tag {12}$$

注意$e^{-j(\phi_2[n]-\phi_1[n])}$表示对于单音将导致频率的测量值,该频率预计为$\omega = 2\pi f (T_2-T_1)n$,由 $e^{j2\pi f(T_2-T_1)n}$项给出。如果我们去除频率偏移(通过上面的乘法),结果就是原始信号的相位差。

取两边的自然对数显示以相位为单位(弧度)的结果:

$$(\theta_2-\theta_1) = 2\pi f(T_2-T_1)n-(\phi_2[n]-\phi_1[n]) \tag{13}$$

所以总而言之,$\phi_1[n]$ , $\phi_2[n]$来自我们给出的测量值$cos(\phi_1[n])$ , $cos(\phi_2[n])$并且我们建立了我们需要通过这些测量的希尔伯特变换的复共轭乘法来得到答案。


示范

我用下面的脚本演示了这一点,类似于 OP 的配置,结果绘制在下面,现在包括抽取,并针对 f = 25 MHz 和 f = 400 MHz(欠采样)进行了测试,结果相似。这显示了演示的每个步骤以上流程,可以进一步组合操作。实施中的希尔伯特变换将是任何将采样音延迟 90° 的选择方法(分数延迟全通滤波器是一个合理的选择)。

Len = 10000;
phase_diff_in = 45;
f=400e6; % Incoming signal frequency
D = 13
Fs1 = 157e6*D;
Fs2 = 121e6*D;
t1 = [0:Len-1]/Fs1;  % Time vector channel 1
t2 = [0:Len-1]/Fs2;  % Time vector channel 2
phi1 = 2*pi*f*t1;   
phi2 = 2*pi*f*t2 + deg2rad(phase_diff_in);
sign1 = cos(phi1);
sign2 = cos(phi2);

% emulation of perfect Hilbert Transform for each tone:
c1_in = 2*(sign1 - 0.5*exp(j*phi1));
c2_in = 2*(sign2 - 0.5*exp(j*phi2));

% create expected phase slope to remove
n = [0:Len-1];
comp_in = exp(-j*2*pi*f*(1/Fs2-1/Fs1)*n);    

% decimation
c1 = c1_in(1:D:end);
c2 = c2_in(1:D:end);
comp = comp_in(1:D:end);
pdout = c1.*conj(c2);
result = pdout.*comp;

%determine phase_diff
phase_out = rad2deg(unwrap(angle(result)));
mean_phase = mean(phase_out); 

下面是两个测试用例的结果,OP 在他的示例中尝试 0°,然后是 45° 相移。

下面显示了频率为 $f$的输入信号副本的结果,在它们之间零度相位的情况下,$f_{s1}$作为 sig1 和$f_{s2}$作为 sig2 采样。复共轭积 pdout 的实数是粗体红色正弦曲线,我们注意到它的相位偏移为零。

相位检测器输出

为了确认计算,下图将其直接与补偿项 $cos(2\pi f(T_2-T_1)) 的实数进行比较,以查看它们的频率是否与等式一致。

角度 diff = 0

并重复$\theta_2-\theta_1 = 45°$

角度 diff = 45

每个样本的原始相位数据的结果表明,每个样本单独具有极低的噪声(受数值精度限制,因此可以用很少的样本确定结果!)。这种性能将取决于希尔伯特变换的实际质量,以准确地将输入音延迟 90° 以创建正交副本。在噪声条件下,可以将结果平均到波形稳定性的范围内,以获得非常稳健的解决方案。

相位与样本

使用欠采样情况进行的扩展性能测试显示了出色的结果(f = 400e6):

以 1 度的步长测试每个差异角: 相位扫描

10,000 个样本的 RMS 误差(注意垂直轴以 0.5e-11 为增量)

标准偏差与输入相位

输入频率从 1e6 到 4000e6 以 1e6 为步长进行了极大扩展的频率扫描,具有 45 度相移,在每个频率处测量了 10,000 个点,结果表明,在所有频率(过采样和欠采样)下的相位确定结果都是一致的。这是 OP 配置的两个频率,包括 13 的抽取。(因此,该测试抽取后每个输入音调的采样率是 fs = 157e6 和 121e6,因此该图的最右边是频率被采样的音调为 4e9 明显欠采样。如图所示,RMS 误差与音调的频率成正比,但即使在这种极端条件下,误差仍然小于 5e-10 度。(8.7e-12弧度或-221 dB)。

扩展频率扫描


实际限制

上述结果的准确性受限于对$f_{s1}$$f_{s2}$给出的准确频率和相位关系的了解,以及对被采样音调的频率$f$的了解。

(如所写,该解决方案还假设两个采样时钟都在时间$t=0$开始,但是可以从等式(8)开始添加采样偏移量,结果相似;底线是两者之间的起始相位关系必须知道或测量采样时钟,因为它会引入额外的偏移)。

现实情况是,没有两个自由运行的时钟会保持完美同步。未锁定到公共参考的采样时钟之间的实际频率和相位差将不可避免地发生漂移(请参阅西格尔定律https://en.wikipedia.org/wiki/Segal%27s_law)。必须将其中一个时钟声明为我们的时间参考(我们的测量将与那个时钟的精度一致)。如果时钟不在物理上位于同一位置,则可以使用双向时间传输技术(参见https://tf.nist.gov/time/twoway.htm)来测量一个时钟与另一个时钟的对比。如果它们在物理上位于同一位置,那么简单的做法就是对一个时钟与另一个时钟进行采样。

下面我展示了这种方法如何从我们的解决方案的方程中完全消除一个采样时钟:( 我尚未对此进行测试,因此可能包含数学错误)

考虑使用$f_{s2}=\frac{1}{T_2}$对$f_{s1}=\frac{1}{T_1}$进行抽样。这将最终通过使用$f_{s1}$作为公共参考完全从等式中删除$f_{s2}$ (我们基本上通过对$f_{ s1}进行采样来测量$f_{s2}$$f_{s1}$ $$f_{s2}$允许我们将$f_{s2}$的样本以$f_{s1}$计数为单位。):

$f_{s1}$作为余弦:

$$x_{s1}(t) = cos(2\pi f_{s1}t) \tag{14}$$

在给定约束条件下使用$f_{s2}$进行采样时,它们都从 t=0 开始变为:

$$x_{s_1}(nT_2) = cos(2\pi f_{s1}nT_2) = cos(2\pi nT_2/T_1) \tag{15}$$

其中以样本为单位:

$$x_{s_1}[n] =cos(2\pi T_2/T_1 n) \tag{16}$$

导致以样本为单位的第三阶段测量,我们可以通过对$f_{s1}$$f_{s2}$进行采样来获得(重要的是要同时完成$x_1(t)$$x_2(t) $被抽样!):

$$\phi_3[n] = 2\pi T_2/T_1 n \tag{17}$$

因此,如果我们不知道$T_2$但有$\phi_3$,我们可以代入上述等式得到:

$$T_2 = \frac{T_1 \phi_3[n]}{2\pi n} \tag{18}$$

代入(4):

$$ \phi_2[n]- \phi_1[n] = 2\pi nf\bigg(\frac{T_1 \phi_3[n]}{2\pi n}-T_1\bigg) + (\theta_2-\theta_1) \标签{19} $$

对原始输入信号的期望相位差产生以下解决方案:

$$ \theta_2-\theta_1 = 2\pi f\bigg(\frac{T_1 \phi_3[n]}{2\pi n}-T_1\bigg) n - (\phi_2[n]- \phi_1[n] ) \标签{20} $$

在哪里

$f$ : 被采样的音调频率

$T_1$ : 采样频率为 $f_{s1}$的采样时钟 1 的周期

$\phi_1[n]$ :使用$f_{s1}$采样音调的结果,值为$cos(\phi_1[n]) $

$\phi_2[n]$ :使用$f_{s2}$采样音调的结果,值为$cos(\phi_2[n]) $

$\phi_3[n]$ :用$f_{s2}$采样$f_{s1}$的结果,值为$cos(\phi_3[n]) $

因此只知道$T_1$$1/f_{s1}$,我们可以直接从$x_1(t)$的样本中测量$f$ ,通过采样$ x_1(t)来测量$\phi_1[n]$ $$f_{s1}$通过采样$x_2(t)$$f_{s_2}$测量$\ phi_2 [n]$并通过采样 $f_{s1}$测量$\phi_3[n]$ $f_{s2}$并从这些测量中解析$\theta_2-\theta_1$

同样,如果您的应用程序的相位偏移不会改变,那么您可以使用结果的斜率测量$f_{s2}$误差,而无需使用$ f_{s2 }$ 对$f_{s1}$进行采样。

真正的结果将取决于$f_{s1}$的实际时钟精度,但我们已经从等式中完全删除了 $f_{s2}$ 。如果您可以将$f_{s1}$视为您对时间的真正参考,这意味着它对于您的测量精度和准确性来说足够准确,那么结果将是您被采样的两个波形的相位差。这意味着最终你需要一些东西来作为你共同的时间参考。

对于您问题的第一部分,也许这会有所启发:

以两种不同的采样频率采样的信号的相位差测量

你的问题的第二部分的答案是单一的纯音是肯定的。它会在 DFT 中显示为较低频率的混叠,但如果您知道实际频率范围,则可以计算出正确的频率。

一个警告。如果它是 DC 或 Nyquist 频率的别名,它可能会出现,也可能不会出现。这些是 DFT 的潜在“盲点”。


我相信我的链接答案的第三部分是最有效和最准确的,特别是考虑到采样不足的可能性。

它是这样的:

$M$$N$的值,使得:

$$ \frac{M}{N} = \frac{T_1}{T_2} - \epsilon $$

这让你:

$$ (MT_2 \约 NT_1 )= T_{DFT \; 帧} $$

由于您知道$f$,因此您知道在第一个信号上$M$样本 DFT中的$k_1$和在相同持续时间的第二个信号上的 $N$ 样本 DFT中的$ k_2$ 。您只需要在每个 DFT 中计算两个 bin 值,即$k$$k+1$ ,它们分别位于其中$f$所在的书挡。使用我的两个 bin 解决方案的相位计算来求解相关参数(不是之前的文章版本,它不会将两个 bin 展开为真实向量)。你已经知道频率,所以你不必估计它。

为了使变量名不同,我们称它们为:

$$ \begin{对齐} S_1[n] &= A_1 \cos( \omega_1 n + \tau_1 ) \\ S_2[m] &= A_2 \cos( \omega_2 m + \tau_2 ) \\ \end{对齐} $$

两个 bin 解决方案的后半部分将求解$A$$\tau$参数。$\omega$是提前知道的

使用采样率(每秒采样数),这些可以转换为真实世界的值,并直接比较该间隔的相位值。如果$\epsilon$很大,则可以将其纳入此计算。

该解决方案使幅度差异无关紧要。它还允许您在欠采样信号的情况下补偿可能的混叠。

DFT 帧持续时间存在固有延迟。

[加粗是为了 OP 和其他人的利益,而不是 Dan]


由于讨论得很多,所以我忽略的是,信号到达的任何时间差异都将直接转化为相位差中的误差。如果相位差跨越许多样本,这只是一个不准确的来源。如果相位差是样本大小甚至是子样本(可通过 DFT 方法检测到),它就会出现真正的问题。第一个链接中介绍了一种校准解决方案,它可能适合也可能不适合 OP。


也可以选择整数周期的持续时间,并从中选择$M$$N$然后每个只需要计算一个DFT bin,并且可以预定义基向量。

选择整数个周期加上一半,其中$MT_2$非常接近$NT_1$,并且采用两个 bin 相位更能抗噪,但每个信号需要两次 DFT bin 计算。


回复丹的评论:

我对希尔伯特不是很擅长。我的理解是离散版本只是连续版本的近似值。与导数相比,离散微分是一个完整的话题。

我们要建立一些样本数据并进行比赛吗?

信号音的频率是先验已知的,无需估计。


好吧,这比它应该花的时间要长得多。调试打印作为评论留下。

结果:

1 6 5 0.833333 0.770701 0.062633 0.955414 1.033058
 2 13 10 0.769231 0.770701 0.001470 2.070064 2.066116
 3 19 15 0.789474 0.770701 0.018773 3.025478 3.099174
 4 25 19 0.760000 0.770701 0.010701 3.980892 3.925620
 5 31 24 0.774194 0.770701 0.003493 4.936306 4.958678
 6 38 29 0.763158 0.770701 0.007543 6.050955 5.991736
 7 44 34 0.772727 0.770701 0.002027 7.006369 7.024793
 8 50 39 0.780000 0.770701 0.009299 7.961783 8.057851
 9 57 44 0.771930 0.770701 0.001229 9.076433 9.090909

已经花费了太多时间,代码将不得不自己说话。

[已编辑 - 如下所示]


评论 Dan 的解决方案太长,无法发表评论:

您可以通过将信号移动四分之一周期从余弦中得到正弦,而不是做希尔伯特。这也保留了适当的幅度,因此您得到一个圆形螺旋。然后你可以频移它:

$$ A_1 e^{i (\omega_1 n + \phi_1) } \cdot e^{i \Delta \omega n } = A_1 e^{i [(\omega_1 + \Delta \omega ) n + \phi_1 ]} $$

去年夏天我在一个 FMCW 项目中做到了这一点。

将另一个信号向另一个方向移动以生成“它本来的共轭”并相乘。

$$ A_1 e^{i [(\omega_1 + \Delta \omega ) n + \phi_1 ]} A_2 e^{-i (\omega_2 n + \phi_2) } = A_1 A_2 e^{i [(\omega_1 - \omega_2 + \Delta \omega ) n + ( \phi_1 - \phi_2)] } $$

$ \Delta \omega = \omega_2 - \omega_1 $你得到$ A_1 A_2 e^{i ( \phi_1 - \phi_2 )} $

您现在可以直接从 arg 读取相位差。您在信号上“延长时间”以使它们逐个样本匹配,因此您的样本不会实时匹配。因此,为了获得特定时间间隔的最佳读数,我会选择样本,以便较短的间隔以较长的间隔为中心。然后,您将希望逐点平均$\Delta \phi$读数以获得$\phi_1 - \phi_2$的单个值。仅在结果间隔内使用较短的内部居中间隔进行平均可能是有利的。


事实证明,有必要应用 off-bin 相位调整,以便在每帧的少量循环中获得相当准确的结果。增加 cpf 仍然会提高准确性,但会以延迟为代价。对于小于延迟的步长,重叠滑动窗口没有问题。

相位调整公式和推导可以在这里找到:

(顺便说一句,我有史以来最好的答案之一,但没有投票。)

以下是调整后的结果:

已选择 9 57 44

28.5 28.5 -1.88182802674e-14
22.0 22.0 -1.60982338571e-15

欧米茄 1.00050721452 1.29817878248

峰值和 Fs 9.0 9.07643312102 9.09090909091

 0 0.2006 1.1933 0.9927
 1 0.4977 1.4948 0.9971
 2 0.7956 1.7982 1.0026
 3 1.0950 2.1022 1.0072
 4 1.3962 2.4054 1.0093
 5 1.6987 2.7067 1.0081
 6 2.0017 -3.2775 -5.2792
 7 2.3041 -2.9805 -5.2846
 8 2.6050 -2.6845 -5.2895
 9 2.9042 -2.3880 -5.2922

故意不应用$2\pi$调整。

这是新代码。任何人都应该很容易进入他们自己的测试算法。单元注释应该是指导性的,即使对于非程序员也是如此。

将 numpy 导入为 np

#=================================================== ====================
定义主():

#---- 设置参数

        Fs1 = 157e6
        Fs2 = 121e6
        f = 25e6 # 输入信号频率

#---- 计算派生值

                          # = 每秒样本数/每秒周期数
        TheSamplesPerCycle1 = Fs1 / f
        theSamplesPerCycle2 = Fs2 / f

#---- 显示 M 和 N 组合

        Q_21 = Fs2 / Fs1

        对于范围内的 cpf (1, 10):
          N = int(theSamplesPerCycle1 * cpf + 0.5)
          M = int(theSamplesPerCycle2 * cpf + 0.5)

          Q_MN = 浮动(M)/浮动(N)

          E = abs(Q_MN - Q_21)

          k1 = float( N ) / theSamplesPerCycle1
          k2 = float( M ) / theSamplesPerCycle2

          打印“%2d %5d %5d %10.6f %10.6f %10.6f %10.6f %10.6f”%\
                 (cpf, N, M, Q_MN, Q_21, E, k1, k2)


        打印

#---- 确定 DFT 大小

        TheCyclesPerFrame = 9

        N = int(theSamplesPerCycle1 * theCyclesPerFrame + 0.5)
        M = int(theSamplesPerCycle2 * theCyclesPerFrame + 0.5)

        打印“选定”,theCyclesPerFrame,N,M
        打印

#---- 构建 DFT bin 的基向量

        C_N, S_N = BuildDftVectors( theCyclesPerFrame, N )
        C_M, S_M = BuildDftVectors( theCyclesPerFrame, M )

        打印 C_N.dot(C_N)、S_N.dot(S_N)、C_N.dot(S_N)
        打印 C_M.dot( C_M ), S_M.dot( S_M ), C_M.dot( S_M )
        打印

#---- 计算归一化频率

        # 每个样本的弧度 = 每个周期的弧度
        # / 每个周期的样本

        omega1 = 2.0 * np.pi / theSamplesPerCycle1
        omega2 = 2.0 * np.pi / theSamplesPerCycle2

        打印“欧米茄”,欧米茄1,欧米茄2
        打印

#---- 设置调整参数

        # 每帧周期 = 每帧样本数
        # / 每个周期的样本

        f1 = N / theSamplesPerCycle1
        p1 = 浮动( theCyclesPerFrame )

        f2 = M / theSamplesPerCycle2
        p2 = 浮动( theCyclesPerFrame )

        打印“峰值和 Fs”,p1,f1,f2
        打印

#---- 做一些跑步

        对于范围内的测试运行(10):
          theSignal1 = BuildSignal(1000, 1.1, omega1, 0.2 + 0.3 * theTestRun)
          theSignal2 = BuildSignal(1000, 1.2, omega2, 1.2 + 0.3 * theTestRun)

          RunTest_Cedron( theTestRun, theSignal1, theSignal2, \
                          欧米茄1,欧米茄2,Fs1,Fs2,\
                          f1, p1, f2, p2, \
                          C_N, S_N, C_M, S_M)

#=================================================== ====================
def BuildSignal(argSampleCount,argAmplitude,argOmega,argPhi):

        x = np.zeros(argSampleCount)

        对于范围内的 n(argSampleCount):
          x[n] = argAmplitude * np.cos( argOmega * n + argPhi )

        返回 x

#=================================================== ====================
def RunTest_Cedron(argTestRun,argSignal1,argSignal2,\
                    欧米茄1,欧米茄2,Fs1,Fs2,\
                    f1, p1, f2, p2, \
                    C_N, S_N, C_M, S_M):

        theInterval1 = argSignal1[0:len(C_N)]
        theInterval2 = argSignal2[0:len(C_M)]

        thePhase1 = FindPhaseOf(theInterval1, C_N, S_N, f1, p1 )
        thePhase2 = FindPhaseOf(theInterval2, C_M, S_M, f2, p2 )

        theDeltaPhase = thePhase2 - thePhase1

        # 样本 = 弧度 / 每个样本的弧度
# theShift1 = thePhase1 / omega1        
# theShift2 = thePhase2 / omega2

        # 秒 = 样本数/每秒样本数
        # theDelta1 = ( theShift1 / Fs1 ) * 1000000.0
# theDelta2 = ( theShift2 / Fs2 ) * 1000000.0
# theDiff = theDelta1 - theDelta2

        打印“%2d %7.4f %7.4f %7.4f”%\
              (argTestRun, thePhase1, thePhase2, theDeltaPhase)

        返回增量阶段

#=================================================== ====================
def FindPhaseOf(argInterval, C, S, f, p):

#---- 计算 DFT Bin 值

        实数 = argInterval.dot( C )
        imag = argInterval.dot( S )

        theBinPhase = np.arctan2( imag, real )

#---- 应用 Off-bin 相位逼近

        MN =浮动(len(C))

        theDeltaPhase = -( f - p ) * ( MN - 1.0 ) / MN * np.pi

#---- 返回 Bin 的角度

        返回 theBinPhase + theDeltaPhase

#=================================================== ====================
def BuildDftVectors(argCyclesPerFrame,argSamplesPerFrame):

        C = np.zeros(argSamplesPerFrame)
        S = np.zeros(argSamplesPerFrame)

        theSlice = 2.0 * np.pi / float(argSamplesPerFrame)

        theStep = argCyclesPerFrame * theSlice
        角度 = 0.0

        对于范围内的 n(argSamplesPerFrame):
          C[n] = np.cos(theAngle)
          S[n] = -np.sin(theAngle)
          theAngle += theStep

        返回 C, S

#=================================================== ====================
主要的()