【发布时间】:2014-10-03 03:42:31
【问题描述】:
我正在编写一个 python 包来将语音信号分解为其频谱谐波,以便它们中的每一个都可以表示为复指数。代码的(非常)简化描述如下:
# -*- coding: utf-8 -*-
import numpy as np
class HarmObj(object):
# Creates an instance for each harmonic.
def __init__(self, file_size):
self.mag = np.zeros((file_size))
self.phi = np.zeros((file_size))
self.freq = np.zeros((file_size))
class SignalObj(object):
# Creates an instance for the synthesized speech signal, which is formed by the
# harmonics.
def __init__(self, n_harm, file_size):
self.n_harm = n_harm
self.size = file_size
self.harmonics = [HarmObj(self.size) for i in xrange(self.n_harm)]
def update_values(self, a, freq, frame):
for harmonic in xrange(self.n_harm):
self.harmonics[harmonic].mag[frame] = np.abs(a[harmonic])
self.harmonics[harmonic].phi[frame] = np.angle(a[harmonic])
self.harmonics[harmonic].freq[frame] = freq[harmonic]
n_harm = 25
file_size = 100
signal = SignalObj(n_harm, file_size)
for frame in xrange(file_size):
#Nevermind this part, is just a simplification ;)
#----------------------------------------------
real_part = np.random.normal(0.0, 0.9, n_harm)
imag_part = np.random.normal(0.0, 0.9, n_harm)
a = real_part + 1j*imag_part
freq = np.random.normal(500.0, 200.0, n_harm)
#-----------------------------------------------
signal.update_values(a, freq, frame)
这个脚本运行没有问题。然而,由于在语音信号中谐波和帧的数量可能很大,因此由于SignalObj.update_values 方法中的for 循环,代码在计算上会有些繁重。
我相信像“numpy-array”这样的解决方案
def update_values(self, a, freq, frame):
self.harmonics[:].mag[frame] = np.abs(a[:])
self.harmonics[:].phi[frame] = np.angle(a[:])
self.harmonics[:].freq[frame] = freq[:]
会更快。但是上面的代码不适用于对象列表。 所以,我想知道是否有一种方法可以更改列表属性或创建我自己的结构,从而允许上述优化的值设置过程。
附言。 : 顺便说一句,逃避这个问题的一种可能的解决方案是丢弃HarmObj 类并将mag、phi 和freq 属性直接关联到SignalObj,即
class SignalObj(object):
def __init__(self, n_harm, file_size):
self.n_harm = n_harm
self.size = file_size
self.mag = np.zeros((n_harm, file_size))
self.phi = np.zeros((n_harm, file_size))
self.freq = np.zeros((n_harm, file_size))
def update_values(self, a, freq, frame):
self.mag[:, frame] = np.abs(a[:])
self.phi[:, frame] = np.angle(a[:])
self.freq[:, frame] = freq[:]
我在 MATLAB 版本中采用了这种解决方法,它确实更快。但是,由于 Python 更足智多谋,我想知道是否有更优雅和 Pythonic 的方式来完成这项工作;)。此外,将 HarmObj 实例分开将有助于我以后开始操作它们。
【问题讨论】:
-
HarmObj只是是三个 numpy 数组的容器 - 没有其他属性吗? -
我想在类中添加一个方法,它将采用三个 numpy 数组并生成合成的单个谐波。然后
SignalObj将对所有这些谐波求和并生成合成信号。 -
实际上,要生成谐波信号,我只需要幅度和相位。但是频率信号对于细化提取算法的结果是必要的。这个过程有助于提高最终合成信号的质量。
-
我不是专家,但我认为您在使用自定义数据类型时无法获得
numpy的性能。您必须确定HarmObj封装是否值得付出性能成本。如果合成/提取可以编写为 standalone 函数和 vectorized 那么您的解决方法可能是正确的方向 - 看来最终您将不得不遍历 @ 987654336@也是。SignalObj.harmonics(H) 可以表示为 (n_harm, 3, file_size) ndarray。每个谐波将是 H[n, :, :] 并且每个帧将是 H[:, :, n] -
是的,可能最好按照您的建议保留 H ndarray 并利用
numpy的性能。老实说,我不介意在整个合成/提取过程中直接使用 H ndarray。正如我所提到的,这就是我在使用 MATLAB 进行原型设计时所做的方式。但由于我想稍后与一些研究人员分享代码,我认为最终他们(也许我也是)想在未来的工作中操纵来自HarmObj的数据。所以我试图让它的访问更加“用户友好”。
标签: python list oop object speech