如何用C语言实现PCM编码

Python013

如何用C语言实现PCM编码,第1张

PCM 脉冲编码调制是Pulse Code Modulation的缩写。脉冲编码调制是数字通信的编码方式之一。主要过程是将话音、图像等模拟信号每隔一定时间进行取样,使其离散化,同时将抽样值按分层单位四舍五入取整量化,同时将抽样值按一组二进制码来表示抽样脉冲的幅值。

模拟信号数字化必须经过三个过程,即抽样、量化和编码,以实现话音数字化的脉冲编码调制(PCM,Pulse Coding Modulation)技术。

抽样(Sampling)

抽样是把模拟信号以其信号带宽2倍以上的频率提取样值,变为在时间轴上离散的抽样信号的过程。例如,话音信号带宽被限制在0.3~3.4kHz内,用 8kHz的抽样频率(fs),就可获得能取代原来连续话音信号的抽样信号。对一个正弦信号进行抽样获得的抽样信号是一个脉冲幅度调制(PAM)信号,如下图对模拟正弦信号的抽样所示。对抽样信号进行检波和平滑滤波,即可还原出原来的模拟信号。

量化(quantizing)

抽样信号虽然是时间轴上离散的信号,但仍然是模拟信号,其样值在一定的取值范围内,可有无限多个值。显然,对无限个样值一一给出数字码组来对应是不可能的。为了实现以数字码表示样值,必须采用“四舍五入”的方法把样值分级“取整”,使一定取值范围内的样值由无限多个值变为有限个值。这一过程称为量化。

量化后的抽样信号与量化前的抽样信号相比较,当然有所失真,且不再是模拟信号。这种量化失真在接收端还原模拟信号时表现为噪声,并称为量化噪声。量化噪声的大小取决于把样值分级“取整”的方式,分的级数越多,即量化级差或间隔越小,量化噪声也越小。

编码(Coding)

量化后的抽样信号在一定的取值范围内仅有有限个可取的样值,且信号正、负幅度分布的对称性使正、负样值的个数相等,正、负向的量化级对称分布。若将有限个 量化样值的绝对值从小到大依次排列,并对应地依次赋予一个十进制数字代码(例如,赋予样值0的十进制数字代码为0),在码前以“+”、“-”号为前缀,来 区分样值的正、负,则量化后的抽样信号就转化为按抽样时序排列的一串十进制数字码流,即十进制数字信号。简单高效的数据系统是二进制码系统,因此,应将十 进制数字代码变换成二进制编码。根据十进制数字代码的总个数,可以确定所需二进制编码的位数,即字长。这种把量化的抽样信号变换成给定字长的二进制码流的 过程称为编码。

例程:

#include <iostream>

using namespace std

int main()

{

 const int sect = 8       //number of segement.

 const int startingVol[sect+1] = {0,16,32,64,128,256,512,1024,2048}

        // the starting value of every segement.

 const int quanIntvl[sect] = {1,1,2,4,8,16,32,64} 

   //quantity interval of every Segments, 1 equeal to 1/2048.

 int pcmInd = 0         //pcm code's index.

 int pcmCode[sect] = {0,0,0,0,0,0,0,0}  // 8 bit of pcm codes.

 int sampleValue = 1270

 int startPoint //starting point of the segement starting piont

     //such as startingVol[startPoint] = 16 or 128  etc.

 int finePoint   //the starting point of inner segement code.

int quanValue // it's used to store the final quantity value. 

 int quanError //error caused by quantity.

//the following four variables is used in geting the segmentCode

 int low = 0

 

 int high = sect

 

 int mid

 int loopInd1 = 0     //loop index to get segment code

 int loopInd2 = 0   //loop index to get inner segment codes

//get the first_digit code of polarity

 (sampleValue > 0) ? (pcmCode[pcmInd++] = 1) : (pcmCode[pcmInd] = 0)

 

 sampleValue = abs(sampleValue)  //make sure the voltage is positive

    //get the segment code  using modified halve search

 while(loopInd1 < 3)  //only need 3 loops the segmentCode can be got 

 {

  mid = (low + high)/2  

   //after 3 loops, sampeValue falls in startingVol[mid] - startingVol[mid] or

    //in startingVol[mid-1] - startingVol[mid]

  if(sampleValue < startingVol[mid])

  {

   pcmCode[pcmInd++] = 0

   high = mid 

   startPoint = mid - 1 

  }

  else

  {

   pcmCode[pcmInd++] = 1

   low = mid

   startPoint = mid

  }

  loopInd1++

 }//end while

//get the last four bits codes of pcm 

 low = 0

 high = 16  //every segment is split into 16 small segments of the same size

 

 while(loopInd2 < 4)

 {

  mid = (low + high)/2

  

  //make the compare progress clear using the following two setences.

  quanValue = startingVol[startPoint] + mid * quanIntvl[startPoint]

  cout<<startingVol[startPoint]<<" + "<<quanIntvl[startPoint]<<" * "<<mid<<" = "

   <<quanValue <<" ? "<<sampleValue<<endl

     //make the compare progress clear using the above two setences.

  

  if(sampleValue < startingVol[startPoint] + mid * quanIntvl[startPoint])

  {

   pcmCode[pcmInd++] = 0

   high = mid

   finePoint = mid -1

  }

  else

  {

   pcmCode[pcmInd++] = 1

   low = mid

   finePoint = mid

  }

  loopInd2++

 }//end while

 quanValue = startingVol[startPoint] + finePoint * quanIntvl[startPoint]

 

 quanValue += quanIntvl[startPoint] / 2 //final quantity value.

 quanError = abs( sampleValue - quanValue) // error of quantity.

 cout<<"Final quantity value is: "<<quanValue<<endl

 cout<<"Error of quantity  is: "<<quanError<<endl

 cout<<"PCM codes are: "

for(int i = 0 i < 8 i++)

  

 {

  cout<<pcmCode[i]<<" "

 }//end for

 cout<<endl

return 0

}

1)去除异常(随机噪声)值按描述,估计采集的是缓变信号。如果是的话,可以采用均值法滤波:求前N-1次采集值的均值后,与最近一次采集值比较(求差值),如果差值超过一定范围,则丢弃;否则保留。2)判断递增递减比较理想的方法是利用最近采集的N点数据做样条函数y=x(t),可以是二次样条或三次样条,具体采用几次样条,同样要有被测信号特性决定。然后再对样条函数求导(dy/dt )即可判断出递增递减趋势。点数值N大于等4个比较合适

数学函数:fabs

原型:extern float fabs(float x)

用法:#include <math.h>

功能:求浮点数x的绝对值

说明:计算|x|, 当x不为负时返回x,否则返回-x

举例:

// fabs.c

#include <syslib.h>

#include <math.h>

main()

{

float x

clrscr()// clear screen

textmode(0x00)// 6 lines per LCD screen

x=-74.12

printf("|%f|=%f\n",x,fabs(x))

x=0

printf("|%f|=%f\n",x,fabs(x))

x=74.12

printf("|%f|=%f\n",x,fabs(x))

getchar()

return 0

}

扩展资料:

程序判数滤波 采样的信号,如因常受到随机干扰传感器不稳定而引起严重失真时,可以采用此方法。

方法是:根据生产经验确定两交采样允许的最大偏差△×,若先后两次采样的信号相减数值大于△×,表明输入的是干扰信号,应该去掉

用上次采样值作为本次采样值,若小于、等于△×表明没有受到干,本次采样值效。该方法适用于慢变化的物理参数的采样,如温度、物理位置等测量系统。

程序判断滤波的C程序函数如下:

float program_detect_filter(float old_new_value[], float X)

{

float sample_value

if (fabs(old_new_value[1]_old_new_value[0])>X)

sample_value=old_new_value[0]

else

sample_value=old_new_value[1]

retrun(sample_value)

}

函数调用需一个一维的两个元素的数组(old_new_value[2],用于存放上次采样值(old_new_value[0],)和本次采样值(old_new_value[1],),函数中sample_value表示有效采样值,X表示根据根据经验确定的两次采样允许的最大偏差△×。

参考资料来源:百度百科:fabs函数