主要实现了直角坐标和极坐标的相互转换,直角坐标的数据来源为我的博客python编程实现分帧数据的fft变换对分帧语音数据经fft变换之后的数据,数据为复数。将fft数据从直角坐标转为极坐标,同时也可以将极坐标数据转换为原始的直角坐标数据。
说明:本文程序使用pycharm编辑运行,均采用命令行方式运行,输入输出数据均保存在txt文件中
直角坐标转为极坐标,就是求幅度和相位,幅度通过复数的实部和虚部的平方和,再开方得到。相位为复数的虚部除以实部再求反正切,求出来的为幅度,需要转为角度的话,就乘以180/pi
。
极坐标:
幅度:
A m p l i t u d e = r e a l 2 + i m a g 2 Amplitude=\sqrt{real^{2}+imag^{2}} Amplitude=real2+imag2
相位:
θ = arctan i m a g r e a l \theta =\arctan \frac{imag}{real} θ=arctanrealimag
程序中设计了极坐标幅值和相位之间以"@"间隔和以空格间隔,需要手动调整。如下:
#Amplitude_and_angle = str(Amplitude) + '@' + str(angle) + '\n' #将幅度和相位数据中间加空格和@符号
Amplitude_and_angle = str(Amplitude) + ' ' + str(angle) + '\n' # 将幅度和相位数据中间加空格
主程序:
#对经fft变换的复数数据转换为极坐标形式
import numpy as np
import getopt
import sys
def main(argv):
try:
opts, args = getopt.getopt(sys.argv[1:], "-i:-o:-h", ["input=", "output=","help"])
except getopt.GetoptError:
print('将经过fft变换的音频数据,转换到极坐标')
print('python ffttxtpolar.py -i fft_test1.txt -o fft_test1_polar.txt')
sys.exit()
# 处理 返回值options是以元组为元素的列表。
for opt, arg in opts:
if opt in ("-h", "--help"):
print("将经过fft变换的音频数据,转换到极坐标")
print('输入格式为:')
print('python ffttxtpolar.py -i fft_test1.txt -o fft_test1_polar.txt')
print('此时幅度和相位以"@"间隔')
print('python ffttxtpolar.py -i fft_test1.txt -o fft_test1_polar1.txt')
print('此时幅度和相位以空格间隔')
sys.exit()
elif opt in ("-i", "--input"):
input = arg
elif opt in ("-o", "--output"):
output = arg
fft_data = np.loadtxt(input, dtype=np.complex) #加载数据文件,读入数据
fft_data_len = len(fft_data) # 输入数据长度
file = open(output, 'w+') #打开输出文件
for i in range(fft_data_len):
#复数实部和虚部的平方和,再开方就是极坐标的幅度
#Amplitude = np.abs(fft_data) # 调包求模,即幅度
#angle = np.rad2deg(np.angle(fft_data)) # 调包求相位,np.angle是求弧度,np.rad2deg将弧度转化为角度
data_real = np.real(fft_data[i]) #取复数的实部
data_imag = np.imag(fft_data[i]) #取复数的虚部
Amplitude = np.sqrt(data_real ** 2 + data_imag ** 2) #求幅度,即模
angle = np.arctan(data_imag / data_real )* (180 / np.pi) # 求相位,此时为角度
#Amplitude_and_angle = str(Amplitude) + '@' + str(angle) + '\n' #将幅度和相位数据中间加空格和@符号
Amplitude_and_angle = str(Amplitude) + ' ' + str(angle) + '\n' # 将幅度和相位数据中间加空格
file.write(Amplitude_and_angle) #将每行数据写入文件
file.close()
if __name__ == "__main__":
main(sys.argv) #调用函数
#python ffttxtpolar.py -i fft_test1.txt -o fft_test1_polar.txt
#python ffttxtpolar.py -i fft_test1.txt -o fft_test1_polar1.txt
python ffttxtpolar.py -h
结果:
将经过fft变换的音频数据,转换到极坐标
输入格式为:
python ffttxtpolar.py -i fft_test1.txt -o fft_test1_polar1.txt
此时幅度和相位以"@"间隔
python ffttxtpolar.py -i fft_test1.txt -o fft_test1_polar.txt
此时幅度和相位以空格间隔
极坐标幅度和相位以"@"间隔
运行:
python ffttxtpolar.py -i fft_test1.txt -o fft_test1_polar1.txt
运行结果:
极坐标幅度和相位以空格间隔
运行:
python ffttxtpolar.py -i fft_test1.txt -o fft_test1_polar1.txt
运行结果:
原始fft数据:
通过上面所述公式验算,结果正确。
极坐标转直角坐标,复数的实部就是用极坐标的幅度乘以cos(相位),复数的虚部就是用极坐标的幅度乘以sin(相位)。
复数的实部
c o m p l e x r e a l = ρ cos θ complexreal=\rho \cos \theta complexreal=ρcosθ
复数的虚部
c o m p l e x i m a g = ρ sin θ compleximag=\rho \sin \theta compleximag=ρsinθ
说明:极坐标转直角坐标的数据格式为幅度和相位之间以空格隔开,方便读取数据,数据格式如下:
#将极坐标数据,转换到直角坐标,还原为fft原始数据
import numpy as np
import getopt
import sys
def main(argv):
try:
opts, args = getopt.getopt(sys.argv[1:], "-i:-o:-h", ["input=", "output=","help"])#sys.argv[1:]为取命令行参数,从第二个参数开始取,因为第一个参数为程序名称
except getopt.GetoptError:
print('将极坐标数据,转换到直角坐标,还原为fft原始数据')
print('python polartxtfft.py -i fft_test1_polar.txt -o polar_test1_fft.txt')
sys.exit()
# 处理 返回值options是以元组为元素的列表。
for opt, arg in opts:
if opt in ("-h", "--help"):
print("将极坐标数据,转换到直角坐标,还原为fft原始数据")
print('输入格式为:')
print('python polartxtfft.py -i fft_test1_polar.txt -o polar_test1_fft.txt')
sys.exit()
elif opt in ("-i", "--input"):
input = arg
elif opt in ("-o", "--output"):
output = arg
polar_data = np.loadtxt(input, dtype=np.float) #加载数据文件,读入数据,数据类型为float,不能为short
polar_data_len = len(polar_data) # 输入数据长度
#m = (polar_data.T).ndim #判断数据是一维还是多维(对数据取转置,再判断维度,即判断输入数据列数)
file = open(output, 'w+') #打开输出文件
# 循环读取每行数据,将极坐标转为直角坐标,还原为fft原始数据
for i in range(polar_data_len):
Amplitude = polar_data[i,0] #取极坐标的幅值,即模
angle = polar_data[i,1] #取极坐标的角度,即相位
#print(Amplitude, angle)
angle = angle*(np.pi/180) #角度转弧度(因为下面cos函数计算时,是按照弧度计算的)
data_real = Amplitude*np.cos(angle) #计算实部
data_imag = Amplitude*np.sin(angle) #计算虚部
#如下判断语句主要用于判断复数的虚部是否大于零,从而判断虚部前是否需要加"+"号,因为负数前面不需要加"+"号
if(data_imag>0): #复数的虚部大于零,则虚部前加"+"号
complex_data = str(data_real) + '+' + str(data_imag) + 'j' + '\n' # 将幅度和相位数据中间加空格和@符号
elif(data_imag<0): #复数的虚部小于零,则虚部前不加"+"号
complex_data= str(data_real) + str(data_imag) + 'j' + '\n' #将幅度和相位数据中间加空格和@符号
else: #复数的虚部等于零,取绝对值后再在虚部前加"+"号
complex_data = str(data_real) + '+' + str(abs(data_imag)) + 'j' + '\n' # 将幅度和相位数据中间加空格和@符号
file.write(complex_data) #将每行数据写入文件
file.close()
if __name__ == "__main__":
main(sys.argv) #调用函数
#python polartxtfft.py -i fft_test1_polar.txt -o polar_test1_fft.txt
将极坐标数据,转换到直角坐标,还原为fft原始数据
输入格式为:
python polartxtfft.py -i fft_test1_polar.txt -o polar_test1_fft.txt
输入数据文件为极坐标数据,输出数据文件为还原的直角坐标数据。
python polartxtfft.py -i fft_test1_polar.txt -o polar_test1_fft.txt
结果:
原始fft数据:
通过对比还原的fft数据,和原始fft数据,发现只有小数部分,后面最小位数处有误差,这是因为计算精度问题,但可以看出结果正确。
此时,直角坐标转极坐标和极坐标转直角坐标已全部实现,且结果正确。
本文所有程序,文件下载:
链接:https://pan.baidu.com/s/1H09ZSMPHjWsEj8_tOn37pg
提取码:ma4r