Python可以在圆圈或球体中显示拍频

时间:2017-09-28 08:02:10

标签: python-3.x matplotlib pyaudio pyopengl

这是科学问题和编程问题。

我想要发生的事情的形象 enter image description here

我使用pyaudio来创建20-20000 Hz的拍频。但现在我想想象这些频率。不是在一条线上,而是在一个圆圈中,甚至是一个更好的球体。有在线工具可以做前者,但不是后者。我对动态渲染而不是静态图像很感兴趣,我希望看到单个频率F1到Fn以及由此产生的拍频在屏幕上随时间和空间移动。

但是什么库可以做到这一点? matplotlib是静态的(根据下面的评论,它不是静态的。显然,我现在不知道我写的问题,你可以使用matplotlib制作动画。),那么可以使用什么库以及如何使用?或者Blender可以更轻松地做到这一点?

在matplotlib中我可以创建浮出水面的形状,但还没有想到根据拍频现象的物理属性使它们像高尔夫球一样颠簸。在matplotlib中我认为它会像X1,Y1 = F1和X2,Y2 = F2 :: X,Y = Fbeat但是还没弄明白该怎么做。

用于编写阅读文本的大脑的决策树。

1问题是否完全理解?是的,不是吗?

如果否: 写下答案让DrillBit更好地解释。

如果是:

2可以在matplotlib -how中完成吗?

如果是:

向DrillBit解释如果我知道它是如何在matplotlib中完成的。 否则停顿65小时然后喝咖啡。

如果否:

3可以在其他Python库或Blender中完成吗?

如果是:

4请向DrillBit解释如何完成或提示RTFM。拍拍自拍,与猫视频一起庆祝。

我创造了一个平坦的表面,没有来自"频率"
的颠簸 Flag surface, no bumps from "frequencies"

1 个答案:

答案 0 :(得分:0)

为了把我的帽子扔进戒指,我建议使用PyOpenGL(创建你的圆圈/球体并做甜蜜的实时2D / 3D图形)和PyQt的组合(来创建)一个OpenGL上下文,用于存放您的可视化以及为输入提供用户界面)。 请注意,如果您选择这条路线,虽然这将非常灵活,但请准备从头开始编写大量内容。您可能还可以查看这两个库的现有组合在@Jeronimo PyQtGraph的评论中提出,这可能更直截了当。

让我们从可视化技术退一步,并在数学上思考 我们将在屏幕上绘制它。从您的问题来看,您的目标似乎如下:

  

我希望在屏幕上看到单个频率F1到Fn以及产生的拍频在时间和空间中移动。

这有点模糊,你应该在你的问题中清除你期望绘制的内容。为了我自己的理智,让我们看一下具有可变半径的圆的“更简单”情况。设圆圈的radius r可以根据幅度+/- a而变化。这种变化可以向我们展示波形。从0到2 * pi弧度开始并逆时针绕圆圈的周长,我们可以模拟沿圆周的t0t1的时间范围。然后,我们可以实时增加t0(和t1)的值,从而改变我们的模拟值范围。

this demo一个问题,我看到只是“包裹”你的线并创建一个完美的ouroboros是在包装点会有不连续 ,除非你改变周长,以便它可以完全被你的拍频周期整除。

此外,我得到的结果(见下面的代码)看起来相当令人失望。为什么?增加时间会使圆圈旋转(将其视为我们的波只是沿着圆的表面传播)。无论如何,这是(凌乱)代码的样子;希望它能提供一些关于如何从头开始创建自己的可视化的想法:

from OpenGL.GL import *
from OpenGL.GLU import *
from PyQt4 import QtGui
from PyQt4.QtCore import QTimer
from PyQt4.QtGui import QColor, QStatusBar, QSizePolicy
from PyQt4.QtOpenGL import *
import math
import numpy as np
import sys
import time

class Waveform(object):
    """
    Defines a class Waveform where waves are of the form: y = sin(2*pi*f*t).
    """
    def __init__(self, frequency):
        self.f = frequency

    def calc_points(self, t0, t1, n):
        """
        Samples at n points from [t0, t1] and calculates the appropriate amplitude "a" value.
        Returns the data as a list of tuples.
        """
        data = []
        for i in range(n):
            frac = (t1 - t0)/(n - 1)
            t = i * frac + t0 
            a = math.sin(2 * math.pi * self.f * t)
            data.append((i, t, a))
        return data

class MainWindow(QtGui.QWidget):

    def __init__(self):
        super(MainWindow, self).__init__()
        self.widget = GLWidget(self)
        layout = QtGui.QVBoxLayout()
        layout.addWidget(self.widget)
        layout.setContentsMargins(5, 5, 5, 5)
        self.setLayout(layout)

class GLWidget(QGLWidget):

    def __init__(self, parent):
        QGLWidget.__init__(self, parent)
        self.setMinimumSize(800, 600)

        self.start_time = time.time()
        self.timer = QTimer()
        self.timer.timeout.connect(self.update)
        self.timer.start(1000/60)#so-called "60 fps"

    def initializeGL(self):
        glClearColor(0, 0, 0, 1)
        glClearDepth(1.0)
        glEnable(GL_DEPTH_TEST)

    def resizeGL(self, width, height):
        glViewport(0, 0, width, height)
        glMatrixMode(GL_PROJECTION)
        glLoadIdentity()
        glOrtho(0, width, 0, height, -1, 1)
        glMatrixMode(GL_MODELVIEW)
        glLoadIdentity()

    def paintGL(self):#Important part of the code (circle drawing stuff) here!
        curr_time = time.time()
        delta = (curr_time - self.start_time)
        t0, t1 = 0 + delta, 0.05 + delta
        f1 = 500
        f2 = 490
        num_slices = 1001
        radius = 200
        amplitude = 5
        a = Waveform(f1)
        b = Waveform(f2)
        data1 = a.calc_points(t0, t1, num_slices)
        data2 = b.calc_points(t0, t1, num_slices)

        w, h = self.width(), self.height()
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
        glBegin(GL_TRIANGLE_FAN)
        glColor(1.0, 0.0, 0.0, 1.0)
        glVertex3f(w/2.0, h/2.0, 0)
        for point in range(len(data1)):
            i1, p1, a1 = data1[point]
            i2, p2, a2 = data2[point]
            t = p1
            a = a1 + a2#adding the waveforms together
            frac = (t - t0)/(t1 - t0)
            angle = 2 * math.pi * frac
            r = radius + amplitude * a
            x = r * math.cos(angle) + (w/2)
            y = r * math.sin(angle) + (h/2)
            glVertex3f(x, y, 0)
        glEnd()

    def update(self):
        self.updateGL()#seems odd, but calling this causes a paintGL() call behind the scenes

if __name__ == '__main__':
    app = QtGui.QApplication(sys.argv)
    window = MainWindow()
    window.setWindowTitle("Beat Frequency App")
    window.show()
    app.exec_()