# 二次均衡器設計
相關文檔: [_數字信號系統_](filters.html)
用Traits.UI和Chaco制作的二次均衡器的設計工具,用戶可以任意添加二次濾波器,并且調整其中心頻率、增益和Q值,并即時查看組合之后的最終頻率響應。

```
# -*- coding: utf-8 -*-
import math
from enthought.traits.api import Float, HasTraits, List, Array, on_trait_change, Instance, Range, Button
from enthought.traits.ui.api import View, TableEditor, Item, Group, HGroup, VGroup, HSplit, ScrubberEditor, EnumEditor
from enthought.traits.ui.table_column import ObjectColumn
from enthought.chaco.api import Plot, AbstractPlotData, ArrayPlotData, VPlotContainer
from enthought.chaco.tools.api import PanTool, ZoomTool
from enthought.enable.api import Component, ComponentEditor
from enthought.pyface.api import FileDialog, OK
import pickle
import numpy as np
SAMPLING_RATE = 44100.0 # 取樣頻率
WORN = 1000 # 頻率響應曲線的點數
# 對數圓頻率數組
W = np.logspace(np.log10(10/SAMPLING_RATE*np.pi), np.log10(np.pi), WORN)
# 對數頻率數組
FREQS = W / 2 / np.pi * SAMPLING_RATE
# 候選頻率
EQ_FREQS = [20.0,25.2,31.7,40.0,50.4,63.5,80.0,100.8,
127.0,160.0,201.6,254.0,320.0,403.2,508.0,640.0,
806.3,1015.9,1280.0,1612.7,2031.9,2560.0,3225.4,
4063.7, 5120.0, 6450.8, 8127.5, 10240.0,12901.6,
16255.0,20480.0,]
def scrubber(inc):
'''創建不同增量的ScrubberEditor'''
return ScrubberEditor(
hover_color = 0xFFFFFF,
active_color = 0xA0CD9E,
border_color = 0x808080,
increment = inc
)
def myfreqz(b, a, w):
'''計算濾波器在w個點的頻率響應'''
zm1 = np.exp(-1j*w)
h = np.polyval(b[::-1], zm1) / np.polyval(a[::-1], zm1)
return h
def design_equalizer(freq, Q, gain, Fs):
'''設計二次均衡濾波器的系數'''
A = 10**(gain/40.0)
w0 = 2*math.pi*freq/Fs
alpha = math.sin(w0) / 2 / Q
b0 = 1 + alpha * A
b1 = -2*math.cos(w0)
b2 = 1 - alpha * A
a0 = 1 + alpha / A
a1 = -2*math.cos(w0)
a2 = 1 - alpha / A
return [b0/a0,b1/a0,b2/a0], [1.0, a1/a0, a2/a0]
class Equalizer(HasTraits):
freq = Range(10.0, SAMPLING_RATE/2, 1000)
Q = Range(0.1, 10.0, 1.0)
gain = Range(-24.0, 24.0, 0)
a = List(Float, [1.0,0.0,0.0])
b = List(Float, [1.0,0.0,0.0])
h = Array(dtype=np.complex, transient = True)
def __init__(self):
super(Equalizer, self).__init__()
self.design_parameter()
@on_trait_change("freq,Q,gain")
def design_parameter(self):
'''設計系數并計算頻率響應'''
try:
self.b, self.a = design_equalizer(self.freq, self.Q, self.gain, SAMPLING_RATE)
except:
self.b, self.a = [1.0,0.0,0.0], [1.0,0.0,0.0]
self.h = myfreqz(self.b, self.a, W)
def export_parameters(self, f):
'''輸出濾波器系數為C語言數組'''
tmp = self.b[0], self.b[1], self.b[2], self.a[1], self.a[2], self.freq, self.Q, self.gain
f.write("{%s,%s,%s,%s,%s}, // %s,%s,%s\n" % tmp)
class Equalizers(HasTraits):
eqs = List(Equalizer, [Equalizer()])
h = Array(dtype=np.complex, transient = True)
# Equalizer列表eqs的編輯器定義
table_editor = TableEditor(
columns = [
ObjectColumn(name="freq", width=0.4, style="readonly"),
ObjectColumn(name="Q", width=0.3, style="readonly"),
ObjectColumn(name="gain", width=0.3, style="readonly"),
],
deletable = True,
sortable = True,
auto_size = False,
show_toolbar = True,
edit_on_first_click = False,
orientation = 'vertical',
edit_view = View(
Group(
Item("freq", editor=EnumEditor(values=EQ_FREQS)),
Item("freq", editor=scrubber(1.0)),
Item("Q", editor=scrubber(0.01)),
Item("gain", editor=scrubber(0.1)),
show_border=True,
),
resizable = True
),
row_factory = Equalizer
)
view = View(
Item("eqs", show_label=False, editor=table_editor),
width = 0.25,
height = 0.5,
resizable = True
)
@on_trait_change("eqs.h")
def recalculate_h(self):
'''計算多組均衡器級聯時的頻率響應'''
try:
tmp = np.array([eq.h for eq in self.eqs if eq.h != None and len(eq.h) == len(W)])
self.h = np.prod(tmp, axis=0)
except:
pass
def export(self, path):
'''將均衡器的系數輸出為C語言文件'''
f = file(path, "w")
f.write("double EQ_PARS[][5] = {\n")
f.write("//b0,b1,b2,a0,a1 // frequency, Q, gain\n")
for eq in self.eqs:
eq.export_parameters(f)
f.write("};\n")
f.close()
class EqualizerDesigner(HasTraits):
'''均衡器設計器的主界面'''
equalizers = Instance(Equalizers)
# 保存繪圖數據的對象
plot_data = Instance(AbstractPlotData)
# 繪制波形圖的容器
container = Instance(Component)
plot_gain = Instance(Component)
plot_phase = Instance(Component)
save_button = Button("Save")
load_button = Button("Load")
export_button = Button("Export")
view = View(
VGroup(
HGroup(
Item("load_button"),
Item("save_button"),
Item("export_button"),
show_labels = False
),
HSplit(
VGroup(
Item("equalizers", style="custom", show_label=False),
show_border=True,
),
Item("container", editor=ComponentEditor(size=(800, 300)), show_label=False),
)
),
resizable = True,
width = 800,
height = 500,
title = u"Equalizer Designer"
)
def _create_plot(self, data, name, type="line"):
p = Plot(self.plot_data)
p.plot(data, name=name, title=name, type=type)
p.tools.append(PanTool(p))
zoom = ZoomTool(component=p, tool_mode="box", always_on=False)
p.overlays.append(zoom)
p.title = name
p.index_scale = "log"
return p
def __init__(self):
super(EqualizerDesigner, self).__init__()
self.plot_data = ArrayPlotData(f=FREQS, gain=[], phase=[])
self.plot_gain = self._create_plot(("f", "gain"), "Gain(dB)")
self.plot_phase = self._create_plot(("f", "phase"), "Phase(degree)")
self.container = VPlotContainer()
self.container.add( self.plot_phase )
self.container.add( self.plot_gain )
self.plot_gain.padding_bottom = 20
self.plot_phase.padding_top = 20
def _equalizers_default(self):
return Equalizers()
@on_trait_change("equalizers.h")
def redraw(self):
gain = 20*np.log10(np.abs(self.equalizers.h))
phase = np.angle(self.equalizers.h, deg=1)
self.plot_data.set_data("gain", gain)
self.plot_data.set_data("phase", phase)
def _save_button_fired(self):
dialog = FileDialog(action="save as", wildcard='EQ files (*.eq)|*.eq')
result = dialog.open()
if result == OK:
f = file(dialog.path, "wb")
pickle.dump( self.equalizers , f)
f.close()
def _load_button_fired(self):
dialog = FileDialog(action="open", wildcard='EQ files (*.eq)|*.eq')
result = dialog.open()
if result == OK:
f = file(dialog.path, "rb")
self.equalizers = pickle.load(f)
f.close()
def _export_button_fired(self):
dialog = FileDialog(action="save as", wildcard='c files (*.c)|*.c')
result = dialog.open()
if result == OK:
self.equalizers.export(dialog.path)
win = EqualizerDesigner()
win.configure_traits()
```
- 用Python做科學計算
- 軟件包的安裝和介紹
- NumPy-快速處理數據
- SciPy-數值計算庫
- matplotlib-繪制精美的圖表
- Traits-為Python添加類型定義
- TraitsUI-輕松制作用戶界面
- Chaco-交互式圖表
- TVTK-三維可視化數據
- Mayavi-更方便的可視化
- Visual-制作3D演示動畫
- OpenCV-圖像處理和計算機視覺
- Traits使用手冊
- 定義Traits
- Trait事件處理
- 設計自己的Trait編輯器
- Visual使用手冊
- 場景窗口
- 聲音的輸入輸出
- 數字信號系統
- FFT演示程序
- 頻域信號處理
- Ctypes和NumPy
- 自適應濾波器和NLMS模擬
- 單擺和雙擺模擬
- 分形與混沌
- 關于本書的編寫
- 最近更新
- 源程序集
- 三角波的FFT演示
- 在traitsUI中使用的matplotlib控件
- CSV文件數據圖形化工具
- NLMS算法的模擬測試
- 三維標量場觀察器
- 頻譜泄漏和hann窗
- FFT卷積的速度比較
- 二次均衡器設計
- 單擺擺動周期的計算
- 雙擺系統的動畫模擬
- 繪制Mandelbrot集合
- 迭代函數系統的分形
- 繪制L-System的分形圖