C语言地址:https://blog.csdn.net/qq_36407771/article/details/88798839
from PCM_Ui import *
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
from PyQt5.QtGui import *
import sys
import matplotlib.pyplot as plt
import numpy as np
import os
import math
TEMP_PATH = "temp.jpg" #缓冲图像
TIMES = 10 #周期10
SAVE_FILE_NAME = "PCM_Code.txt" #保存文件名字
class PCM(QDialog):
def __init__(self,ui,parent = None):
super().__init__(parent)
self._Qimg = QPixmap() #用于显示图片
self._old_Data = None #原波形
self._new_Data = None #采集得到的波形
self._old_time_s = 0 #周期
self._new_time_s = 0 #周期
self.HZ = 0 #原波形采集频率
self.Signal_HZ = 0 #原波形信号频率
self.process_HZ = 0 #新采集频率
self.__ui = ui #ui界面
self.code = None #PCM编码
self.__scaledImg = None #防止图片过大,缩放后的图片
self.__ui.setupUi(self) #给界面上控件
self.__ui.ImgLabel.setAlignment(Qt.AlignCenter) #设置对其方式:居中对齐
self.__ui.save_btn.setEnabled(False) #设置没有编码不能按保存编码
self.__ui.o_process_btn.clicked.connect(self._o_process) #产生原波形(Sin)
self.__ui.p_process_btn.clicked.connect(self._p_process) #根据采集频率得到新波形
self.__ui.PCM_btn.clicked.connect(self.PCM_Code) #计算新波形的PCM编码
self.__ui.save_btn.clicked.connect(self.saveCode) #保存编码
def _update(self): #更新界面(刷新图片)
self.__showGraph() #对图片的处理
if os.path.exists(TEMP_PATH): #缓存图片
self._Qimg.load(TEMP_PATH) #加载图片
if self._Qimg.size().width() > self.__ui.ImgLabel.size().width() and \
self._Qimg.size().height() > self.__ui.ImgLabel.size().height(): #图片过大则缩放图片
self.__scaledImg = self._Qimg.scaled(self.__ui.ImgLabel.size)
elif self._Qimg.size().width() > self.__ui.ImgLabel.size().width(): #根据宽缩放
self.__scaledImg = self._Qimg.scaledToWidth(self.__ui.ImgLabel.size().width())
elif self._Qimg.size().height() > self.__ui.ImgLabel.size().height(): #根据高缩放
self.__scaledImg = self._Qimg.scaledToHeight(self.__ui.ImgLabel.size().height())
else:
self.__scaledImg = self._Qimg.copy() #复制该图片信息
self.__ui.ImgLabel.setPixmap(self.__scaledImg) #给Label贴上图片
super().update() #调用父类的update函数
def _o_process(self):
try: #判断是否输入的是数字
self.HZ = int(self.__ui.o_setHz.text()) #得到采集频率
self.Signal_HZ = int(self.__ui.o_setSignalHz.text()) #得到信号频率
self._old_time_s = TIMES #周期
self._old_Data = np.sin(np.linspace(0, self.Signal_HZ * self._old_time_s * 2 * np.pi , self.HZ * self._old_time_s)) #产生正弦波
self._update() #刷新显示
except ValueError:
QMessageBox(QMessageBox.Critical,"error type!","Please input with number").exec_() #提醒需要输入数字
return
def _p_process(self):
try:
self.process_HZ = int(self.__ui.p_setHZ.text()) #得到采集频率
if self.process_HZ > self.HZ: #最大只能为该频率
self.process_HZ = self.HZ
self._new_time_s = TIMES #周期
self.__scanWave() #根据原音频信息得到新信息
self._update() #刷新显示
except ValueError:
QMessageBox(QMessageBox.Critical,"error type!","Please input with number").exec_() #提醒需要输入数字
return
def __showGraph(self): #显示波形信息图
plt.clf() #清除原图像
Graphnum = 3 if self._old_time_s != 0 and self._new_time_s != 0 \
else 1 #设置显示图的个数
if self._new_time_s != 0: #得到对应采集频率的横坐标点集合
new_time = np.arange(0,self.process_HZ * self._new_time_s)*(1.0 / self.process_HZ)
if self._old_time_s != 0: #得到对应采集频率的横坐标点集合
old_time = np.arange(0,self.HZ * self._old_time_s)*(1.0 / self.HZ)
if self._old_time_s != 0:
plt.subplot(Graphnum,1,1) #设置图片个数,排版方式
plt.plot(old_time,self._old_Data) #根据两个x,y集合,显示对应的数据
plt.xlabel("Time(s)") #x轴注释
plt.ylabel("Amplitude") #y轴注释
plt.title("original wavedata") #图像注释
if self._new_time_s != 0: #如果存在被采集,显示采集点
plt.scatter(new_time,self._new_Data,color= "black")
plt.grid('on') #标尺,on:有,off:无。
if self._new_time_s != 0:
plt.subplot(Graphnum,1,3) #设置图片个数,排版方式
plt.plot(new_time,self._new_Data) #根据两个x,y集合,显示对应的数据
plt.xlabel("Time(s)") #x轴注释
plt.ylabel("Amplitude") #y轴注释
plt.title("sampled wavedata") #图像注释
plt.grid('on') #标尺,on:有,off:无。
plt.savefig(TEMP_PATH)
def __scanWave(self):
K = self.HZ / self.process_HZ #频率比例
newframes = int(self._old_Data.shape[0] / K) #新采集点个数
self._new_Data = np.zeros((newframes,)) #创建对应的集合
for x in range(newframes):
self._new_Data[x] = self._old_Data[int(x * K)] #在对应的波形数据上获取采集的数据
def saveCode(self):
path = QFileDialog().getSaveFileName(self, "Save File", SAVE_FILE_NAME, "TEXT (*.txt)") #打开保存文件对话框
if len(path[0]) != 0:
f = open(path[0],'w') #打开文件
for x in self.code:
f.write(str(x.tostring())) #按行写入文件(字节)
f.close() #关闭文件
def PCM_Code(self):
if self._new_time_s == 0: #如果没有采集,提示采集
QMessageBox(QMessageBox.Information,"no data","Please sample the original waveform!").exec_()
return
self.changeCode() #十三折线换算
self.toPCM_Code() #转换为PCM编码
self.__ui.save_btn.setEnabled(True)
def changeCode(self):
self.code = np.zeros((self._new_Data.shape[0],))
for i,x in enumerate(self._new_Data):
f = 1 if x>= 0 else -1
d = abs(x)
y = 0
""" 十三折线换算法"""
if d>=0 and d<0.015625:
y=16*d
elif d>=0.015625 and d<0.03125:
y=d*8+0.125
elif d>=0.03125 and d<0.0625:
y=4*d+0.25
elif d>=0.0625 and d<0.125:
y=2*d+0.375
elif d>=0.125 and d<0.25:
y=d+0.5
elif d>=0.25 and d<0.5:
y=0.5*d+5/8.00
elif d>=0.5 and d<=1:
y=0.25*d+3/4.00
self.code[i] = y * f #存储换算后的值
def toPCM_Code(self):
z = [0,16,32,64,128,256,512,1024] #对应量化区间
y = [1,1,2,4,8,16,32,64] #每个量化区间按16等分后的每一小段量化等级
code_list = [] #存储PCM编码
for i,x in enumerate(self._new_Data):
g = x * 2048 #2048个量化等级
e = math.floor(g) #低位取整
code = np.zeros((8,),dtype=int) #存储编码
if e < 0: #符号位判断,小于0第一位码为0,大于0第一位码为1
code[0] = 0
e = abs(e)
else:
code[0] = 1
if e > 128: #段落码第一位判断
code[1] = 1
if e <= 32 or (e>=128 and e<= 512): #段落码第二位判断
code[2] = 0
else:
code[2] = 1
if (e>=16 and e<32) or (e>=64 and e< 128) or(e>=256 and e<=512) or e>=1024:
code[3] = 1 #段落码第三位判断
h = code[1] * 4 + code[2] * 2 + code[3] #根据段落码算出在第几段
k = int((e - z[h]) / y[h]) #算出在段内第几段
if k == 0: #输入为0,输出也为0
code[4],code[5],code[6],code[7] = 0,0,0,0
else:
num = 7 #从高位开始编码
while(k>0):
code[num] = k%2 #取余编码
num -= 1
k = int(k/2) #0
代码+UI
链接:https://pan.baidu.com/s/17GtG9b5OEtczVnoR0s1SHA
提取码:65np