【发布时间】:2012-01-08 02:44:52
【问题描述】:
我或多或少是一个 Python 新手,正在研究这个 evolutionary Mona Lisa 实验的音频模拟。
以下代码旨在:
- 将给定的 .wav 文件读入 NumPy 数组。
- 检测波形中的“零交叉”,即当数组元素改变符号时。在这些点将数组拆分为波形“块”的嵌套列表。
- 将正面与负面块分开,然后打乱这些块并将它们重新组合成一个 NumPy 数组,正负交替。我不能使用 random.shuffle(),因为列表有超过 2000 个元素。
- 比较洗牌数组的“适应度” 与原始样本,定义为差的平方 在打乱后的数组和原始样本之间。
最终,我将添加复制、变异和选择,但现在我的适应度函数存在问题。拆分、混洗和重组后的数组与原始输入的维度不同,导致以下错误:
$ ValueError: operands could not be broadcast together with shapes (1273382) (1138213)
每次运行程序时,第二个数组的尺寸都会有所不同,但始终在 1138000-1145000 左右。在拆分、洗牌和重组步骤中,我似乎丢失了一些块,我怀疑我在第 3 步的某个地方错误地使用了列表推导,但我不太清楚在哪里或为什么。出了什么问题?
# Import scipy audio tools, numpy, and randomization tools
import scipy
from scipy.io import wavfile
import numpy
from random import shuffle, randint
# Read a wav file data array, detect zero crossings, split at zero crossings, and return a nested list.
def process_wav(input):
# Assign the wavefile data array to a variable.
wavdata = input[1]
# Detect zero crossings, i.e. changes in sign in the waveform data. The line below returns an array of the indices of elements after which a zero crossing occurs.
zerocrossings = numpy.where(numpy.diff(numpy.sign(wavdata)))[0]
# Increment each element in the array by one. Otherwise, the indices are off.
zerocrossings = numpy.add(numpy.ones(zerocrossings.size, zerocrossings.dtype), zerocrossings)
wavdatalist = wavdata.tolist()
zerocrossingslist = zerocrossings.tolist()
# Split the list at zero crossings. The function below splits a list at the given indices.
def partition(alist, indices):
return [alist[i:j] for i, j in zip([0]+indices, indices+[None])]
return partition(wavdatalist, zerocrossingslist)
# Accept a list as input, separate into positive and negative chunks, shuffle, and return a shuffled nested list
def shuffle_wav(list):
# Separate waveform chunks into positive and negative lists.
positivechunks = []
negativechunks = []
for chunk in list:
if chunk[0] < 0:
negativechunks.append(chunk)
elif chunk[0] > 0:
positivechunks.append(chunk)
elif chunk[0] == 0:
positivechunks.append(chunk)
# Shuffle the chunks and append them to a list, alternating positive with negative.
shuffledchunks = []
while len(positivechunks) >= 0 and len(negativechunks) > 0:
currentpositivechunk = positivechunks.pop(randint(0, len(positivechunks)-1))
shuffledchunks.append(currentpositivechunk)
currentnegativechunk = negativechunks.pop(randint(0, len(negativechunks)-1))
shuffledchunks.append(currentnegativechunk)
return [chunk for sublist in shuffledchunks for chunk in sublist]
def get_fitness(array, target):
return numpy.square(numpy.subtract(target, array))
# Read a sample wav file. The wavfile function returns a tuple of the file's sample rate and data as a numpy array, to be passed to the process_wav() function.
input = scipy.io.wavfile.read('sample.wav')
wavchunks = process_wav(input)
shuffledlist = shuffle_wav(wavchunks)
output = numpy.array(shuffledlist, dtype='int16')
print get_fitness(output, input[1])
scipy.io.wavfile.write('output.wav', 44100, output)
编辑:这是完整的回溯:
Traceback (most recent call last):
File "evowav.py", line 64, in <module>
print get_fitness(output, input[1])
File "evowav.py", line 56, in get_fitness
return numpy.square(numpy.subtract(target, array))
ValueError: operands could not be broadcast together with shapes (1273382) (1136678)`
【问题讨论】:
-
请始终包含 COMPLETE 回溯,否则我们无能为力,因为我们只是猜测应该发生什么或为什么会发生。
-
抱歉。我在上面添加了完整的回溯。
-
您是否有指向您正在使用的 .wav 文件的链接,以便我们重现它?
-
基本问题似乎在于洗牌逻辑。如果输入列表中正和负块的数量不同,则输出中总是会丢失一个块。这会导致输入和输出的大小不同,从而导致您看到的失败。
-
@ecmendenhall - 另外,没有必要使用
numpy.square(numpy.subtract(target, array))之类的东西。使用(target - array)**2更加pythonic(并且完全等价)同样,zerocrossings = numpy.add(numpy.ones(zerocrossings.size, zerocrossings.dtype), zerocrossings)等价于zerocrossings += 1。 (实际上后者效率稍高一些,因为它会就地修改数组。)