如何用C语言实现PCM编码

如何用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、G.711是一种由国际电信联盟(ITU-T)订定音频编码方式,又称为ITU-T G.711.目前G.711有两个编码方式,A-law以及Mu-law.G711A是其中一种编码方式.

2、例程:

/*

 * g711.c

 *

 * u-law, A-law and linear PCM conversions.

 */

#define SIGN_BIT (0x80)  /* Sign bit for a A-law byte. */

#define QUANT_MASK (0xf)  /* Quantization field mask. */

#define NSEGS  (8)  /* Number of A-law segments. */

#define SEG_SHIFT (4)  /* Left shift for segment number. */

#define SEG_MASK (0x70)  /* Segment field mask. */

static short seg_end[8] = {0xFF, 0x1FF, 0x3FF, 0x7FF,

       0xFFF, 0x1FFF, 0x3FFF, 0x7FFF}

/* copy from CCITT G.711 specifications */

unsigned char _u2a[128] = {   /* u- to A-law conversions */

 1, 1, 2, 2, 3, 3, 4, 4,

 5, 5, 6, 6, 7, 7, 8, 8,

 9, 10, 11, 12, 13, 14, 15, 16,

 17, 18, 19, 20, 21, 22, 23, 24,

 25, 27, 29, 31, 33, 34, 35, 36,

 37, 38, 39, 40, 41, 42, 43, 44,

 46, 48, 49, 50, 51, 52, 53, 54,

 55, 56, 57, 58, 59, 60, 61, 62,

 64, 65, 66, 67, 68, 69, 70, 71,

 72, 73, 74, 75, 76, 77, 78, 79,

 81, 82, 83, 84, 85, 86, 87, 88,

 89, 90, 91, 92, 93, 94, 95, 96,

 97, 98, 99, 100, 101, 102, 103, 罩竖纤104,

 105, 106, 107, 108, 109, 110, 111, 112,

 113, 114, 115, 116, 117, 118, 119, 120,

 121, 122, 123, 124, 125, 126, 127, 128}

unsigned char _a2u[128] = {   /* A- to u-law conversions */

 1, 3, 5, 7, 9, 11, 13, 15,

 16, 17, 18, 19, 20, 21, 22, 23,

 24, 25, 26, 27, 28, 29, 30, 31,

 32, 32, 33, 33, 34, 34, 35, 35,

 36, 37, 38, 39, 40, 41, 42, 43,

 44, 45, 46, 47, 48, 48, 49, 49,

 50, 51, 52, 53, 54, 55, 56, 57,

 58, 59, 60, 61, 62, 63, 64, 64,

 65, 66, 67, 68, 69, 70, 71, 72,

 73, 74, 75, 76, 77, 78, 79, 79,

 80, 81, 82, 83, 84, 85, 86, 87,

 88, 89, 90, 91, 92, 93, 94, 95,

 96, 97, 98, 99, 100, 101, 102, 103,

 104, 105, 106, 107, 108, 109, 110, 111,

 112, 113, 114, 115, 116, 117, 118, 119,

 120, 121, 122, 123, 124, 125, 126, 127}

static int

search(

 int  val,

 short  *table,

 int  size)

{

 int  i

 for (i = 0 i < size i++) {

  if (val <= *table++)

   return (i)

 }

 return (size)

}

/*

 纤码* linear2alaw() - Convert a 16-bit linear PCM value to 物仿8-bit A-law

 *

 * linear2alaw() accepts an 16-bit integer and encodes it as A-law data.

 *

 *  Linear Input Code Compressed Code

 * ------------------------ ---------------

 * 0000000wxyza   000wxyz

 * 0000001wxyza   001wxyz

 * 000001wxyzab   010wxyz

 * 00001wxyzabc   011wxyz

 * 0001wxyzabcd   100wxyz

 * 001wxyzabcde   101wxyz

 * 01wxyzabcdef   110wxyz

 * 1wxyzabcdefg   111wxyz

 *

 * For further information see John C. Bellamy's Digital Telephony, 1982,

 * John Wiley & Sons, pps 98-111 and 472-476.

 */

unsigned char

linear2alaw(

 int  pcm_val) /* 2's complement (16-bit range) */

{

 int  mask

 int  seg

 unsigned char aval

 if (pcm_val >= 0) {

  mask = 0xD5  /* sign (7th) bit = 1 */

 } else {

  mask = 0x55  /* sign bit = 0 */

  pcm_val = -pcm_val - 8

 }

 /* Convert the scaled magnitude to segment number. */

 seg = search(pcm_val, seg_end, 8)

 /* Combine the sign, segment, and quantization bits. */

 if (seg >= 8)  /* out of range, return maximum value. */

  return (0x7F ^ mask)

 else {

  aval = seg << SEG_SHIFT

  if (seg < 2)

   aval |= (pcm_val >> 4) & QUANT_MASK

  else

   aval |= (pcm_val >> (seg + 3)) & QUANT_MASK

  return (aval ^ mask)

 }

}

/*

 * alaw2linear() - Convert an A-law value to 16-bit linear PCM

 *

 */

int

alaw2linear(

 unsigned char a_val)

{

 int  t

 int  seg

 a_val ^= 0x55

 t = (a_val & QUANT_MASK) << 4

 seg = ((unsigned)a_val & SEG_MASK) >> SEG_SHIFT

 switch (seg) {

 case 0:

  t += 8

  break

 case 1:

  t += 0x108

  break

 default:

  t += 0x108

  t <<= seg - 1

 }

 return ((a_val & SIGN_BIT) ? t : -t)

}

#define BIAS  (0x84)  /* Bias for linear code. */

/*

 * linear2ulaw() - Convert a linear PCM value to u-law

 *

 * In order to simplify the encoding process, the original linear magnitude

 * is biased by adding 33 which shifts the encoding range from (0 - 8158) to

 * (33 - 8191). The result can be seen in the following encoding table:

 *

 * Biased Linear Input Code Compressed Code

 * ------------------------ ---------------

 * 00000001wxyza   000wxyz

 * 0000001wxyzab   001wxyz

 * 000001wxyzabc   010wxyz

 * 00001wxyzabcd   011wxyz

 * 0001wxyzabcde   100wxyz

 * 001wxyzabcdef   101wxyz

 * 01wxyzabcdefg   110wxyz

 * 1wxyzabcdefgh   111wxyz

 *

 * Each biased linear code has a leading 1 which identifies the segment

 * number. The value of the segment number is equal to 7 minus the number

 * of leading 0's. The quantization interval is directly available as the

 * four bits wxyz.  * The trailing bits (a - h) are ignored.

 *

 * Ordinarily the complement of the resulting code word is used for

 * transmission, and so the code word is complemented before it is returned.

 *

 * For further information see John C. Bellamy's Digital Telephony, 1982,

 * John Wiley & Sons, pps 98-111 and 472-476.

 */

unsigned char

linear2ulaw(

 int  pcm_val) /* 2's complement (16-bit range) */

{

 int  mask

 int  seg

 unsigned char uval

 /* Get the sign and the magnitude of the value. */

 if (pcm_val < 0) {

  pcm_val = BIAS - pcm_val

  mask = 0x7F

 } else {

  pcm_val += BIAS

  mask = 0xFF

 }

 /* Convert the scaled magnitude to segment number. */

 seg = search(pcm_val, seg_end, 8)

 /*

  * Combine the sign, segment, quantization bits

  * and complement the code word.

  */

 if (seg >= 8)  /* out of range, return maximum value. */

  return (0x7F ^ mask)

 else {

  uval = (seg << 4) | ((pcm_val >> (seg + 3)) & 0xF)

  return (uval ^ mask)

 }

}

/*

 * ulaw2linear() - Convert a u-law value to 16-bit linear PCM

 *

 * First, a biased linear code is derived from the code word. An unbiased

 * output can then be obtained by subtracting 33 from the biased code.

 *

 * Note that this function expects to be passed the complement of the

 * original code word. This is in keeping with ISDN conventions.

 */

int

ulaw2linear(

 unsigned char u_val)

{

 int  t

 /* Complement to obtain normal u-law value. */

 u_val = ~u_val

 /*

  * Extract and bias the quantization bits. Then

  * shift up by the segment number and subtract out the bias.

  */

 t = ((u_val & QUANT_MASK) << 3) + BIAS

 t <<= ((unsigned)u_val & SEG_MASK) >> SEG_SHIFT

 return ((u_val & SIGN_BIT) ? (BIAS - t) : (t - BIAS))

}

/* A-law to u-law conversion */

unsigned char

alaw2ulaw(

 unsigned char aval)

{

 aval &= 0xff

 return ((aval & 0x80) ? (0xFF ^ _a2u[aval ^ 0xD5]) :

     (0x7F ^ _a2u[aval ^ 0x55]))

}

/* u-law to A-law conversion */

unsigned char

ulaw2alaw(

 unsigned char uval)

{

 uval &= 0xff

 return ((uval & 0x80) ? (0xD5 ^ (_u2a[0xFF ^ uval] - 1)) :

     (0x55 ^ (_u2a[0x7F ^ uval] - 1)))

}

#include <stdio.h>

#include <conio.h>

int trans(int n)

{

int r=0

if(n<0)

{

r=r|0x80

n=-n

}

if(n<橡告=16)

{

r=r|0x00

}

else if(n<=32)

{

r=r|0x10

}

else if(n<=64)

{

r=r|0x20

}

else if(n<=128)

{

r=r|0x30

}

else if(n<=256)

{

r=r|0x40

}

else if(n<=512)

{

r=r|0x50

}

else if(n<=1024)

{

r=r|0x60

}

else if(n<=2046)

{

r=r|0x70

}

else

{

return 0

}

r=r|(n&0x0f)

return r

}

main()

{

int n,r,i

printf("输入一个10进制(1-2048):")

scanf("%d",&n)

if(n>=1 &&n<薯缓=2048)

{

r=trans(n)

printf("8位2进制为:")

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

{

printf("%c",((r>>梁手明(8-i-1))&0x01)+'0')

}

printf("\n")

}

else

{

printf("输入错误!\n")

}

}


欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/yw/12489326.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2023-05-25
下一篇 2023-05-25

发表评论

登录后才能评论

评论列表(0条)

保存