Python - Осциллограф - PullRequest
0 голосов
/ 07 марта 2019

Я пытаюсь создать программу на python, которая может создавать осциллограф из живого звука (через микрофон)

Отличие от обычного осциллографа состоит в том, что он показывает только одну длину волны, например (желаемый результат):

Output Example

Это показывает три разных длины волны и то, как они будут отображаться в программе.

Мой прогресс такfar:

  1. Я создал программу, чтобы показать график, очистить и перерисовать его
  2. Затем я создал программу, которая будет отображать живой звук (хотя он очень медленный, который в идеале был бы исправлен, если это возможно)

Код # 1:

import matplotlib.pyplot as plt
import time

plt.ion()

#y1 is the data
y1 = [0,0.309,0.587,0.809,0.951,1,0.951,0.809,0.587,0.309,0, -0.309, -0.587, -0.809, -0.951, -1, -0.951, -0.809, -0.587, -0.309, 0]

plt.plot(y1, 'r.-') #Graph with data
plt.plot([0 for _ in y1]) #Straight line at y=0

while True:
    #Update data to new data
    #y1 = new data
    plt.plot(y1, 'r.-') #Graph with data
    plt.plot([0 for _ in y1]) #Straight line at y=0
    plt.draw()
    plt.pause(0.5) #Time for one wave? Need some way to find this...
    plt.clf()

Код # 2:

import pyaudio
import numpy as np
import matplotlib.pyplot as plt
import time

RATE = 44100
CHUNK = int(RATE/20) # RATE / number of updates per second

def soundplot(stream):
    t1=time.time()
    data = np.fromstring(stream.read(CHUNK),dtype=np.int16)
    plt.pause(0.1) #To draw graph!
    plt.clf()
    plt.plot(data)
    plt.draw()
    plt.axis([0,len(data),-2**16/2,2**16/2])
    print("took %.02f ms"%((time.time()-t1)*1000))

if __name__=="__main__":
    p=pyaudio.PyAudio()
    stream=p.open(format=pyaudio.paInt16,channels=1,rate=RATE,input=True,
                  frames_per_buffer=CHUNK)
    for i in range(int(20*RATE/CHUNK)): #do this for 10 seconds
        soundplot(stream)
    stream.stop_stream()
    stream.close()
    p.terminate()

Редактировать: Чтобы было ясноМой желаемый результат состоит в том, чтобы показать одну длину волны, как показано на рисунке, а не кратную, что дает второй код

1 Ответ

1 голос
/ 07 марта 2019

Чтобы показать одну длину волны, сначала сканируйте вперед во времени, пока не найдете неотрицательную точку данных. (Это произошло бы сразу, с самой первой записью, с данными в коде № 1.)

Затем продолжите сканирование вперед во времени и сохраните дельту между последовательными выборками. Первоначально дельта (или дискретная производная) будет положительной, когда кривая приближается к своему максимуму, затем станет отрицательной до достижения минимума, а затем снова станет положительной.

Прекратите сканирование вперед во время, когда вы встретите неотрицательную точку данных и дельта будет положительной. В этот момент у вас есть полная длина волны.

EDIT:

Если у вас много данных, тогда можно пропустить некоторые образцы данных преамбулы. Ключевым моментом здесь является то, что мы хотим найти пересечение нуля с положительной производной, а затем продолжать, пока не найдем еще одно пересечение нуля с положительной производной. Таким образом, это первое решение должно искать неотрицательную точку данных и настаивать на положительной дельте.

При наличии шума мы могли бы видеть изменения знака на дельте чаще, чем период сигнала. Таким образом, начальный шаг может заключаться в том, чтобы найти минимальные и максимальные значения для набора выборок (подразумевая диапазон), затем выбрать произвольные пороговые значения, такие как диапазон min + .25 * и диапазон min + .75 *, записать первое положительное пересечение нуля, подождать чтобы сигнал превысил верхний порог, подождите, пока он опустится ниже нижнего порога (после пересечения отрицательного нуля), затем запишите следующее положительное пересечение нуля. Это дает вам оценку длины волны. Сделайте повторные оценки, если вы находите это полезным, и возьмите некоторую удобную совокупность, такую ​​как среднее или (лучше) медиана.

Вооружившись оценкой длины волны, вы в лучшем положении, чтобы оценить, является ли пара положительных пересечений нуля «правильной» или из-за шума. Отклоните пары, которые находятся намного ближе друг к другу, чем можно предположить. Также может оказаться удобным вычислить сглаженную производную, поэтому вместо дельты последних двух видимых точек (K = 2) вы осредняете последние K точек, возможно, полдюжины из них. Функция усреднения - это фильтр нижних частот, который подавляет высокочастотный шум.

...