精华内容
下载资源
问答
  • 老师给了我一道题,让我用Verilog编写出来:通过100M时钟产生3M、5M和20M正弦波,并将产生的三个不同频率正弦波加在一起,然后从这个和信号中将20M正弦波提取出来。 我的思路 首先通过DDS分别产生3M、5M、20M正弦...

    题目要求

    老师给了我一道题,让我用Verilog编写出来:通过100M时钟产生3M、5M和20M正弦波,并将产生的三个不同频率的正弦波加在一起,然后从这个和信号中将20M正弦波提取出来。

    我的思路

    首先通过DDS分别产生3M、5M、20M正弦波,通过加法器将这三个正弦波加在一起,再通过设计FIR数字滤波器将20M正弦波从和信号中滤出来。整个过程思路还是很清楚的。

    DDS原理及代码

    关于DDS原理介绍的文章很多,csdn上就很多的文章,可以参考下。
    DDS,即直接数字式频率合成法,基本思想就是在存储器中存入正弦波的N个均匀间隔样值,然后以均匀速度将样值传输到数模转换器,将其转换成模拟信号。
    这一块我感觉很多文章写的不是很清楚,我直接给大家看看课本上关于DDS原理的介绍:
    在这里插入图片描述
    在这里插入图片描述
    简单的说就是在存储器ROM中,每隔k个点取一个值,实现k倍频。但由于要满足Nquist定理,所以DDS输出频率小于等于时钟频率的二分之一,即:fo <= fc/2。
    DDS输出频率:
    在这里插入图片描述

    M为频率控制字,N为相位累加器的位宽。

    DDS实现过程及代码

    首先我们需要生成ROM存储单元。可以直接用Verilog编写,也可以在MATLAB中生成.coe文件,通过Vivado调用ROM的IP核来实现(我更推荐第二种办法)。
    MATLAB生成ROM存储单元的.coe文件(.coe文件google便可明白)。波形数据表ROM中存有一个完整周期的正弦波信号。使波形文件ROM的地址为12位,存储数据位宽11位。将一个周期的正弦波,沿横轴等间隔采样212=4096次,每次采集的信号幅度用11位数据表示,最大值为2048,最小值为0。将采集的4096个数据按顺序存入ROM中,然后以相位累加器的输出为地址,进行访问。

    MATLAB生成ROM存储单元的.coe文件:

    clear;clc;
    depth = 4096;   %4096个存储空间
    width = 11;      %存储数据位宽
    t = 0:depth-1;
    ADC = 2^11 - 1;  %直流分量
    A = 2^11;        %幅度
    s = A * sin(2*pi*t/(depth-1)) + ADC;
    plot(t,s);
    fid = fopen('sine.coe','wt');
    fprintf(fid,'MEMORY_INITIALIZATION_RADIX=10;\n');
    fprintf(fid,'MEMORY_INITIALIZATION_VECTOR=\n');
    for i = 1:depth-1
        fprintf(fid,'%d,\n',ceil(s(i)));
    end
    fprintf(fid,'%d;\n',ceil(s(depth)));
    fclose(fid);
    

    在Vivado中调用ROM的IP核
    点击IP Catalog
    在这里插入图片描述
    在search中搜索rom,选择Block Memory Generator
    在这里插入图片描述
    点击Port A Option进行修改,主要修改Width和Depth的修改,与之前matlab中保持一致。
    在这里插入图片描述
    点击Other Option
    在这里插入图片描述
    之后一路OK便可。IP核设置完成之后,我们需要在模块中调用。
    我们先来写3M正弦波的产生文件。
    程序中ROM IP核的调用方法:点击IP Source,找到。veo文件,将框中的代码复制进DDS_3M文件中,实现IP核调用。
    在这里插入图片描述

    module DDS_3M(
        input clk,
        input reset,
        output [11:0] data
        );
    parameter fre_word = 32'd128849018;     //频率控制字     fre_word = f_out * 2^N / fclk   N为累加器位宽
    reg [31:0] addr_sin;
    
    //相位累加器
    always @(posedge clk or reset)  
    begin
        if(reset == 0)
            addr_sin <= 32'b0;
        else
            addr_sin <= addr_sin + fre_word;
    end
    
    wire [11:0]addra = addr_sin[31:20];
    //ROM IP核的调用
    sin_rom your_instance_name (
      .clka(clk),    // input wire clk	时钟
      .addra(addra),  // input wire [11 : 0] addra	相位累加器输入给rom的地址
      .douta(data)  // output wire [11 : 0] douta	从ROM返回的数据(3M正弦波的采样点)
    );
    endmodule
    

    5M、20M正弦波的产生方法与3M完全类似,只是需要改变相位控制字即可,此处不再呈现。

    下面的代码为了让后续代码编写起来更简洁

    module DDS(
        input clk,
        input reset,
        output [11:0] data_3M,
        output [11:0] data_5M,
        output [11:0] data_20M
        );
        
    DDS_3M DDS_3M_inst(
        .clk(clk),
        .reset(reset),
        .data(data_3M)
    );
    
    DDS_5M DDS_5M_inst(
        .clk(clk),
        .reset(reset),
        .data(data_5M)
    );
    
    DDS_20M DDS_20M_inst(
        .clk(clk),
        .reset(reset),
        .data(data_20M)
    );
    endmodule
    

    至此,DDS产生正弦波成功。

    正弦波求和

    此处非常简单,我直接上代码:
    需要注意的就是求和之后,和的位数可能会超过之前单个正弦波样值的12位,所以需要拓宽正弦波和的位宽。

    module wave_summation(
        input clk,
        input reset,
        input [11:0] wave_3M,
        input [11:0] wave_5M,
        input [11:0] wave_20M,
        
        output  reg [13:0] wave_sum
        );
        
    DDS wave(
        .clk(clk),
        .reset(reset),
        .data_3M(wave_3M),
        .data_5M(wave_5M),
        .data_20M(wave_20M)
    );
    
    always @(posedge clk or reset)
       if(reset == 0)
            wave_sum = 14'b0;
        else
            wave_sum = wave_3M + wave_5M  + wave_20M;
    endmodule
    

    滤波器设计

    滤波器的设计是我感觉比较难的一个地方。
    先说说我自己遇到的问题:就是DDS模块和求和模块中,符号都是unsigned,而在滤波器设计模块,我按照一篇文章将符号改为signed,导致仿真一直出错。

    滤波器的设计及调用我推荐大家这篇文章:https://blog.csdn.net/follow_moon/article/details/80376118
    只是其中需要注意的是,在保存.coe文件之前需要将hn的系数改为无符号数:
    在这里插入图片描述
    注:其他操作与我推荐的博客中的操作来便可。
    fir IP核调用推荐文章:
    https://blog.csdn.net/judas1801/article/details/108506433
    这篇文章非常使用,照着设置IP核,便可成功。之后的调用方式与ROM的调用方式完全一样。
    https://blog.csdn.net/keilzc/article/details/104249702
    这篇文章对于fir IP核调用的理解有很大帮助。
    下面是fir滤波器的代码:

    module bondpass_filter(
        input clk,
        input [13:0] wave_in,
        output [39:0] wave_out,
        output m_tvalid,
        output s_tready
        );
    
    
    wire [15:0] s_tdata;
    assign s_tdata = {2'b0,wave_in};    //s_tdata为16bit位宽,输入信号wave_in为14bit位宽,通过拼接运算填补高位
       
    fir_compiler_0 your_instance_name (
      .aclk(clk),                              
      .s_axis_data_tvalid(1'b1),  
      .s_axis_data_tready(s_tready),  //准备好信号,置1表示FIR可以接收数据输入
      .s_axis_data_tdata(s_tdata),    // input wire [15 : 0] s_tdata
      .m_axis_data_tvalid(m_tvalid),  //FIR输出数据有效信号,置1表示输出有效
      .m_axis_data_tdata(wave_out)    // output wire [39 : 0] m_tdata
    );
    endmodule
    

    测试文件

    `timescale 1ns / 1ps
    module wave_summation(
        input clk,
        input reset,
        input [11:0] wave_3M,
        input [11:0] wave_5M,
        input [11:0] wave_20M,
        
        output  reg [13:0] wave_sum
        );
        
    DDS wave(
        .clk(clk),
        .reset(reset),
        .data_3M(wave_3M),
        .data_5M(wave_5M),
        .data_20M(wave_20M)
    );
    
    always @(posedge clk or reset)
       if(reset == 0)
            wave_sum = 14'b0;
        else
            wave_sum = wave_3M + wave_5M  + wave_20M;
    endmodule
    

    加粗样式

    展开全文
  • 传统的直接数字频率合成(DDS)移相原理是先将正弦波信号数字化,并形成一张数据表存入两片ROM芯片中,此后可通过两片。D/A转换芯片在计数器的控制下连续地循环输出该数据表,就可获得两路正弦波信号。当两片D/A转换...
  • 1971年,由J.Tierney 和C.M.Tader 等人在 “A Digital Frequency Synthesizer”一文中首次提出了DDS的概念, ...这种方法不仅可以产生不同频率正弦波,而且可以控制波形的初始相位. 还可以用DDS方法产生任意波形(AWG)
  • 传统的直接数字频率合成(DDS)移相原理是先将正弦波信号数字化,并形成一张数据表存入两片ROM芯片中,此后可通过两片。D/A转换芯片在计数器的控制下连续地循环输出该数据表,就可获得两路正弦波信号。当两片D/A转换...
  • 用FPGA来完成直接数字频率...而通过设定不同的累加器初值(K1)和初始相位值(K2),可以调节两路相同频率正弦信号之间的相位差,从而产生两路数字式的频率、相位和幅值可调的正弦波信号,最后通过MAX+plusII演示仿真结果。
  • 2.3.1 量化输出正弦波的傅里叶分析 2.3.2 相位截断正弦波的频谱分析 2.3.3 正弦字的截断 2.3.4 背景杂散信号电平的估计 2.3.5 W和S之间的关系 2.4 D/A变换器的噪声分析 2.4.1 量化引起的信噪比 2.4.2 D/A变换器引起...
  • 一系列三角函数谐波(harmonic sinusoids)是傅里叶分析的基石,我们可以用这些不同频率的谐波构建各种各样的信号/波形。 谐波(harmonics): 现在我们选择一个频率为f0的任意频率(arbitrary frequency)的...

    三角函数的性质

     

           一系列三角函数谐波(harmonic sinusoids)是傅里叶分析的基石,我们可以用这些不同频率的谐波构建各种各样的信号/波形。

    谐波(harmonics):

          现在我们选择一个频率为f0的任意频率(arbitrary frequency)的正弦/余弦函数为基波(fundamental frequency)。则有一系列的基于该波的谐波(harmonics),这些谐波的频率都是基波的整数倍,例如,2f0, 3f0, 4f0, 5f0......kf0。

     

    频率为任意频率f0的基波(一对正弦和余弦):

    基于该基波的谐波分量fk = k*f0,k是任意整数:

    下图是频率为任意频率f0的基波及其谐波,周期逐级以整数倍递减,频率逐级以整数倍增加。

    上图是频率为任意频率f0的基波及其谐波,周期逐级以整数倍递减,频率逐级以整数倍增加。

    ————————————————————————————————————————————————————

    下面我们用另外一种方式来重新表示谐波,如下:

    之前我们只是通过不同的频率或周期来表示不同的谐波,现在我们还能通过改变振幅(amplitude)和相位(phase)来定义不同的谐波。

     

     

    幅度(amplitude):

         波的幅度就是信号中高于或低于信号均值的值,幅度可以是正值或负值。如果一个余弦函数的表达式为:a cos(wt),则该余弦曲线的最大值(+1)和最小值(-1)由系数a进行缩放。波形的最高峰值不会超过a,这个系数被称为波的幅度。在上面的两个等式中,ak和bk都是是波的幅度。

     

     

    相位(phase):

         相位可以理解成波形的起始位置,也可以理解成整个波形的整体移动。例如一个正弦波,当相位为0时,(即,无位移的情况下)他在0点的值是0。若发生了四分之一个周期的位移,即,90度的位移,则他在0点的值是正1。

    上图中的一艘军舰遭遇了叠加着三种不同波长/不同频率海浪的拍打!当这些海浪由于相位不同,大部分能量相互抵消,所以大部分时候的海面风平浪静。当这些海浪的相位达到一种相互增强的情况下时,则最终会叠加成一个巨大的海浪(如上图中虚线)。是否会形成这种巨浪取决于这些分量的相对相位!

     

     

    正交(orthogonality):

         正弦波和余弦波正好差了π/2个相位,即90度。若有两个信号的相位相差-90度或+90度时,则这两个信号被视为是正交的,因此,正弦波和余弦波是相互正交的。

    例如,下图中最后一图发生了90度移位的正弦波和余弦波正好重合。

     

         余弦波总是在0点(t = 0)处达到其峰值/最大值,且在此处的相位为π/2。正弦波,不论其频率为多少,在0点(t = 0)处总是为0,且此处的相位为0。因此,不管把多少任意频率,任意幅度的正弦波加在一起,最终的波形在0点处一定还是0。同理,不论把多少各种各样的余弦波加在一起,最终在0点的幅度总不是0。

        

     

     

    用不同频率的三角波合成信号

    谐波信号的叠加(只改变频率):

     

         下面我们把上图中,幅度相同,0相位,不同频率的三个正弦波和三个余弦波加在一起。由下图中的实验结果知,三个正弦波/奇函数相加还是奇函数,并且在0点处的值还是0,关于原点中心对称。三个余弦波/偶函数相加的结果还是偶函数,并且在0点处的值还是峰值,关于Y轴镜像对称。最后一幅图是把正弦函数和余弦函数的和相加后的结果,这是信号合成的基础。

         上图中的信号合成是用三个整数倍于基波频率f0的正弦谐波和余弦谐波的叠加而成的,请大家回忆一下,本文中一开始讲的基波频率整数倍的谐波,f0, 2f0, 3f0, 4f0.......kf0。上面只是用了3-6个谐波来合成新波形,并且不改变幅度和相位。接下来我们仍旧不改变谐波的幅度和相位,而是增加谐波的数量(增加到12,50个,乃至更多)来合成新的信号。

     

    正弦谐波的叠加(只改变频率):

     

    余弦谐波的叠加(只改变频率):

    注意:我专门用黑框标注的幅度的变换。

     

    正弦+余弦谐波的叠加,并取绝对值(只改变频率):

    用无穷多个相同幅度,0相位的,不同频率的正弦和余弦的谐波叠加并取绝对值,最终会合成一个冲击串信号

     

       就目前来看,如果只是改变三角函数的频率能够合成的波形似乎非常有限。目前我们只是合成信号处理中最常见的冲击串和Sinc函数。那么其他的常见信号又是怎么用三角函数合成的呢?例如,方波,锯齿波,随机信号,等等。

     

    预知后事如何,请见下回分解。

     

    《圣经》约翰福音 12章:25 ------ 爱惜自己生命的,就失丧生命;在这世上恨恶自己生命的,就要保守生命到永生。

                                                                                                     *配图与本文无关*

     

    展开全文
  • matlab开发-合成信号生成和回放。它产生两个不同频率正弦波和随机噪声并播放。
  • 语音合成最新进展

    2018-09-10 19:25:00
    通过时域到频域的变换,可以得到从侧面看到的频谱,但是这个频谱并没有包含时域的中全部的信息,因为频谱只代表各个频率正弦波的振幅是多少,而没有提到相位。基础的正弦波\(Asin(wt+\theta)\)中,振幅、频率和相位...

    Tacotron2

    前置知识

    通过时域到频域的变换,可以得到从侧面看到的频谱,但是这个频谱并没有包含时域的中全部的信息,因为频谱只代表各个频率正弦波的振幅是多少,而没有提到相位。基础的正弦波\(Asin(wt+\theta)\)中,振幅、频率和相位缺一不可。不同相位决定了波的位置,所以对于频域分析,仅有频谱是不够的,还需要一个相位谱。

    • 时域谱:时间-振幅

    • 频域谱:频率-振幅

    • 相位谱:相位-振幅

    84160661.jpg

    参见:傅里叶分析之掐死教程(完整版)更新于2014.06.06

    传统语音合成:

    • 单元挑选和拼接:将事先录制好的语音波形小片段缝合在一起。边界人工痕迹明显
    • 统计参数:直接合成语音特征的平滑轨迹,交由声码器合成语音。发音模糊不清且不自然

    Tacotron2分为两部分:

    • 一个seq2seq结构的特征预测网络,将字符向量映射到梅尔声谱图
    • 一个WaveNet修订版,将梅尔声谱图合成为时域波形

    梅尔频谱是对短时傅里叶变换获得的声谱(即线性声谱)频率轴施加一个非线性变换,其依据人耳特性:低频细节对语音的理解十分关键,而高频细节可以淡化,对频率压缩变换而得。Tacotron2使用低层的声学特征梅尔声谱图来衔接两个部分的原因:

    • 梅尔频谱容易通过时域波形计算得到
    • 梅尔频谱对于每一帧都是相位不变的,容易使用均方差(MSE)训练

    梅尔声谱抛弃了相位信息,而像Griffin-Lim算法对抛弃的相位信息进行估计,然后用一个短时傅里叶逆变换将梅尔声谱图转换为时域波形。可就是说,梅尔声谱是有损的,而声码器Griffin-Lim算法和近年出现的WaveNet有“找补”作用。Tacotron2特征预测网络选择梅尔频谱作为输出以减轻模型负担,再另加一个声码器WaveNet单独将梅尔频谱转波形。

    声谱预测网络

    80024370.jpg

    编码器将字符序列转化为一个隐状态,继而解码器接受隐状态用以预测声谱图。构建注意力网络用以消费编码器输出结果,编码器的每次输出,注意力网络都将编码序列归纳为上下文向量。最小化进入post-net前后的均方差以加速收敛。stop-token用于在推断(inference)时,动态结束生成过程。

    WaveNet声码器

    两部分组件分开训练,WaveNet依赖Tacotron2的特征预测网络的结果进行预测,一个替代方案是,使用从真实音频中抽取的梅尔频谱来训练WaveNet。注意:使用预测特征训练,就用预测特征推断;真实特征训练,真实特征推断;诸如使用预测特征训练,使用真实特征预测这种方法合成效果最差。

    另外,论文中提到,梅尔频谱的通道数和合成语音质量是一种有趣的权衡;在解码后使用后处理网络结合上下文以改善合成质量,虽然WaveNet也含有卷积,但通过对比合成质量,加了后处理网络的合成质量更好些;与修改之前的30层卷积,256ms感受野的WaveNet相比,修改后的WaveNet卷积层减少到12层,感受野为10.5ms,但模型仍然合成了高质量的语音。因此对于语音质量来说,一个大的感受野并不是必须的,但是,如果去除所有的扩大卷积,感受野与基线模型相比小两个数量级,语音质量也大幅下降。因此虽然模型不需要一个大感受野,但是适当的上下文是必需的。

    实现代码

    Tacotron-2_Rayhane-mamah@github为例,说明Tacotron2特征预测部分的实现。

    特征预测网络的主文件位于Tacotron-2/tacotron/models/tacotron.py

    • Character Embedding,上图中,Input TextChar Embedding:将Input Text映射到实数向量

      [batch_size, sequence_length] -> [batch_size, sequence_length, embedding_size]

      e.g.:
      \[ [ [2,4], [3] ]\\ \to \\ [[[0.3,0.1,0.5,0.9], [0.5,0.,1.9,0.3,0.4]], [[1.3,0.4,5.1,0.8]] \]

      embedding_table = tf.get_variable(
        'inputs_embedding', [len(symbols), hp.embedding_dim], dtype=tf.float32)
      embedded_inputs = tf.nn.embedding_lookup(embedding_table, inputs) 
      • embedding_table: [len(symbols), embedding_size]. Tensorflow待训练变量,len(symbols)为所有字符的数目

      • inputs: [batch_size, sequence_length]. sequence_length为输入时间序列的步数,矩阵中的值为字符ID

      • embedded_inputs: [batch_size, sequence_length, embedding_size]

    • Encoder,上图中,3 Conv LayersBidirectional LSTM:编码器

      [batch_size, sequece_length, embedding_size] -> [batch_size, encoder_steps, encoder_lstm_units]

      encoder_cell = TacotronEncoderCell(
        EncoderConvolutions(is_training, hparams=hp, scope='encoder_convolutions'),
        EncoderRNN(is_training, size=hp.encoder_lstm_units,
                   zoneout=hp.tacotron_zoneout_rate, scope='encoder_LSTM'))
      
      encoder_outputs = encoder_cell(embedded_inputs, input_lengths)
      • encoder_outputs: [batch_size, encoder_steps, encoder_lstm_units]

        其中,TacotronEncoderCellBasicRNNCellGRUCellBasicLSTMCell一样,是自定义的RNNCell,继承自from tensorflow.contrib.rnn import RNNCell,参见:tensorflow中RNNcell源码分析以及自定义RNNCell的方法

        • TacotronEncoderCell的参数之一EncoderConvolutions,对应于3 Conv Layers
        with tf.variable_scope(self.scope):
            x = inputs
            for i in range(self.enc_conv_num_layers):
                x = conv1d(x, self.kernel_size, self.channels, self.activation,
                           self.is_training, self.drop_rate, 'conv_layer_{}_'.format(i + 1) + self.scope)
        return x
        • TacotronEncoderCell的参数之二EncoderRNN,对应于Bidirectional LSTM
        with tf.variable_scope(self.scope):
            outputs, (fw_state, bw_state) = tf.nn.bidirectional_dynamic_rnn(
                self._fw_cell,
                self._bw_cell,
                inputs,
                sequence_length=input_lengths,
                dtype=tf.float32,
                swap_memory=True)
        
            # Concat and return forward + backward outputs
            return tf.concat(outputs, axis=2)

        其中,self._fw_cellself._bw_cell均为自定义的RNNCell,ZoneoutLSTMCell。这是一种最近出现的LSTM变种,参见:Zoneout: Regularizing RNNs by Randomly Preserving Hidden Activations

    • Decoder,上图中,2 Layer Pre-NetLocation Sensitive Attention2 LSTM LayersLinear Projection:解码器

      [batch_size, encoder_steps, encoder_lstm_units] -> [batch_size, decoder_steps, num_mels×r]

      # Attention Decoder Prenet
      prenet = Prenet(is_training, layers_sizes=hp.prenet_layers, drop_rate=hp.tacotron_dropout_rate,
                    scope='decoder_prenet')
      # Attention Mechanism
      attention_mechanism = LocationSensitiveAttention(hp.attention_dim, encoder_outputs, hparams=hp,
                                                     mask_encoder=hp.mask_encoder,
                                                     memory_sequence_length=input_lengths,
                                                     smoothing=hp.smoothing,
                                                     cumulate_weights=hp.cumulative_weights)
      # Decoder LSTM Cells
      decoder_lstm = DecoderRNN(is_training, layers=hp.decoder_layers,
                              size=hp.decoder_lstm_units,                  zoneout=hp.tacotron_zoneout_rate,
                              scope='decoder_lstm')
      • Prenet2 Layer Pre-Net,Dense + Dropout

        x = inputs
        
        with tf.variable_scope(self.scope):
            for i, size in enumerate(self.layers_sizes):
                dense = tf.layers.dense(x, units=size, activation=self.activation,
                                        name='dense_{}'.format(i + 1))
                # The paper discussed introducing diversity in generation at inference time
                # by using a dropout of 0.5 only in prenet layers (in both training and inference).
                x = tf.layers.dropout(dense, rate=self.drop_rate, training=True,
                                      name='dropout_{}'.format(i + 1) + self.scope)
        return x
      • LocationSensitiveAttentionLocation Sensitive Attention

        继承自from tensorflow.contrib.seq2seq.python.ops.attention_wrapper import BahdanauAttention的子类

        Location Sensitive Attention是稍微改动的混合注意力机制:

        • energy
          \[ e_{ij}=v_a^Ttanh(Ws_i+Vh_j+Uf_{i,j}+b) \]
          其中,\(v_a^T\)\(W\)\(V\)\(U\)\(b\)为待训练参数,\(s_i\)为当前解码步上RNN隐状态,\(h_j\)为编码器隐状态,\(f_{i,j}\)经卷积的累加的之前的alignments

          # processed_query shape [batch_size, query_depth] -> [batch_size, attention_dim]
          W_query = self.query_layer(query) if self.query_layer else query
          # -> [batch_size, 1, attention_dim]
          W_query = tf.expand_dims(processed_query, axis=1)
          
          # processed_location_features shape [batch_size, max_time, attention dimension]
          # [batch_size, max_time] -> [batch_size, max_time, 1]
          expanded_alignments = tf.expand_dims(previous_alignments, axis=2)
          # location features [batch_size, max_time, filters]
          f = self.location_convolution(expanded_alignments)
          # Projected location features [batch_size, max_time, attention_dim]
          W_fil = self.location_layer(f)
          
          v_a = tf.get_variable(
            'attention_variable', shape=[num_units], dtype=dtype,
            initializer=tf.contrib.layers.xavier_initializer())
          b_a = tf.get_variable(
            'attention_bias', shape=[num_units], dtype=dtype,
            initializer=tf.zeros_initializer())
          
          tf.reduce_sum(v_a * tf.tanh(W_keys + W_query + W_fil + b_a), axis=[2])

          其中,\(f_{i,j}\to W\_fil\)self.location_convolution & self.location_layer

          self.location_convolution = tf.layers.Conv1D(filters=hparams.attention_filters,
            kernel_size=hparams.attention_kernel, padding='same', use_bias=True,
            bias_initializer=tf.zeros_initializer(), name='location_features_convolution')
          
          self.location_layer = tf.layers.Dense(units=num_units, use_bias=False,
            dtype=tf.float32, name='location_features_layer')

          alignments | attention weights
          \[ \alpha_{ij}=\frac{exp(e_{ij})}{\sum_{k=1}^{T_x}exp(e_{ik})} \]

          alignments = self._probability_fn(energy, previous_alignments)
        • context vector
          \[ c_{i}=\sum_{j=1}^{T_x}\alpha_{ij}h_j \]

          context = math_ops.matmul(expanded_alignments, attention_mechanism.values)
          context = array_ops.squeeze(context, axis=[1])
      • FrameProjection & StopProjectionLinear Projection,Dense

        • FrameProjection

          with tf.variable_scope(self.scope):
           #If activation==None, this returns a simple Linear projection
           #else the projection will be passed through an activation function
           # output = tf.layers.dense(inputs, units=self.shape, activation=self.activation,
           #   name='projection_{}'.format(self.scope))
           output = self.dense(inputs)
          
           return output
        • StopProjection

          with tf.variable_scope(self.scope):
           output = tf.layers.dense(inputs, units=self.shape,
               activation=None, name='projection_{}'.format(self.scope))
          
           #During training, don't use activation as it is integrated inside the sigmoid_cross_entropy loss function
           if self.is_training:
               return output
           return self.activation(output)

    在Decoder的实现中,将实例化的prenetattention_mechanismdecoder_lstmframe_projectionstop_projection传入TacotronDecoderCell

    decoder_cell = TacotronDecoderCell(
       prenet,
       attention_mechanism,
       decoder_lstm,
       frame_projection,
       stop_projection)

    其中,TacotronDecoderCell继承自from tensorflow.contrib.rnn import RNNCell

    #Information bottleneck (essential for learning attention)
    prenet_output = self._prenet(inputs)
    
    #Concat context vector and prenet output to form LSTM cells input (input feeding)
    LSTM_input = tf.concat([prenet_output, state.attention], axis=-1)
    
    #Unidirectional LSTM layers
    LSTM_output, next_cell_state = self._cell(LSTM_input, state.cell_state)
    
    
    #Compute the attention (context) vector and alignments using
    #the new decoder cell hidden state as query vector
    #and cumulative alignments to extract location features
    #The choice of the new cell hidden state (s_{i}) of the last
    #decoder RNN Cell is based on Luong et Al. (2015):
    #https://arxiv.org/pdf/1508.04025.pdf
    previous_alignments = state.alignments
    previous_alignment_history = state.alignment_history
    context_vector, alignments, cumulated_alignments = _compute_attention(self._attention_mechanism,
        LSTM_output,
        previous_alignments,
        attention_layer=None)
    
    #Concat LSTM outputs and context vector to form projections inputs
    projections_input = tf.concat([LSTM_output, context_vector], axis=-1)
    
    #Compute predicted frames and predicted <stop_token>
    cell_outputs = self._frame_projection(projections_input)
    stop_tokens = self._stop_projection(projections_input)
    
    #Save alignment history
    alignment_history = previous_alignment_history.write(state.time, alignments)
    
    #Prepare next decoder state
    next_state = TacotronDecoderCellState(
        time=state.time + 1,
        cell_state=next_cell_state,
        attention=context_vector,
        alignments=cumulated_alignments,
        alignment_history=alignment_history)
    
    return (cell_outputs, stop_tokens), next_state

    然后定义helper,初始化后,开始解码:

    #Define the helper for our decoder
    if is_training or is_evaluating or gta:
        self.helper = TacoTrainingHelper(batch_size, mel_targets, stop_token_targets, hp, gta, is_evaluating, global_step)
    else:
        self.helper = TacoTestHelper(batch_size, hp)
    
    
    #initial decoder state
    decoder_init_state = decoder_cell.zero_state(batch_size=batch_size, dtype=tf.float32)
    
    #Only use max iterations at synthesis time
    max_iters = hp.max_iters if not (is_training or is_evaluating) else None
    
    #Decode
    (frames_prediction, stop_token_prediction, _), final_decoder_state, _ = dynamic_decode(
        CustomDecoder(decoder_cell, self.helper, decoder_init_state),
        impute_finished=False,
        maximum_iterations=max_iters,
        swap_memory=hp.tacotron_swap_with_cpu)
    
    
    # Reshape outputs to be one output per entry
    #==> [batch_size, non_reduced_decoder_steps (decoder_steps * r), num_mels]
    decoder_output = tf.reshape(frames_prediction, [batch_size, -1, hp.num_mels])
    stop_token_prediction = tf.reshape(stop_token_prediction, [batch_size, -1])

    Seq2Seq定义简明说明参见:Tensorflow新版Seq2Seq接口使用Dynamic Decoding-Tensorflow

    • Postnet,上图中,5 Conv Layer Post-Net:后处理网络

      [batch_size, decoder_steps, num_mels×r] -> [batch_size, decoder_steps×r, postnet_channels]

      with tf.variable_scope(self.scope):
        x = inputs
        for i in range(self.postnet_num_layers - 1):
            x = conv1d(x, self.kernel_size, self.channels, self.activation,
                self.is_training, self.drop_rate, 'conv_layer_{}_'.format(i + 1)+self.scope)
        x = conv1d(x, self.kernel_size, self.channels, lambda _: _, self.is_training, self.drop_rate,
            'conv_layer_{}_'.format(5)+self.scope)
      return x

      之后进入残差部分:

      [batch_size, decoder_steps×r, postnet_channels] -> [batch_size, decoder_steps×r, num_mels]

      residual_projection = Dense(hp.num_mels, scope='postnet_projection')
      projected_residual = residual_projection(residual)
      
      mel_outputs = decoder_output + projected_residual

      此外,代码中还提供了“开关”后处理CBHG的选项:

      if post_condition:
        # Add post-processing CBHG:
        post_outputs = post_cbhg(mel_outputs, hp.num_mels, is_training)  # [N, T_out, 256]
        linear_outputs = tf.layers.dense(post_outputs, hp.num_freq)
    • Loss计算

      self.loss = self.before_loss + self.after_loss + self.stop_token_loss + self.regularization_loss + self.linear_loss
      • self.before_loss & self.after_loss

        送入Post-Net前的MaskedMSE & 经过Post-Net和残差之后的MaskedMSE,MaskedMSE定义如下:

        def MaskedMSE(targets, outputs, targets_lengths, hparams, mask=None):
            '''Computes a masked Mean Squared Error
            '''
        
            #[batch_size, time_dimension, 1]
            #example:
            #sequence_mask([1, 3, 2], 5) = [[[1., 0., 0., 0., 0.]],
            #                               [[1., 1., 1., 0., 0.]],
            #                               [[1., 1., 0., 0., 0.]]]
            #Note the maxlen argument that ensures mask shape is compatible with r>1
            #This will by default mask the extra paddings caused by r>1
            if mask is None:
                mask = sequence_mask(targets_lengths, hparams.outputs_per_step, True)
        
            #[batch_size, time_dimension, channel_dimension(mels)]
            ones = tf.ones(shape=[tf.shape(mask)[0], tf.shape(mask)[1], tf.shape(targets)[-1]], dtype=tf.float32)
            mask_ = mask * ones
        
            with tf.control_dependencies([tf.assert_equal(tf.shape(targets), tf.shape(mask_))]):
                return tf.losses.mean_squared_error(labels=targets, predictions=outputs, weights=mask_)

        即:在计算预测和Ground-Truth序列的均方差时,对超过Ground-Truth长度处的方差置0。

      • self.stop_token_loss

        Ground-Truth的stop-token概率和预测的stop-token概率两者的交叉熵,stop-token是通过一个简单的逻辑回归预测,超过0.5则停止序列生成。和MaskedMSE类似,MaskedSigmoidCrossEntropy定义如下:

        def MaskedSigmoidCrossEntropy(targets, outputs, targets_lengths, hparams, mask=None):
            '''Computes a masked SigmoidCrossEntropy with logits
            '''
        
            #[batch_size, time_dimension]
            #example:
            #sequence_mask([1, 3, 2], 5) = [[1., 0., 0., 0., 0.],
            #                               [1., 1., 1., 0., 0.],
            #                               [1., 1., 0., 0., 0.]]
            #Note the maxlen argument that ensures mask shape is compatible with r>1
            #This will by default mask the extra paddings caused by r>1
            if mask is None:
                mask = sequence_mask(targets_lengths, hparams.outputs_per_step, False)
        
            with tf.control_dependencies([tf.assert_equal(tf.shape(targets), tf.shape(mask))]):
                #Use a weighted sigmoid cross entropy to measure the <stop_token> loss. Set hparams.cross_entropy_pos_weight to 1
                #will have the same effect as  vanilla tf.nn.sigmoid_cross_entropy_with_logits.
                losses = tf.nn.weighted_cross_entropy_with_logits(targets=targets, logits=outputs, pos_weight=hparams.cross_entropy_pos_weight)
        
            with tf.control_dependencies([tf.assert_equal(tf.shape(mask), tf.shape(losses))]):
                masked_loss = losses * mask
        
            return tf.reduce_sum(masked_loss) / tf.count_nonzero(masked_loss, dtype=tf.float32)
      • self.regularization_loss

        所有变量的正则化Loss

        # Get all trainable variables
        all_vars = tf.trainable_variables()
        regularization = tf.add_n([tf.nn.l2_loss(v) for v in all_vars
                                   if not ('bias' in v.name or 'Bias' in v.name)]) * reg_weight
      • self.linear_loss

        当特征网络预测线性谱时,特有的Loss。特别加大低于2000Hz线性谱的Ground-Truth和预测的Loss,这是因为低频对理解音频十分重要

        def MaskedLinearLoss(targets, outputs, targets_lengths, hparams, mask=None):
            '''Computes a masked MAE loss with priority to low frequencies
            '''
        
            #[batch_size, time_dimension, 1]
            #example:
            #sequence_mask([1, 3, 2], 5) = [[[1., 0., 0., 0., 0.]],
            #                               [[1., 1., 1., 0., 0.]],
            #                               [[1., 1., 0., 0., 0.]]]
            #Note the maxlen argument that ensures mask shape is compatible with r>1
            #This will by default mask the extra paddings caused by r>1
            if mask is None:
                mask = sequence_mask(targets_lengths, hparams.outputs_per_step, True)
        
            #[batch_size, time_dimension, channel_dimension(freq)]
            ones = tf.ones(shape=[tf.shape(mask)[0], tf.shape(mask)[1], tf.shape(targets)[-1]], dtype=tf.float32)
            mask_ = mask * ones
        
            l1 = tf.abs(targets - outputs)
            n_priority_freq = int(2000 / (hparams.sample_rate * 0.5) * hparams.num_freq)
        
            with tf.control_dependencies([tf.assert_equal(tf.shape(targets), tf.shape(mask_))]):
                masked_l1 = l1 * mask_
                masked_l1_low = masked_l1[:,:,0:n_priority_freq]
        
            mean_l1 = tf.reduce_sum(masked_l1) / tf.reduce_sum(mask_)
            mean_l1_low = tf.reduce_sum(masked_l1_low) / tf.reduce_sum(mask_)
        
            return 0.5 * mean_l1 + 0.5 * mean_l1_low

        可以阅读hp.mask_decoder == False时的Loss计算,即不对decoder进行Mask,更容易理解计算整个网络Loss的方法。

    • 优化

      使用AdamOptimizer优化,值得注意的是,默认学习率策略:

      • < 50k steps: lr = 1e-3

      • [50k, 310k] steps: lr = 1e-3 ~ 1e-5,指数下降:tf.train.exponential_decay

      • > 310 k steps: lr = 1e-5

        # Compute natural exponential decay
        lr = tf.train.exponential_decay(learning_rate = init_lr,
                                        global_step = global_step - hp.tacotron_start_decay,  # lr = 1e-3 at step 50k
                                        decay_steps = self.decay_steps,
                                        decay_rate = self.decay_rate,  # lr = 1e-5 around step 310k
                                        name='lr_exponential_decay')
        
        # clip learning rate by max and min values (initial and final values)
        return tf.minimum(tf.maximum(lr, hp.tacotron_final_learning_rate), init_lr)

        学习率指数衰减:

        decayed_learning_rate=learining_rate*decay_rate^(global_step/decay_steps)

        参见:Tensorflow中tf.train.exponential_decay函数(指数衰减法)

    ClariNet

    ClariNet改进重点在WaveNet。论文地址:ClariNet: Parallel Wave Generation in End-to-End Text-to-Speech

    论文贡献:

    • 单高斯简化parallel WaveNet的KL目标函数,改进了蒸馏法(distillation)算法,使得结构更简单,更稳定
    • 通过Bridge-net连接了Tacotron(特征预测网络)和WaveNet,彻底端到端

    前置知识

    • KL散度
      \[ \begin{align*} KL(P||Q)&=\int_{-\infty }^{+\infty}p(x)log\frac{p(x)}{q(x)}dx\\ &=\int_{-\infty}^{+\infty}p(x)logp(x)-\int_{-\infty}^{+\infty}p(x)logq(x)\\ &=-H(P)+H(P,Q) \end{align*} \]
      其中,\(-H(P)\)为固定值,\(H(P,Q)\)为交叉熵。最小化\(KL(P||Q)\),等价于最小化交叉熵。散度是差值的意思,散度越小,两个分布越相像。

      KL散度是非负的,这种度量是不对称的,也即是\(KL(P||Q)\neq KL(Q||P)\)

      31039392.jpg

      现在希望使用简单分布\(q\)拟合复杂分布\(p\),使用\(KL(q||p)\)做最优化,是希望p(x)为0的地方q(x)也为0,否则

      \(\frac{q(x)}{p(x)}\)会很大(上图中右侧两张图);使用\(KL(p||q)\)做最优化,就是尽量避免p(x)不为0而q(x)用0去拟合,上图中最左侧的图。因此,\(KL(q||p)\)得到的近似分布\(q(x)\)会比较窄,因为其希望\(q(x)\)为0的地方比较多(上图右侧两图);而\(KL(p||q)\)得到的近似分布\(q(x)\)会比较宽,因为其希望\(q(x)\)为0的地方比较多(上图最左侧图)。

      由于\(KL(q||p)\)至少可以拟合到其中一个峰上,而\(KL(p||q)\)拟合的结果,其概率密度最大的地方可能没有什么意义,因此在通常情况下,使用简单分布\(q\)拟合复杂分布\(p\)时,\(KL(q||p)\)更符合我们的需要。

    • 变分推断

      变分推断的核心思想是:用形式简单的分布去近似形式复杂、不易计算的分布。比如,我们可以在指数族函数空间当中,选一个和目标分布最相像的分布,这样计算起来就方便多了。所谓“变分”,就是从函数空间中找到满足某些条件或约束的函数。

      参见:PRML读书会第十章 Approximate Inference(近似推断,变分推断,KL散度,平均场, Mean Field )

    之前的WaveNet可以根据任意形式的输入直接合成波形,结构是纯卷积的,没有循环层,在训练时可以在采样点的级别上并行,效率很高;但是在预测时是自回归的,即每个采样点都依赖于之前的采样点,效率很低。

    这里构建“学生”和“老师”两种网络,作为学生的网络一般比老师的网络结构更简单,但是希望凭借学生这种简单的结构学到老师的精华,这种在网络间传授知识的过程称作“蒸馏”(distill)。一般来说,蒸馏的过程是让学生网络的输出分布尽可能逼近老师网络的输出分布,这一般是通过最小化两个网络输出分布之间的KL散度实现的。

    之前WaveNet的输出层是一个分类层,输出0~255的离散样本值,这不适合从老师传授给学生,于是parallel WaveNet的作者们将输出改造为连续的mixture of logistics(MoL)分布,而学生网络的输出分布使用的是logistic inverse auto-regressive flow,学生网络虽然也称“auto-regressive”,但实际上合成是并行的。parallel WaveNet的蒸馏过程使用了大量的logistic函数,这导致学生网络和老师网络的输出分布的KL散度很难计算,不得不用蒙特卡洛方法近似,于是网络的蒸馏过程容易出现数值不稳定的情况。

    ClariNet将老师的输出分布简化为单高斯分布,并通过实验证明这并不影响合成效果。学生的输出分布改为了高斯逆回归流(Gaussian IAF),简化的好处在于两边输出分布的KL散度能够写出显式表达式,蒸馏过程可以通过正常的梯度下降法来完成。

    论文中,使用一种改进的KL散度衡量学生和老师网络输出分布的差异:
    \[ KL(q||p)=log\frac{\sigma_p}{\sigma_q}+\frac{\sigma_q^2-\sigma_p^2+(\mu_p-\mu_q)^2}{2\sigma_p^2} \]

    转载于:https://www.cnblogs.com/mengnan/p/9622043.html

    展开全文
  • 将方波振荡器的信号分频滤波产生不同频率正弦波,经移相放大等处理后,分别根据方波三角波谐波组成关系,再合成方波和三角波。滤波模块对同一信号进行二次滤波,先用开关电容滤波器滤波,再经三阶巴特沃斯低通...
  • 将方波振荡器的信号分频滤波产生不同频率正弦波,经移相放大等处理后,分别根据方波三角波谐波组成关系,再合成方波和三角波。滤波模块对同一信号进行二次滤波,先用开关电容滤波器滤波,再经三阶巴特沃斯低通...
  • 依据直接数字频率合成技术(DDS)工作原理,在simulink软件搭建系统仿真模型输出正弦信号,在此基础上实现了两种压缩ROM查询表数据量的方法来抑制杂散,并把这两种压缩方法相结合使得压缩比达到了1:42.67,有效...
  • 实验分别利用矩形波、三角波、正弦波进行相位调制, 得到了相应波形的激光输出; 利用不同参量矩形波进行相位调制, 可以得到重复频率从1~500 kHz,占空比从20%~80%可调的脉冲光输出, 在重复频率为500 kHz时, 脉宽可达...
  • 不同频率,相位,幅度的三角波合成信号    上回我们通过只改变正弦和余弦频率的方式,得到了冲击串信号和Sinc函数,这两个常见信号。这次我们不仅要改变各阶谐波的频率(k*fo)还要改变他们的幅值(ak,bk)和...

    用不同频率,相位,幅度的三角波合成信号

     

        上回我们通过只改变正弦和余弦频率的方式,得到了冲击串信号和Sinc函数,这两个常见信号。这次我们不仅要改变各阶谐波的频率(k*fo)还要改变他们的幅值(ak,bk)和相位(φk),去合成更多的波。

    谐波信号的叠加(不同频率,不同幅度,不同相位):

         刚才我们所合成的信号非常有限,因为我们只改变了三角函数中的频率,而没有改变幅度和相位这两个参数。现在我们试着改变不同谐波中的幅度和相位,我们就能合成几乎所有类型的波。这就是傅里叶分析的核心思想!

     

    用正弦波/余弦波合成方波:

         用正弦波合成方波时,只需把频率是基波频率f0的奇整数倍的正弦谐波(奇函数),即,1f0,3f0,5f0....., 逐一相加就行了。但在相加之前需要把正弦函数的幅度A改为其频率的倒数,即,A = 1/1, 1/3,1/5.....。最终合成出来的方波还是一个奇函数。

     

         用余弦波合成方波时,方法和合成正弦波的方式基本相同。不是上面所说的“逐一相加”,而是一正一负,或者说是一加一减。最终合成出来的方波还是一个偶函数。

     

    具体的正弦波和余弦波的合成公式如下:

     

    奇数项谐波和偶数项谐波的相互抵消:

         请注意,不论是用正弦还是用余弦来合成方波时,所选用的谐波系数K都是奇数。主要原因就是,奇数项的谐波(不论是正弦还是余弦,即,不论是奇函数,还是偶函数)会抵消偶数项的谐波。换句话说,偶数项/阶(even order)的谐波是具有破坏性的(destructive),因此不常被用于信号的分析和构建。例如在下图中,可以明显的看到这一点。

     

         这里,频率为1,3Hz的谐波和频率为2,4Hz的谐波在图中所指出的位置(t = 0.5 秒)是正好相反的(antipodal)。之所以,无穷多个正弦波和余弦波的叠加(取绝对值)能够被用来合成冲击串信号也是正是利用了这一原理,即,偶数阶谐波的破坏性。见下图。

     

     

     

    颠覆了傅里叶变换的Gibbs现象

    Gibbs现象:

        在合成方波的过程中,我们最初只用了一个基波+三个谐波合成的信号就很像方波了,那么是不是只要谐波的数量足够多,最终合成的波形就能够和方波一模一样吗?答案是否定的。

        随着谐波数量的增加,如下图中谐波的数量增加到100项,最终合成的波形确实越来越像方波,但是始终会波形的边缘处产生剧烈的振荡/抖动(ripple),这就是著名的Gibbs现象。Gibbs现象同时还是一个非常优秀的特例,彻底的否定了另一个鼎鼎大名的定理,即,傅里叶指出所有信号都可以用傅里叶级数来表达。Gibbs现象说明了傅里叶级数无法表示不连续,有间断的信号。

     

    如何合成锯齿波:

    锯齿波(sawtooth wave)是奇函数,所以只能用正弦函数来合成。锯齿波的合成公式如下:

         公式中的系数使得各阶谐波对于整个函数的贡献随着谐波系数k(即,谐波频率)的增加而减少,这一点和方波的合成是一样的。

     

           跟方波的合成不同的是,锯齿波的合成只需要少量的几个谐波就能达到很逼真的锯齿波,例如,20个谐波。但是,对方波而言,往往需要很多谐波的叠加才能达到很好的逼近,如100个谐波。这是因为,方波的不连续和跳变要比锯齿波厉害的多,所以要用更多的谐波去叠加。

     

    80年代录像带大放送:(写在最后)

    下面的视频中,从1阶谐波增加到2阶的时候波形没有发生改变,为什么呢?别忘了方波的合成中,只有叠加了奇数波。

     

    下图是从0阶一直加到了100阶,出现了明显的Gibbs现象。

    谢谢收看!

    再见。

     

    鸣谢:

    【1】http://complextoreal.com/

    【2】 signals and systems --- 奥本海姆

     

    圣经》路加福音 16章:10 ------ 人 在 最 小 的 事 上 忠 心 , 在 大 事 上 也 忠 心 。 在 最 小 的 事 上 不 义 , 在 大 事 上 也 不 义 。

    *配图与正文内容无关

    展开全文
  • MATLAB语音分析

    2013-03-07 14:37:43
    电话按键的声音是用不同频率正弦波合成的,所以本资料在于用matlab来分析电话语音的频谱分析
  • 主要原理就是将对应音符的频率以不同频率正弦波输出播放: clc clear y21=523; y22=587; y23=659; y24=698; y25=784; y26=880; y27=988; %形成一段音乐 小星星乐谱 f1 = [y21,y21,y25,y25,y26,y26,y25,y24,y24,...
  • 谐波分量

    2021-01-01 23:06:19
    谐波就是一组(很多个)频率成整数倍的正弦波zhi。 要明白谐波就要明白基波,基波... 反 过来说,也就是不同频率正弦波可以合成一个非正弦周期波。 这些正弦 波叫做非正弦波的谐波分量,其中频率与之相同的成分称为
  • 该器件采用第三代频率合成技术—直接数字频率合成技术,以“相位”的概念进行频率合成,不仅可以产生不同频率正弦波,而且可以控制波形的初始相位,还可以产生三角波和方波。主要介绍AD9833的基本结构、功能特性及...
  • 它是继直接频率合成和间接频率合成之后发展起来的第三代频率合成技术,突破了前两代频率合成法的原理,从“相位”的概念出发进行频率合成,这种方法不仅可以产生不同频率正弦波、方波、三角波,而且可以控制波形的...
  • 过去常采用人工测量的方法,通过输出不同频点的正弦信号去激励电路网络,然后测量电路网络的响应,一个测试往往需花费较长的时间才能完成。采用专用的扫频仪、网络分析仪等实现电路网络的频率特性测量虽只需几分钟,...
  • EVAL-CN0304-SDZ评估板可以输出三种基本波行,正弦波、三角波、方波,最高频率为18MHz。 可以配合ADI官方的另外一块控制板EVAL-SDP-CB1Z使用。测试系统框图如下: 附件提供了EVAL-CN0304-SDZ评估板原理图、PCB源文件...
  • 提出了以AVR单片机中的 ATmega8为主控芯片,利用直接数字频率合成法(DDS)的原理,从 “相位”的概念出发...这种方法不仅可以给出不同频率正弦波,而且还可以给出不同初始相位的正弦波 ,甚至可以给出各种任意波形 。
  • 录音与播放示例, 以Android AAudio为例

    千次阅读 2019-09-10 21:40:02
    最近看了谷歌的codelabs介绍AAudio的示例, 写...1. 示例1, 主要讲了怎么创建一个声音合成器, 生成不同频率正弦波. https://codelabs.developers.google.com/codelabs/making-waves-1-synth/#0 这个程序可提升的...
  • 它是继直接频率合成和间接频率合成之后发展起来的第三代频率合成技术,突破了前两代频率合成法的原理,从“相位”的概念出发进行频率合成,这种方法不仅可以产生不同频率正弦波、方波、三角波,而且可以控制波形的...
  • 它是继直接频率合成和间接频率合成之后发展起来的第三代频率合成技术,突破了前两代频率合成法的原理,从“相位”的概念出发进行频率合成,这种方法不仅可以产生不同频率正弦波、方波、三角波,而且可以控制波形的...
  • 傅里叶级数及傅里叶变换

    万次阅读 多人点赞 2018-06-17 23:59:23
    周期信号的傅里叶级数:用正弦信号逼近方波:如下图:船的振荡频率为 ,跷跷板的频率为 ,小女孩的玩具的振荡频率为 ,如果排列合理的话,三者的波形能合成类似于方波的样子,且此频率规律的正弦波越多,合成波形...
  • 基本放大电路 一.放大的代理 以话筒与扬声器为例,声音(信号源)传入话筒...任何模拟信号通过傅里叶分析,都可看作不同频率正弦波合成 放大的本质:能量的控制 放大的特征:功率放大 放大的基本要求:不失...
  • 噪声是什么? 1.感性认识 一个正常工作的放大电路,当输入端接地时,用示波器观察输出,你...噪声可以看做不同频率正弦波合成,而且在无穷大时间段内,各频率分量的有效值是确定的。在任意一个窄小时间段内,各...
  • 计算机网络笔记二

    2017-09-11 20:30:04
    不管是模拟信号还是数字信号,都是由大量频率不同正弦波信号合成的。 信号理论解释为:任何一个信号都是由无数个谐波(正弦波)组成的。数学解释为:任何一个函数都可以用傅里叶级数展开为一个常数和无穷个正弦...

空空如也

空空如也

1 2 3
收藏数 56
精华内容 22
关键字:

不同频率正弦波合成