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")
}
}
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)