Matlab 到 Python 代码转换:二进制相移键控 (BPSK)

Matlab to Python code conversion: Binary phase-shift keying (BPSK)

我有这个 MATLAB 代码:

d=[1 0 1 1 0]; % Data sequence
b=2*d-1; % Convert unipolar to bipolar
T=1; % Bit duration
Eb=T/2; % This will result in unit amplitude waveforms
fc=3/T; % Carrier frequency
t=linspace(0,5,1000); % discrete time sequence between 0 and 5*T (1000 samples)
N=length(t); % Number of samples
Nsb=N/length(d); % Number of samples per bit
dd=repmat(d',1,Nsb); % replicate each bit Nsb times
bb=repmat(b',1,Nsb); dw=dd'; % Transpose the rows and columns
dw=dw(:)'; 
% Convert dw to a column vector (colum by column) and convert to a row vector
bw=bb';
bw=bw(:)'; % Data sequence samples
w=sqrt(2*Eb/T)*cos(2*pi*fc*t); % carrier waveform
bpsk_w=bw.*w; % modulated waveform

% plotting commands follow

subplot(4,1,1);
plot(t,dw); axis([0 5 -1.5 1.5])

subplot(4,1,2);
plot(t,bw); axis([0 5 -1.5 1.5])

subplot(4,1,3);
plot(t,w); axis([0 5 -1.5 1.5])

subplot(4,1,4);
plot(t,bpsk_w,'.'); axis([0 5 -1.5 1.5])
xlabel('time')

这给了我如下所示的图表:

下面是我使用 Numpy 转换的 Python 代码 / Scipy

import numpy as np
import scipy
import matplotlib.pylab as plt
plt.clf()
plt.close('all')

d = np.array(np.hstack((1, 0, 1, 1, 0)))
b = 2*d-1.
T = 1
Eb = T/2
fc = 3/T
t = np.linspace(0, 5, 1000)
N = t.shape
Nsb = np.divide(N, d.shape)
dd = np.tile(d.conj().T, Nsb)
bb = np.tile(b.conj().T, Nsb)
dw = dd.conj().T
dw = dw.flatten(0).conj()
bw = bb.conj().T
bw = bw.flatten(0).conj()
w = np.dot(np.sqrt(np.divide(2*Eb, T)), np.cos(np.dot(np.dot(2*np.pi, fc), t)))
bpsk_w = bw*w
plt.subplot(4, 1, 1)
plt.plot(t, dw)
plt.axis(np.array(np.hstack((0, 5, -1.5, 1.5))))
plt.subplot(4, 1, 2)
plt.plot(t, bw)
plt.axis(np.array(np.hstack((0, 5, -1.5, 1.5))))
plt.subplot(4, 1, 3)
plt.plot(t, w)
plt.axis(np.array(np.hstack((0, 5, -1.5, 1.5))))
plt.subplot(4, 1, 4)
plt.plot(t, bpsk_w, '.')
plt.axis(np.array(np.hstack((0, 5, -1.5, 1.5))))
plt.xlabel('time')
plt.show()

但是我既没有收到错误也没有得到正确的输出:

请告诉我迁移此代码的错误在哪里?

=====更新======

当我更改 Python 代码以使用以下行时,我得到了更好的输出:

..............
b = 2.*d-1.
T = 1.
Eb = T/2.
fc = 3./T
...............
w = np.dot(np.sqrt(np.divide(2.*Eb, T)), np.cos(np.dot(np.dot(2.*np.pi, fc), t)))
.............

您的问题源于使用 np.tile 而不是 np.repeat

举个简单的例子说明两者的区别:

>>> a = np.arange(3)
>>> a
array([0, 1, 2])
>>> np.repeat(a, 4)
array([0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2])
>>> np.tile(a, 4)
array([0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2])

所以基本上 tile 接受一个 "tiling array" 并将其连接起来,类似于铺瓷砖厨房地板的方式,而 repeat 将向量中的每个元素重复指定数量在获取该向量的下一个元素之前的次数。

现在,利用这些知识,您可以重写 matlab 示例并得到以下结果:

from __future__ import division

import numpy as np
import scipy
import matplotlib.pylab as plt

unipolar_arr = np.array([1, 0, 1, 1, 0])
bipolar = 2*unipolar_arr - 1
bit_duration = 1
amplitude_scaling_factor = bit_duration/2  # This will result in unit amplitude waveforms
freq = 3/bit_duration  # carrier frequency
n_samples = 1000
time = np.linspace(0, 5, n_samples)

samples_per_bit = n_samples/unipolar_arr.size  # no need for np.divide. Also, use size rather than shape if you want something similar to Matlab's "length"
# 1. Use repeat rather than tile (read the docs)
# 2. No need for conjugate transpose
dd = np.repeat(unipolar_arr, samples_per_bit)  # replicate each bit Nsb times
bb = np.repeat(bipolar, samples_per_bit)  # Transpose the rows and columns
dw = dd
# no idea why this is here
#dw = dw.flatten(0).conj()
bw = bb  # one again, no need for conjugate transpose
# no idea why this is here
#bw = bw.flatten(0).conj()
waveform = np.sqrt(2*amplitude_scaling_factor/bit_duration) * np.cos(2*np.pi * freq * time)  # no need for np.dot to perform scalar-scalar multiplication or scalar-array multiplication
bpsk_w = bw*waveform

f, ax = plt.subplots(4,1, sharex=True, sharey=True, squeeze=True)
ax[0].plot(time, dw)
ax[1].plot(time, bw)
ax[2].plot(time, waveform)
ax[3].plot(time, bpsk_w, '.')
ax[0].axis([0, 5, -1.5, 1.5])
ax[0].set_xlabel('time')
plt.show()

我添加了更多评论以显示根本不需要的内容(如此混乱,您向我们展示的代码是由转换程序以某种方式生成的吗?)并冒昧地更改了您的大部分 1-2字符变量名变成更易读的东西,这只是我的一个烦恼。

此外,在 Python2.x 中,整数除法是默认值,因此 5/2 将计算为 2,而不是 2.5。在 Python3.x 中,这已得到改善,通过使用 from __future__ import division 行,您也可以在 Python2.x 中获得该行为。