| 本帖最后由 Zleepwalking 于 2015/3/22 18:29 编辑 
 2015.3
 本贴所包含信息时间过于久远,已废弃。出于保留项目历史原因在此搁置。
 内容概述:
 CBV文件结构定义,发音记号系统,音源库开发流程,音源库制作软件TDPSMStudio使用方法和原理。
 
 
 
 
 从《关于CybervoiceEngine和TDPSM》里,你应该知道Rocaloid的CBV是一种记载了分拆后语音帧的音源库文件。CBV这个格式是Rocaloid唯一的从初代保留到二代的数据文件后缀。CBV的格式倒是经过了三次变化。Rocaloid Renaissance 1.6核心版采用了两种版本的CBV:v0.5和v0.6。我本来像把CBV 0.5, 0.6的后缀改成CVDB,但在CVE 1.5时期为了兼容老版本CBV所以后缀没变,但较原来的CBV,CVDB多了一个文件头。
 
 CVDB 0.5
 
 
 这是Rocaloid音源库中用于保存音源数据的文件格式。
 记录的内容:数据特性、语音数据、语音帧分界线的位置。
 
 先说CVDB 0.5吧。Rocaloid保存的音源库规格为: PCM signed 16bit little endian 96000HZ 1536kbps mono。如果你装了Goldwave一类的波形编辑软件,按这个规格直接打开CVDB 0.5的文件,应该会看到:
 
 
  
         其实CVDB 0.5是在音源库数据中穿插FE 7F(32766)和FF 7F(32767)来分割语音信号周期。其中FF 7F表示最后一个周期结束。 
         用winhex打开CVDB 0.5的话,你会在开头看到: 
 
          CVDB 0.5的文件头定义如下: (Rocaloid_HatsuneMiku 1.5.1 -RENAISSANCE-字样其实只是装帅。。。。。。。。。)复制代码CVDB Information
0-3 CVDB Header 'CVDB'
4-5 Version UInt16
6  Consonant FF(255)-True   FE(254)-False
7-10 StartPoint Int32
11-14 Average Period Int32
15  Fill FF(255)
16-255 Information  String
CVDB Data
FE 7F Frame/Period
FF 7F CVDB End
 
 CVDB 0.6
 
 
 这是Rocaloid音源库中用于保存音源数据的文件格式。
 记录的内容:数据特性、语音数据、语音帧分界线的位置。
 比CVDB 0.5更先进。
 
 CVDB 0.6和0.5的差别主要是,0.6里不再用FE 7F和FF 7F代表语音帧之间的界线,而是在文件头里塞下了一个帧长度表。Winhex打开如下:
 
  在帧长度表结束后就是一个去掉文件头的wav。所以你可以很容易地从CVDB 0.6中还原出wav,以后数据压缩也会很容易。
 而Goldwave打开的CVDB 0.6看上去跟wav几乎没区别,你甚至可以直接播放它。注意文件头会在起始处形成一个爆音。
 
  
 
 这是CVDB 0.6文件定义:
 Rocaloid Renaissance发音记号系统复制代码0-3 CVDB Header "CVDB"
4-5 Version UInt16 = 0x0002
6 Consonant FF(255)-True   FE(254)-False
7-10 StartPosition Int32
11-14 PeriodStartPosition Int32
15 Fill FF(255)
16-17 Chunk number UInt16
18-? Frame Chunks
      Period Length UInt16
?+1 Wave Data
      Data Chunks Int16
 
 这一段介绍Rocaloid Renaissance使用的发音记号和对应的发音,开发音源库或者高级调教需要看:
 最后给出了一张对照表,你懒得看介绍的话可以直接去看表。
 
 从初代。开始(打dai kai会被和谐掉。。。)Rocaloid就使用一套与众不同的发音记号系统。不用罗马音,国际音标,X-SAMPA等记号系统的原因:
 
 关于初代的发音记号就不详述了。初代只有1000多个CBV文件,而且每个辅音只有一组对应的CBV,比如b只有ba对应,c只有ci,k对应ke,x对应xi,p对应po……  这些记号系统可能无法准确地描述音源库文件的发音。  这些记号系统有太多发音,在Rocaloid的音源库中没有对应。  使用复杂的发音记号不利于开发和调试。
 
 Roca Rena的发音记号系统相比一代丰富了5倍,每个辅音,例如b,对应了3-5种辅音-元音的diphone,如ba, bo, be, bi, bu(汉语拼音)。
 辅音-元音diphone在Roca Rena记号系统中表示为:第一个字符是汉语拼音,第二个字符是@ [ 3 # ~中的一个。
 
 特殊情况是当辅音的汉语拼音占两个字符时,要用符号替换:@ 对应 a[   对应 o3  对应 e#  对应  i~  对应 u
 把发音记号限制成两个字符以内是为了开发方便,看起来也舒服(我觉得舒服吧。。。)。
 
 元音如此对应:
 
 a   对应  ao   对应  aoe   对应  aie-  对应  ei    对应   iu   对应  uv    对应  yu (也就是v)
 对于鼻音,也规划在元音之内:
 NG偏后鼻音,前面两个看情况使用,我很难用语言表述出它们的区别。@http404求说明。。。
 
 还有几个特殊的发音记号
 
 -    对应  ri后面的"i"的发音-#  对应  zi后面的"i"的发音,或者zhi、chi、shi中"i"的发音v-   对应 yu,和v的区别是v仅是yu后"u"的发音(用作元音),v-是整个yu(用作辅音)
 
 这里给出一张表格,是目前音源库中使用所有Rocaloid发音记号:
 
 | No. | Field | Rocaloid Symbol | Pronounciation |  | 1 | Vowel | a | a |  | 2 | o | ao |  | 3 | e | ai |  | 4 | e- | e |  | 5 | i | yi |  | 6 | u | u |  | 7 | v | yu |  | 8 | b | b@ | ba |  | 9 | b3 | be |  | 10 | b[ | buo |  | 11 | b# | bi |  | 12 | b~ | bu |  | 13 | p | p@ | pa |  | 14 | p3 | pe |  | 15 | p[ | puo |  | 16 | p# | pi |  | 17 | p~ | pu |  | 18 | m | m@ | ma |  | 19 | m3 | me |  | 20 | m[ | muo |  | 21 | m# | mi |  | 22 | m~ | mu |  | 23 | f | f@ | fa |  | 24 | f3 | fe |  | 25 | f[ | fuo |  | 26 | d | d@ | da |  | 27 | d3 | de |  | 28 | d[ | duo |  | 29 | d# | di |  | 30 | d~ | du |  | 31 | t | t@ | ta |  | 32 | t3 | te |  | 33 | t[ | tuo |  | 34 | t# | ti |  | 35 | t~ | tu |  | 36 | n | n@ | na |  | 37 | n3 | ne |  | 38 | n[ | nuo |  | 39 | n# | ni |  | 40 | n~ | nu |  | 41 | l | l@ | la |  | 42 | l3 | le |  | 43 | l[ | luo |  | 44 | l# | li |  | 45 | l~ | lu |  | 46 | j | j# | ji |  | 47 | q | q# | qi |  | 48 | x | x# | xi |  | 49 | g | g@ | ga |  | 50 | g3 | ge |  | 51 | g[ | guo |  | 52 | g~ | gu |  | 53 | k | k@ | ka |  | 54 | k3 | ke |  | 55 | k[ | kuo |  | 56 | k~ | ku |  | 57 | h | h@ | ha |  | 58 | h3 | he |  | 59 | h[ | huo |  | 60 | h~ | hu |  | 61 | z | z@ | za |  | 62 | z3 | ze |  | 63 | z[ | zuo |  | 64 | z# | zi |  | 65 | c | c@ | ca |  | 66 | c3 | ce |  | 67 | c[ | cuo |  | 68 | c# | ci |  | 69 | s | s@ | sa |  | 70 | s3 | se |  | 71 | s[ | suo |  | 72 | s# | si |  | 73 | zh | %@ | zha |  | 74 | %3 | zhe |  | 75 | %[ | zhuo |  | 76 | %# | zhi |  | 77 | %~ | zhu |  | 78 | ch | ^@ | cha |  | 79 | ^3 | che |  | 80 | ^[ | chuo |  | 81 | sh | &@ | sha |  | 82 | &3 | she |  | 83 | &[ | shuo |  | 84 | &~ | shu |  | 85 | w | w@ | wa |  | 86 | w3 | we |  | 87 | w[ | wuo |  | 88 | r | -# | zi |  | 89 | - | ri |  | 90 | n | N | n |  | 91 | NG | n |  | 92 | NN | n |  | 93 | v | v- | yu | 
 若要包含所有发音符号在所有音高下的发音,工作量太大了,所以我仅制作了C2-C5,属于比较常用的音域。
 93个发音符号 × 37个音高(C2 - C5) = 3441,也就是1.6核心版音源库中的CBV文件个数。
 
 
 CBV的文件名命名规则
 
 统一的命名规则:发音记号+下划线+音高.cbv
 如:b@_C3.cbv即C3下ba的发音。
 注意音高半音均使用#,例如C#3, D#3, F#3, G#3, A#3, C#4, D#4……但没有Eb3, Bb3这种表示。
 
 
 音源库开发流程
 
 
 介绍了音源库开发的四个步骤:
 最后附带了一个能自动调教Vocaloid的按键精灵脚本。| 
 | 步骤 | 使用工具 |  | 1 | 导出原始波形数据 | Vocaloid、按键精灵 |  | 2 | 纠正错误的或突兀的发音 | TDPSMStudio(Wave Editor模式) |  | 3 | 拆帧 | TDPSMStudio(Wave Analyzer模式) |  | 4 | 检查,标注VOT | TDPSMStudio(CVDB Quality Control模式) | 
 如果你要加入开发音源库,看这段:
 
 
 
  
 这是使用CVMaker+CVQC+VoiceWaver方案的流程图 
         因为TDPSMStudio的完成,如我在【序章】提到,这个软件涵盖了CVMaker+CVQC+VoiceWaver的功能,上面的方案已经被简化:把三个工具名字用TDPSMStudio替换掉,把用CVQC优化CBV的一步改成“检查和标注VOT”即可。 
         音源库的3441个文件都是从Vocaloid里导出后经由上述操作制成的。即是说初音唱了3441次……实际上的次数远大于这个数字,因为音源库来回刷了好几遍才能做出最好的。现在的音源库(1.6.1也不是最终的版本)。 
         DBManager是一个音源库管理工具,用批处理写的。起初我们使用Hamachi组建虚拟局域网,用windows自带的局域网文件共享传文件。这个批处理就放在共享文件夹里。后来Hamachi速度实在跟不上,我们就用百度网盘共享文件了,同样,批处理丢进同步文件夹就好了。 
 
  
         起初音源库操作经历上述三个步骤,中间会产生大量的文件。难处是这些文件即使不用了还得留着,说不定那天还会用得上。我在开发初代的时候受了个教训:总是记得以前有个音源库版本发音比当前的版本还好,回去找却发现文件已经被删掉了。         DBManager所做的事情就是把这些中间产生的文件自动归类和取出。首先相同发音的文件放在同一个文件夹里: 
         
  
         在这些文件夹里,不同步骤产生的文件又被放进数个子文件夹里归类。 
 因为一个发音会被重新制作n次,所以在Raw\Gen\Edit后面加上数字以表明版本,如Raw1, Gen2, Edit1这样……这些都是DBManager做的事情。| 文件夹 | 存储内容 |  | Raw | 从Vocaloid里直接导出的文件 |  | Raw | 经过波形调整的wav文件 |  | Gen | 经过拆帧产生的cbv文件 |  | Edit | 经过检查和调整的cbv文件 | 
 
 
  因为TDPSMStudio的出现,Gen被合并到Edit里去了。
 最后的音源库版本号,如1.6.1\71-236,1.6.1是音源库总版本号;71是所有Edit版的数量,236是所有Raw+Gen+Edit版的数量。
 
 1.6.1\71-236,也是发此贴时的音源库版本,共包含三万五千个半手工半自动处理的文件。好在有了TDPSMStudio这种工具后音源库开发的自动化程度大大提高。
 
 
  
         不过开源后这种共享方式不能继续了,DBManager也得退役了。因为我不能保证不会有人修改百度网盘的密码。Rgwan提议通过打7z包互传音源库部分文件的方式共享资料。 
         从Vocaloid导出文件也是批量导出的,我用按键精灵写了个脚本,输入一个发音记号就可以全自动从C2合成输出到C5: 
 复制代码PID = Plugin.Window.Foreground()
PitchList = Array("C2","C#2","D2","D#2","E2","F2","F#2","G2","G#2","A2","A#2","B2","C3","C#3","D3","D#3","E3","F3","F#3","G3","G#3","A3","A#3","B3","C4","C#4","D4","D#4","E4","F4","F#4","G4","G#4","A4","A#4","B4","C5")
Notes = Array("mo", "mi", "me", "mu")
NoteNames= Array("m[","m#","m3","m~")
NoteNo=0
NoteName = InputBox("Input the synthesis symbol:")
PitchNum = 0
Call Plugin.Window.Show(PID)
Rem Restart
'NoteName=NoteNames(NoteNo)
For i = 0 To 36
Delay 100
'Select All
KeyDown 18, 1
KeyPress 69, 1
KeyUp 18, 1
Delay 50
KeyPress "E", 1
Delay 100
        'Goto Skip
        FileName = NoteName & "_" & PitchList(i)
        'CTRL+ALT+SHIFT+S
        KeyDown 17, 1
        KeyDown 18, 1
        KeyDown 16, 1
        KeyPress 83, 1
        KeyUp 16, 1
        KeyUp 18, 1
        KeyUp 17, 1
        KeyPress "Enter", 1
        Delay 50
        'Input FileName
        SayString FileName
        Delay 100
        KeyPress "Enter", 1
        Delay 100
        'Wait For Synthesis
        Call WaitForColorChange(673,329)
        Rem Skip
        'Find Note
        FindColor 115,93,800,520,"F4E90B",intX,intY
        NoteX = intX + 30
        NoteY = intY + 5
        'Move
        MoveTo NoteX, NoteY
        Delay 100
        LeftDown 1
        Delay 100
        MoveR 0, -5 
        Delay 10
        MoveR 0, -4
        Delay 10
        MoveR 0, -3 
        Delay 100
        LeftUp 1
        Delay 100
        LeftClick 1
        Delay 100
        'Scroll
        If NoteY < 200 Then 
                MouseWheel 4
        End If
        Delay 100
Next
Call Restore
NoteNo = NoteNo + 1
FindColor 115,93,800,520,"F4E90B",intX,intY
NoteX = intX + 30
NoteY = intY + 5
If NoteNo = 4 Then 
        Goto EndS
End If
'Delay 20
'MoveTo NoteX, NoteY
'Delay 20
'LeftDoubleClick 1
'Delay 20
'SayString Notes(NoteNo)
'Delay 20
'KeyPress "Enter", 1
'Delay 50
'Goto Restart
Rem EndS
Function WaitForColorChange(x, y)
Rem F_WFCC
        Delay 10
        If GetPixelColor(x, y) = "C8D0D4" Then 
                Goto F_WFCC
        End If        
End Function
Function Restore()
        For i = 0 To 36
                Delay 20
                KeyDown 17, 1
                KeyPress 90, 1
                KeyUp 17, 1
                Delay 10
                FindColor 115,93,800,520,"F4E90B",intX,intY
                NoteX = intX + 30
                NoteY = intY + 5
                If NoteY > 455 Then 
                        MouseWheel -1 
                        Delay 20
                        MouseWheel -1
                End If
        Next
End Function
这是适用于V3的版本,简单改一下就可以适用于V2。你可以看到代码里隐藏了一个可以合成整个辅音-元音系列的功能,像这样按顺序合成:ma mi me mo。(人类已经不能阻止我开发Rocaloid了。。。)
 
 
 
         关于TDPSMStudio 
 TDPSMStudio是Rocaloid Renaissance中最新的用于开发音源库的软件,打破了以往用一批零散的工具开发音源库的局面。接下来的几段介绍TDPSMStudio的使用方法。
 既然它替代了以往一堆软件的功能,它有多个工作模式:
 要加入音源库开发请读这几段:
 
 
         TDPSMStudio 1.0.5.27281下载地址(484KB):           http://pan.baidu.com/share/link?shareid=543662&uk=3423845838         这个压缩包里包括了TDPSMStudio本体和一个测试用的o_C2.wav文件。(其实o_C2.wav保存的是%[_C2的数据。音源库里用%[代替o的发音。)         TDPSMStudio有三种模式,分别对应原本VoiceWaver, CVMaker 和 CVQC的功能(波形编辑,拆帧,检查)。 
         Wave Analyzer模式 
 
 
         这是用于拆帧的模式,打开TDPSMStudio后的默认模式。         在Symbol后输入发音记号,在Pitch里输入音高(遵循文件名的音高命名方式),然后点击Open即可打开一个wav文件。 
  
         波形下面的框是三种模式通用的。Amplitdue滑块控制显示面板上波形的竖向缩放比例;如果打开的是一个辅音-元音Diphone,就把Consonant勾上;Data Length是拆帧拆出来的数据长度,一般Diphone用0.5秒,元音用2秒;Balance Wave是自动平衡波形,一般情况下勾上。不过Balance多了理论上会对波形质量造成影响,如果这个波形之前被Balance过,就不用选了。前面说了,o_C2这个文件其实是zho的发音,所以把Consonant勾上就可以当成Diphone分析,不勾上就可以当元音分析。 
         红色的线代表音量大小,黑色的线是用来反映音量变化速率的,一般用不着。 
         载入一个wav后,会先出来连根粉红色的线,这是TDPSMStudio识别出的一个周期。拆帧时就会以这个地方为起始点拆帧。 
         波形视图的缩放方法跟Goldwave一样,鼠标滚轮控制缩放和移动,缩放的中心点即鼠标所在位置,很容易上手。 
         菜单栏下面的一排按钮里,有个Analyze Frame。点一下就可以自动拆帧。如果成功了会变成这样: 
 
  
         辅音部分因为没有周期性,会自动用音高对应的周期代替。 
         如果你在和TDPSMStudio同一目录下放了一个发音记号从C2到C5的所有发音的wav文件,就可以按Analyze Frame To All,一次按下对所有wav自动拆帧。TDPSMStudio理论上支持任意CPU核心数量的电脑,并且可以100%利用电脑的性能。在批量操作的时候会变得非常卡,鼠标甚至都会被卡住。。。好在处理37个文件速度很快,在i5-3320M上不到10秒就可以完成37个文件的批量处理。 
         在Settings->Analyzer里可以对分析器(拆帧器)进行设定: 
 
  
 | Silence Threshold | 判断为静音的音量阀值 |  | Allowing Error | 范围是0-1,当识别出的相邻两个周期长度区别超过这个倍数时,就停止分析(判断为VOT) |  | Self Correlation | 使用自相关算法 |  | Self Difference | 使用自差分算法 |  | Search Window | 搜寻窗口大小,即寻找周期长度的范围 | 
 Wave Editor 模式
 
 从Mode -> Wave Editor可以进入这个波形编辑器模式。在Wave Analyzer模式的基础上,可以用鼠标左右键单击波形窗口选中一段波形。
 
 
  
         此外你会看到一条红线,这是TDPSMStudio自动识别的VOT位置。 
         此模式下左边一排工具栏处于可用状态,从上向下功能依次为: 
 
 播放选定区域停止播放复制选定区域切除选定区域将复制的部分混音在选定区域的左边界线改变选定区域的音量平滑(模糊)选定区域标准化选定区域内的音量缩短选定区域(相当于CVE中的Shrink,须选中VOT之前的部分,不然会崩)使选定区域静音淡入选定区域按二次函数,减弱选定区域中心自适应性标准化+平衡(其实是标准化使音量全部在0.1以内)
 在Fade In或者Weaken按钮上按右键,右键菜单中有一列数字可以选择,这是一些参数。Fade In弹出的参数是淡入前的起始音量(比例)。Weaken弹出的参数是最低音量比例。
 
 与Wave Analyzer模式类似,如果你已经在TDPSMStudio所在目录放置了从C2到C5的同一个发音记号的37个wav文件,打开发音记号_C2后按Adjust To All可以批量对所有wav文件进行处理。
 
 
  
 | Automatic Adjust | 字面意思是自动调整,其实是标准化+平衡,找不到合适的名字了……后面跟的数字是音量大小限制 |  | Smoothen At VOT | 在VOT处平滑音量变化。Vocaloid在音高较高的时候,某些辅音的音量会突然上升,导致听上去不自然。此功能可以把VOT处的音量变化抑制在Limit以内 |  | Shrink Consonant | 缩短辅音 |  | Limit Consonants | 某些辅音的音量过大,Limit Consonant其实是个针对于辅音的Automatic Adjust |  | Consonant Fading In | 淡入辅音,同样是针对辅音音量过大的问题 |  | Until | 从当前音高一直批量处理到指定音高 | 
 若要保存调整后的wav,按快捷键Ctrl + C。
 
 CVDB Quality Control 模式
 
 这个模式直接对应CVQC的功能,即对批量CBV文件的检测。如果你已经生成了一个CBV文件,或者已经把CBV文件丢到TDPSMStudio同一目录下,输入发音记号和音高即可打开CBV。
 
 
  
         波形视图上呈现的就是拆帧后的CBV,红线代表准许CVE识别为周期性信号的位置。为了保持稳定,红线的位置被刻意放在VOT之后一小段时间。在此之前的信号被当作辅音的部分,CVE不对其进行处理或参与过渡。因为红线位置过于靠后会导致合成时产生爆音。一般此位置需要手动稍微向前调整。 
         调整周期其实位置只需在调整后的位置点击。若要保存起始位置调整后的CBV,按快捷键Ctrl + C。 
 
 
         适用于任何模式的功能 
 
         快捷键: 
 
 
 
 
 
 
 这种特殊的,和Windows常用快捷键不同的快捷键排布方式是为了能用左手操纵键盘,同时右手操纵鼠标,以提高操作效率。
 Ctrl + A     上一个音高Ctrl + S      打开这个音高Ctrl + D     下一个音高Ctrl + C      保存
 遍历:
 此功能用于检查处理后的文件。
 在任何模式下View All和Stop按钮都是可用的,View All用于把所有文件按音高顺序打开一遍,Stop是停止View All。
 
 波形预处理:
 此功能是在载入波形时对波形进行的处理,为了方便拆帧和语音分析。
 从Settings -> Preprocess可以进入。
 为了方便拆帧,TDPSMStudio会对波形进行(多次)移动平均。
 
 
  
 Moving Average: Enabled: 启用移动平均预处理Twice:二次移动平均Extra:再多一次移动平均
 2/3 Periods:移动平均长度为基频周期长度的2/3
 1/2 Periods:移动平均长度为基频周期长度的1/2
 1/3 Periods:移动平均长度为基频周期长度的1/3
 Envelope Mapping:1/4 Periods:移动平均长度为基频周期长度的1/4
 
 Start Position:1 Period:包络精确到1个基频周期长度2 Periods:包络精确到2个基频周期长度4 Periods:包络精确到4个基频周期长度
 
 Fixed:拆帧的开始点是固定的Delayed:拆帧的开始点在音量突破静音阀值(在Analyzer中设置)之后。下面的文本框设定Delayed的延迟时间。
 TDPSMStudio的原理
 
 关键字:移动平均,自相关算法,自差分算法。
 如果你加入TDPSMStudio的开发,请读下面:
 
 前面的说明中应该已经能看到一些原理了。
 移动平均之所以能利于之后的拆帧,是因为经过两次长度大约1/3基频周期长度的移动平均后,大多数语音波形会变成一峰一谷的形式。
 如果仅是选取任意点为周期分界进行拆帧,在PSM混合时可能会对波形造成比较大的损害。例:“i”和“u”是波形类似正弦的简单波形,假如我以i的波峰前的过零点为周期(语音帧之间的)分界;以u的波谷前的过零点为周期分界,那么在从i到u的过渡中可能有一刻,i和u的波峰波谷互相抵消,这个过渡就被断开了。        将波形移动平均后变为一峰一谷的形式,TDPSM选择波峰前的过零点作为周期分界,也有助于提高合成质量。不过这么做仅仅是减轻了对音质的损害,这是PSM目前没解决的问题之一。
 关于前文中提到的“自差分”算法,我不知道学术上怎么称呼,只是我自己给它取的名字。
 [2013-7-25补充]这个“自差分”学术上叫AMDF,自相关在这里称为ACF。
 这是离散信号自相关算法的公式,如果你学过DSP,你懂的肯定比我多:
 
  
         其实它就是把一段长度为l的波形,从x处移动到x+n的位置,并不断把移动前后对应位置上的数据乘起来。正正得正,正负得负,负负得正,所以移动n位后波形重合度越高,On的值也越大。         那么理论上值最高的On(除了O0)就是周期交接处的位置。 
         自差分就是把乘法改成减法然后取绝对值: 
 
  
 
         它是把一段长度为l的波形,从x处移动到x+n的位置,并不断计算把移动前后对应位置上的数据的大小区别。所以移动n位后波形重合度越高,On的值也越接近0。那么理论上值最低的On(除了O0)就是周期交接处的位置。 
 
 
 
 
 
 |