连续可变斜率增量调制(CVSD)浅析

本文首先简单介绍了CVSD,然后简单说明了CVSD示例代码,最后给出了一个CVSD应用的实例。

1. CVSD简介

我们看到,所有的有线的或无线的语音通信都已经或者即将数字化。语音通过数字化进行传输或存储比传统的模拟方法有明显的优势。在数字通信或存储系统里,信息以二进制数的形式传送——接收方只需要确定接收信号是0是1即可完全恢复出原信息。在数字语音系统中,信息就是语音。衡量数字语音编码算法性能的参数是精确量化语音信号、并在传送后解码器还原语音的能力。换句话说,原始模拟语音信号必须能够在接收端被精确还原。然而,没有压缩量化的语音所占用带宽比原始模拟信号大许多。在无线或有线电信应用中,语音占用300—3300Hz的带宽。如果带内模拟信号经过抽样速率为奈奎斯特速率的线性模数转换,例如8kHz,进行8bit的256阶量化,得到的数据比特率是64kbps。没有引入编解码,得到的数字信号的带宽接近原始信号的20倍。

语音编码领域的工程师已经研究出许多减少编码后语音信号带宽的编解码方法。早期的算法试图利用人耳的动态适应性来进行编码。人耳对语音信号有或多或少的敏感性—人耳可以听到声压0dB到120dB的声音,人耳听觉动态范围约40dB。换句话说,我们很难听到摇滚音乐会上人们的细语。有一些语音编码算法利用了这种现象,使用较长码字对出现几率小的幅度范围的信号进行编码,而用较短码字对常见幅度范围的信号编码。这就是常用的非均匀量化。非均匀量化被用在PSTN网络中时,被称为律脉冲编码调制。一个更加复杂的方法是利用临近采样值之间的强相关性,只对样值的差值做编码。在相同的信号质量要求下,这种差值信号所需要的量化电平少了许多,因此降低了对带宽的要求。利用这种技术的算法都属于差分编码(DPCM)这一类。进一步的带宽节省可以通过更加复杂的算法实现。例如,结合自适应量化的DPCM是最常用的编码算法——ADPCM。

DeltaM(DM)和连续可变斜率增量调制(CVSD)都是差分波形量化技术。它们都采用了两级量化(1bit)。CVSD是带有自适应量化器的基本DM。对DM量化器使用自适应技术可以连续调整量化步长。通过调整量化步长,编码器可以高准确度地展现出小幅度信号,而不用牺牲大信号性能。

CVSD适用于同时对语音质量和安全性有要求的场合。MIL-STD-188-113 和Federal Standard 1023都是使用CVSD的例子。


1.1 差分量化

差分量化是一种当前样值与当前预测值之差作为下一时刻量化输入的编码方式。这种量化优势在于信号差量的动态范围要比不经过处理的输入信号动态范围小。因此,在相同SNR输出情况下需要较少的量化等级。或者,在相同的量化等级内,差量信号充分使用可用带宽编码可以得到更好的信号质量。

图5框图表示了一个差分量化系统。用时域上的离散信号x(n)x(n)表示原信号x(t)x(t)。注意到解码器在编码器的反馈回路里。因此,解码器是编码器的逆过程。标记为QQ的模块把差分信号d(n)d(n)转换成二进制形式,以适合传输。模块Q−1Q−1并没有进行逆过程。事实上,从d(n)d(n)到c(n)c(n)的转化再到dpd(n)dpd(n)是差分编码非理想的一个很重要的因素。尽管如此,这个系统的基础研究可以假设不存在QQ和Q−1Q−1而被简化。有了这个假设,编码器传导函数的zz域表示为:

HENC(z)=C(z)X(z)=Q(z)[1−P(z)](16)(16)HENC(z)=C(z)X(z)=Q(z)[1−P(z)]

解码器传导函数为:

HENC(z)=XQD(z)C(z)=1Q(z)[1−P(z)](17)(17)HENC(z)=XQD(z)C(z)=1Q(z)[1−P(z)]

如果DQD(z)≅D(z)DQD(z)≅D(z),则XQD(z)≅X(z)XQD(z)≅X(z),整个系统的传导函数可以写成:

H(z)=HENC(z)HDEC(z)=1(18)(18)H(z)=HENC(z)HDEC(z)=1

尽管公式(18)是基于一些假设的,但它体现了一个图5所示的结构构成的差分量化系统方案可以大致的还原信号。这个接近程度的好坏就是区分不同差分量化方案的依据。一般的,高质量的接近是需要付出代价的。

差分量化的一个关键因素是预测器P(z)P(z)。P(z)P(z)的输出xp(n)xp(n)是前面时刻输入信号样值的加权总和。一般表达式等效于一个FIR滤波器

xp(n)=∑k=1pakxQ(n−k)(19)(19)xp(n)=∑k=1pakxQ(n−k)

其中,P=预测器阶数
akak=加权系数
xp(n)xp(n)=预测器输出
xQ(n)=dQ(n) xp(n)xQ(n)=dQ(n)xp(n)预测器输入

zz域预测器的传导函数

P(z)=Xp(z)Xq(z)=∑k=0pakZ−k(20)(20)P(z)=Xp(z)Xq(z)=∑k=0pakZ−k

公式(19)和(20)说明了预测器输出是过去输入的线性组合,因此得名“线性预测器”。非线性预测器也有人研究,但考虑到其复杂度和稳定性等问题,使用较少。

差分量化编码器存在这不稳定性。如前边提到的,公式(20)是一种FIR滤波器。FIR最重要的性质之一就是稳定(传导函数只有零点)。然而,当FIR被放在反馈回路里时,编码器就是这样,零点就变成极点了——如果有一个极点在单位圆外,差分量化器就不稳定了。


1.2 差分调制

DM是两阶量化的差分编码方案。每个采样值用1bit表示,采样率等于比特率。因此,采样率直接关系到信噪比SNR。同时,输入信号的带宽和限带输出都是决定信号质量的重要因素。

DM算法最初于1946年产生。在过去的50年里,两种算法:线性DM(LDM)和CVSD因其有效处理数字语音信号而备受关注。LDM是最基础的最小复杂度的一种DM。因此,这里把LDM当作理解较复杂的DM算法的基础来解释。CVSD算法被定为战术级标准,在点对点的无线应用中越来越多的被使用,这里也会介绍。


1.2.1 线性DM

LDM的线性预测器P(z)P(z)是一阶的,量化器是两电平的。图6是描述LDM编解码算法的框图。

预测器是一个单抽头的FIR滤波器,传导特性为P(z)=az−1P(z)=az−1。编码器中,dQ(n)dQ(n)到xp(n)xp(n)的传导函数可以表示成zz域形式:

Xp(n)Dq(z)=az−11−az−1(21)(21)Xp(n)Dq(z)=az−11−az−1

解码器中,d_{QD}(n)到x_{QD}(n)的传导函数可以表示成zz域形式:

XQD(n)DQD(z)=11−az−1(22)(22)XQD(n)DQD(z)=11−az−1

公式(21)和(22)表示离散时间积分器(如果a=1a=1)。如果a<1a<1,就变成阻尼积分器了。McDonald 和 Noll 都建议a=1a=1为最适增益。一个纯积分器(a=1a=1)会使比特误码率比扩散更长,因此实际上还是推荐a<1a<1。

图6中的量化器QQ就像一个比较器。当输入d(n)超过0输出逻辑1,反之输出逻辑0。因此,QQ的输出是单比特的,表示了d(n)d(n)幅度的符号。反量化器Q−1Q−1把0、1逻辑翻译成增量dQ(n)dQ(n),如下表所示

增量ΔΔ的值对LDM的性能起了非常重要的作用。如果ΔΔ比较小,可以跟踪细微变化,小信号可以很好的被还原出来,但对变化快的或是突发信号的捕捉能力很差。如果DM不能跟上输入信号变化,这种现象叫做斜率过载,如图7所示。

增大ΔΔ可以减小斜率过载带来的影响,但同时也产生一个问题:粒状噪声(granular noise)。随着ΔΔ变大,小信号量化的电平不够细致,从而还原出来像信道的噪声,如图8。理想信道方案只是一系列的0、1序列表示输入信号是否在变化。由于0、1交替的图样均值为0,因此解码器输出信号为0。


1.2.2 CVSD

通过对量化步长ΔΔ做动态调整可以很大程度上减小粒状噪声和斜率过载。自适应DM(ADM)算法就是这样一种尝试,这种算法在信号变化缓慢时采用较小ΔΔ,而在信号变化剧烈是采用较大ΔΔ。使用最广泛的ADM算法是CVSD。它是1970年由Greefkes 和 Riemens提出的。他们的CVSD算法中,ΔΔ的自适应调整基于之前的3个或4个采样输出值(即,c(n),c(n−1),c(n−2),c(n−3)c(n),c(n−1),c(n−2),c(n−3))。图9和图10分别表示了这种算法编码器和解码器的流程。注意这里只利用了过去的3个采样c(n)c(n)。

前面图6中出现过的模块Q−1Q−1被两个级联的延迟一个采样周期z−1z−1的延迟器替代,用来确定是否出现了三个连0或连1。最小和最大步长分别用ΔminΔmin和ΔmaxΔmax表示。如果很长一段时间内没有连0或连1出现,积分器I2I2输出衰减到0附近,算法就等效于LDM了。I2I2和I1I1的时间常数典型值分别为4ms和1ms。在CVSD的文献中,积分器I1I1称为理论积分器,I2I2称为音节积分器。所谓的音节积分器是因音节长度而得名。事实上,一个音节大概持续100ms,但是,音调变化却在10ms量级上。因此,4ms更适合CVSD音节时间常数。标号为L的模块作用是单电平转换(例如,c(n)=1c(n)=1,L输出1;c(n)=0c(n)=0,L输出-1) 。这种CVSD算法也被称为数字控制DM。

图11画出了积分器I1I1的输出(编码器的xp(n)xp(n)和解码器的xpd(n)xpd(n))。与图7和图8相比,斜率过载和粒状噪声有所改善。


1.2.3 总结

CVSD的特性很适合语音数字编码。由于采用1bit量化,避免了复杂的帧结构。有很好的检测误码和纠错的性能。其他的语音编码方案则需要有数字信号处理器和外部模数数模转换器来对模拟信号进行数字转换。整个CVSD编解码算法,包括了输入输出滤波器,可以继承在单硅片里。尽管结构简单,CVSD却有足够的复杂度用来在安全应用领域进行数字加密。最后,CVSD可以在很宽的速率范围内工作——CVSD已经被成功的应用于9.6kbps—64kbps。在9.6kbps音频质量不是特别的好,但是不影响理解。在24kbps到48kbps,语音质量已经很容易接受。高于48kbps时,性能达到了Toll Quality的级别。

Toll Quality

MOS值达到4到4.5的认为是Toll Quality,还不错(等效于商用电信水平)。通信质量MOS值一般在3到4(仅仅是有可以忍受的失真,不影响理解)。

图13比较了律PCM(标准Toll Quality)、CVSD和ADPCM算法的MOS值。注意到CVSD的性能在当前误比特率条件下等于或好于律PCM和ADPCM。特别是,当误比特率增加到1%时,CVSD仍然可以维持很好的MOS值,误比特率增加到10%时,MOS也可以达到3(通信质量)。恰是这种突发的比特误码使CVSD成为了许多无线语音通信应用的理想选择。

所有这些特点是CVSD吸引了无线通信系统(如数字无线电话,数字陆地移动无线广播)设计者。设防领域已经在有线或无线系统中使用CVSD许多年了。最近,美国联邦标准1023提出将25kHz的 CVSD用于工作在30MHz以上的无线广播信道。图14显示了CVSD编解码器在数字移动广播系统中的应用。


2. CVSD代码示例

2.1 初始化程序

#define MAX_CHAN 1 //编码的通道数short min_step=10; //设定的最小量阶short max_step=1280; //设定的最大量阶double step_decay=0.9990234375; //I2的衰减因子double accum_decay= 0.96875; //I1的衰减因子int K=32;int J=4; //出现连续4个1后调整量阶short pos_accum_max=32767; //c(n)的最大正值short neg_accum_max=-32767; //c(n)的最小负值void cvsd_coder_init(void ){ int i; for(i = 0; i < MAX_CHAN ; i ) { encoder.d_min_step[i] = min_step; encoder.d_max_step[i] = max_step; encoder.d_step_decay[i] = step_decay; encoder.d_accum_decay[i] = accum_decay; encoder.d_K[i] = K; encoder.d_J[i] = J; encoder.d_pos_accum_max[i] = pos_accum_max; encoder.d_neg_accum_max[i] = neg_accum_max; encoder.d_accum[i] = 0; encoder.d_loop_counter[i] = 1; encoder.d_runner[i] = 0; encoder.d_stepsize[i] = min_step; decoder.d_min_step[i] = min_step; decoder.d_max_step[i] = max_step; decoder.d_step_decay[i] = step_decay; decoder.d_accum_decay[i] = accum_decay; decoder.d_K[i] = K; decoder.d_J[i] = J; decoder.d_pos_accum_max[i] = pos_accum_max; decoder.d_neg_accum_max[i] = neg_accum_max; decoder.d_accum[i] = 0; decoder.d_loop_counter[i] = 1; decoder.d_runner[i] = 0; decoder.d_runner_mask[i] = 0; decoder.d_stepsize[i] = min_step; }}

  • 1

  • 2

  • 3

  • 4

  • 5

  • 6

  • 7

  • 8

  • 9

  • 10

  • 11

  • 12

  • 13

  • 14

  • 15

  • 16

  • 17

  • 18

  • 19

  • 20

  • 21

  • 22

  • 23

  • 24

  • 25

  • 26

  • 27

  • 28

  • 29

  • 30

  • 31

  • 32

  • 33

  • 34

  • 35

  • 36

  • 37

  • 38

  • 39

  • 40

  • 41

  • 42

  • 43

  • 44

  • 45

  • 1

  • 2

  • 3

  • 4

  • 5

  • 6

  • 7

  • 8

  • 9

  • 10

  • 11

  • 12

  • 13

  • 14

  • 15

  • 16

  • 17

  • 18

  • 19

  • 20

  • 21

  • 22

  • 23

  • 24

  • 25

  • 26

  • 27

  • 28

  • 29

  • 30

  • 31

  • 32

  • 33

  • 34

  • 35

  • 36

  • 37

  • 38

  • 39

  • 40

  • 41

  • 42

  • 43

  • 44

  • 45

2.2 编码程序

CVSD通过不断改变量阶δδ大小来跟踪信号的变化,以减小颗粒噪声和斜率过载失真,量阶δδ调整是基于过去的3个或4个样值输出。

int cvsd_encoder (int ch,int noutput_items,                const short * input_items,                 unsigned char * output_items){  const short *in = &input_items[0];  unsigned char *out =  &output_items[0];  int i=0;       // 2 bytes, 0 .. 65,535  unsigned char output_bit=0;    // 1 byte, 0 .. 255  unsigned char output_byte=0;   // 1 bytes 0.255  unsigned char bit_count=0;         // 1 byte, 0 .. 255  unsigned int mask=0;       // 4 bytes, 0 .. 4,294,967,295  // Loop through each input data point  for(i = 0; i < noutput_items*8; i  ) {    // 当前值与计分器的输出作比较    if((int)in[i] >= encoder.d_accum[ch]) {    // Note:  sign((data(n)-accum))      output_bit=1;    }    else {      output_bit=0;    }    // Update Accum (i.e. the reference value)    // 如果大于积分器输出,积分器输出增大,反之减小    if (output_bit) {      encoder.d_accum[ch]=encoder.d_accum[ch] encoder.d_stepsize[ch];    }    else {      encoder.d_accum[ch]=encoder.d_accum[ch]-encoder.d_stepsize[ch];    }    // Multiply by Accum_Decay    // 乘上衰减因子    encoder.d_accum[ch]=(cvsd_round(encoder.d_accum[ch]*encoder.d_accum_decay[ch]));    // Check for overflow    if (encoder.d_accum[ch] >= ((int)encoder.d_pos_accum_max[ch])) {      encoder.d_accum[ch] = (int)encoder.d_pos_accum_max[ch];    }    else if(encoder.d_accum[ch] <= ((int) encoder.d_neg_accum_max[ch])) {      encoder.d_accum[ch] = (int) encoder.d_neg_accum_max[ch];    }    // Update runner with the last output bit    // Update Step Size    // 如果已经处理了超过4个bit,则开始检查是否有连续的1或0,有的话调整Step Size,调整过程中注意不要超过Step Size的值域    if (encoder.d_loop_counter[ch] >= encoder.d_J[ch]) {     // Run this only if you have >= J bits in your shift register      mask=(cvsd_pow(2, encoder.d_J[ch]) - 1);      if ((cvsd_bitwise_sum(encoder.d_runner[ch] & mask) >= encoder.d_J[ch])       || (cvsd_bitwise_sum((~encoder.d_runner[ch]) & mask) >= encoder.d_J[ch]))       {        if(cvsd_bitwise_sum(encoder.d_runner[ch] & mask) >= encoder.d_J[ch])          encoder.d_stepsize[ch] = min( (short)(encoder.d_stepsize[ch]                                    encoder.d_min_step[ch]), encoder.d_max_step[ch]);        else          encoder.d_stepsize[ch] = max( (short)(encoder.d_stepsize[ch]                                  - encoder.d_min_step[ch]), encoder.d_min_step[ch]);      }      else {// No runs of 1s and 0s        encoder.d_stepsize[ch] = max( (short)cvsd_round((encoder.d_stepsize[ch]-encoder.d_min_step[ch])*encoder.d_step_decay[ch]), encoder.d_min_step[ch]);           }    }    // Runner is a shift-register; shift left, add on newest output bit    encoder.d_runner[ch] = (encoder.d_runner[ch]<<1) | ((unsigned int) output_bit);    // Update the ouput type; shift left, add on newest output bit    // If you have put in 8 bits, output it as a byte    output_byte = (output_byte<<1) | output_bit;    bit_count  ;    if (encoder.d_loop_counter[ch] <= encoder.d_K[ch]) {      encoder.d_loop_counter[ch]  ;    }    // If you have put 8 bits, output and clear.    // 8bit作为单个数据输出    if (bit_count==8) {      // Read in short from the file      *(out  ) = output_byte;      // Reset the bit_count      bit_count=0;      output_byte=0;    }  } // While  return noutput_items;}12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394951234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495

2.3 解码程序

译码是对收到的数字编码进行判断,每收到一个“1”码就使积分器输出上升一个δδ值,每收到一个“0”码就使积分器输出下降一个δδ值,连续收到“1”码(或“0”码)就使输出一直上升(或下降),这样就可以近似地恢复输入信号。

intcvsd_decoder(int ch ,int noutput_items, unsigned char * input_items, unsigned short * output_items){ const unsigned char *in = &input_items[0]; short *out = &output_items[0]; int i=0; short output_short=0; // 2 bytes 0 .. 65,535 unsigned char bit_count=0; // 1 byte, 0 .. 255 unsigned int mask=0; // 4 bytes, 0 .. 4,294,967,295 unsigned char input_byte=0; // 1 bytes unsigned char input_bit=0; // 1 byte, 0 .. 255 // Loop through each input data point for(i = 0; i < noutput_items/8.0; i ) { input_byte = in[i]; // Initiliaze bit counter bit_count=0; // 每次处理一个字节内的1bit while(bit_count<8) { // Compute the Appropriate Mask mask=cvsd_pow(2,7-bit_count); // Pull off the corresponding bit input_bit = input_byte & mask; // Update the bit counter bit_count ; // Update runner with the next input bit // Runner is a shift-register; shift left, add on newest output bit decoder.d_runner[ch] = (decoder.d_runner[ch]<<1) | ((unsigned int) input_bit); // Run this only if you have >= J bits in your shift register if (decoder.d_loop_counter[ch]>=decoder.d_J[ch]) { // Update Step Size // 如果已经处理了超过4个bit,则开始检查是否有连续的1或0,有的话调整Step Size,调整过程中注意不要超过Step Size的值域 decoder.d_runner_mask[ch]=(cvsd_pow(2,decoder.d_J[ch])-1); if ((cvsd_bitwise_sum(decoder.d_runner[ch] & decoder.d_runner_mask[ch])>=decoder.d_J[ch])||(cvsd_bitwise_sum((~decoder.d_runner[ch]) & decoder.d_runner_mask[ch])>=decoder.d_J[ch])) { if (cvsd_bitwise_sum(decoder.d_runner[ch] & decoder.d_runner_mask[ch])>=decoder.d_J[ch]) decoder.d_stepsize[ch] = min( (short) (decoder.d_stepsize[ch] decoder.d_min_step[ch]), decoder.d_max_step[ch]); else decoder.d_stepsize[ch] = max( (short) (decoder.d_stepsize[ch] - decoder.d_min_step[ch]), decoder.d_min_step[ch]); } else { // No runs of 1s and 0s decoder.d_stepsize[ch] = max( (short) cvsd_round(decoder.d_stepsize[ch]*decoder.d_step_decay[ch]), decoder.d_min_step[ch]); } } // Update Accum (i.e. the reference value) if (input_bit) { decoder.d_accum[ch]=decoder.d_accum[ch] decoder.d_stepsize[ch]; } else { decoder.d_accum[ch]=decoder.d_accum[ch]-decoder.d_stepsize[ch]; } // Multiply by Accum_Decay decoder.d_accum[ch]=(cvsd_round(decoder.d_accum[ch]*decoder.d_accum_decay[ch])); // Check for overflow if (decoder.d_accum[ch] >=((int) decoder.d_pos_accum_max[ch])) { decoder.d_accum[ch]=(int)decoder.d_pos_accum_max[ch]; } else if (decoder.d_accum[ch] <=((int) decoder.d_neg_accum_max[ch])) { decoder.d_accum[ch]=(int)decoder.d_neg_accum_max[ch]; } // Find the output short to write to the file output_short=((short) decoder.d_accum[ch]); if (decoder.d_loop_counter[ch] <= decoder.d_K[ch]) { decoder.d_loop_counter[ch] ; } *(out ) = output_short; } // while () } // for() return noutput_items;}

  • 1

  • 2

  • 3

  • 4

  • 5

  • 6

  • 7

  • 8

  • 9

  • 10

  • 11

  • 12

  • 13

  • 14

  • 15

  • 16

  • 17

  • 18

  • 19

  • 20

  • 21

  • 22

  • 23

  • 24

  • 25

  • 26

  • 27

  • 28

  • 29

  • 30

  • 31

  • 32

  • 33

  • 34

  • 35

  • 36

  • 37

  • 38

  • 39

  • 40

  • 41

  • 42

  • 43

  • 44

  • 45

  • 46

  • 47

  • 48

  • 49

  • 50

  • 51

  • 52

  • 53

  • 54

  • 55

  • 56

  • 57

  • 58

  • 59

  • 60

  • 61

  • 62

  • 63

  • 64

  • 65

  • 66

  • 67

  • 68

  • 69

  • 70

  • 71

  • 72

  • 73

  • 74

  • 75

  • 76

  • 77

  • 78

  • 79

  • 80

  • 81

  • 82

  • 83

  • 84

  • 85

  • 86

  • 87

  • 88

  • 89

  • 90

  • 1

  • 2

  • 3

  • 4

  • 5

  • 6

  • 7

  • 8

  • 9

  • 10

  • 11

  • 12

  • 13

  • 14

  • 15

  • 16

  • 17

  • 18

  • 19

  • 20

  • 21

  • 22

  • 23

  • 24

  • 25

  • 26

  • 27

  • 28

  • 29

  • 30

  • 31

  • 32

  • 33

  • 34

  • 35

  • 36

  • 37

  • 38

  • 39

  • 40

  • 41

  • 42

  • 43

  • 44

  • 45

  • 46

  • 47

  • 48

  • 49

  • 50

  • 51

  • 52

  • 53

  • 54

  • 55

  • 56

  • 57

  • 58

  • 59

  • 60

  • 61

  • 62

  • 63

  • 64

  • 65

  • 66

  • 67

  • 68

  • 69

  • 70

  • 71

  • 72

  • 73

  • 74

  • 75

  • 76

  • 77

  • 78

  • 79

  • 80

  • 81

  • 82

  • 83

  • 84

  • 85

  • 86

  • 87

  • 88

  • 89

  • 90


3. CVSD应用实例

基于嵌入式系统的CVSD语音编解码器的实现

4. 参考文献

1. 译文-连续可变斜率增量调制
2. Continuously Variable Slope Delta Modulation (CVSD)
3. CVSD 的 算 法 、仿 真 及 实现
4. CVSD


(0)

相关推荐

  • 【以拆会友】拆解一台4通道记录仪

    应饺神要求,拆解一台AD工业的PowerLab4/25 四通道记录仪,设备为四通道16bit 100K记录仪,主要用于医疗记录生理电位信息,可以用于心电图等,相对高速记录仪来讲应该是比较慢了.废话就不 ...

  • 【学术论文】基于FPGA的LVDS高可靠性传输优化设计

    摘要: 针对LVDS高速链路传输过程中出现的误码及传输距离较短问题,分别从硬件和逻辑编码方面提出各自优化方案.硬件方面在LVDS发送端增加高速驱动器,接收端增加自适应线缆均衡器,可补偿信号在长距离传输 ...

  • 丰田direct shift CVT连续可变变速箱

    最近很多朋友买车换车考虑丰田的车型,从卡罗拉.雷凌.RAV4到凯美瑞.亚洲龙.问起小星到底丰田的CVT变速箱怎么样,有什么优点.甚至一些专业的朋友对比试了不同品牌的CVT车型后发现丰田的CVT不管怎么 ...

  • [科普]CVT连续可变变速箱

    朋友问起到底CVT变速箱是什么变速箱,它的工作原理是什么样的.看来是时候让小星来科普一下啦.随着小星一起来了解一下吧. CVT变速箱的全称是Continuously Variable Transmis ...

  • 连续油管氮气气举排液技术浅析(全文)

    [摘 要]连续油管液氮气举工艺技术通过连续油管与液氮泵车.液氮罐车或现场制氮设备相配合,形成压裂与快速返排工艺技术的整合配套.在文古 3 井现场应用,取得良好效果.该工艺排液速度快,施工安全,可控制排 ...

  • 印度过去2周全国检测阳性率达21%:连续3日新增病例超40万例

    快科技      2021年5月8日      10:31 印度是目前全球疫情最严重的国家,没有之一. 过去24小时,印度新增新冠肺炎确诊病例超过41.4万例,再次达到疫情以来印度国内,以及全球范围内 ...

  • ​浅析农贸市场设计改造与动态线路规划的重要性

    浅析农贸市场设计改造与动态线路规划的重要性 现代农贸市场的日常运作,动态线路设计必须保持稳定发展的首要因素.完善合理的动态线路规划,不仅能反映进入市场时的客货供应情况,而且对引导顾客的购物趋势也有很大 ...

  • MLOps具有模型单元测试的连续交付

    在本系列文章中,我们将引导您完成将CI/CD应用于AI任务的过程.最后,您将获得一个满足GoogleMLOps成熟度模型第2级要求的功能管道.我们假设您对Python,深度学习,Docker,DevO ...

  • 【劲爆大揭秘!!!利用此技术再次斩获连续涨停板!】

    首先恭喜使用涨停板铺排技术再次斩获连续涨停板股票西藏珠峰600338的朋友,获利幅度50%!这个股票我们前期做过非常详细的分析,并且一直斩钉截铁认为这个股票必然有后市行情!经过一段时间的等待,终于爆发 ...

  • 浅析抗体偶联药物的理想抗原靶点应该具有哪些特征

    近年来抗体偶联药物(ADC)已经成为抗肿瘤药物研发的热点,可以将细胞毒药物直接运输到癌细胞发挥杀伤作用.合适的抗原靶点.高度特异性的抗体.理想的偶联子和高效的偶联药物的选择是一个成功的ADC药物需要具 ...

  • 浅析人工智能的发展方向

    众所周知人工智能现如今正在高速发展,并且深入人们的生活和工作中,这不仅对人工的生活和工作提供了便利,同时也对人们未来的生活产生了影响.那么未来人工智能的发展方向主要在哪些方面? 一是在治疗方面,开发出 ...