【信号处理】内插器原理和MATLAB仿真

简介:


这篇文章将讲述内插器的框架和线性内插器的原理。线性内插器有一个很常见的用途,就是用于图像的缩放,于是我突然好奇,能不能对一段采样频率Fs为44.1kHz的音频进行采样频率为Fs/8的降采样/下采样,再用内插器有效地复原出原音频信号呢?答案留在后面。

一、内插器


首先介绍内插这个概念。按 Digital Signal Processing- A computer-Based Approach 一书中所说:“降低序列抽样率的过程称为抽取,而实现抽样的多抽样率结构称为抽取器,所以,增加抽样率这个相反过程就称为内插。用于内插的多抽样率结构称为内插器。”

内插器的种类其实有不少种,分别用于不同的系统中。常见的分为线性内插器和非线性内插器。在这里介绍线性内插器。

线性内插器的原理相当简单,我们先看看他的结构图:

 其中的 ↑L 是上采样器,它完成什么功能呢?我们看图即可:

首先假如x[n]长这样:

 那么它上采样之后,比如L=4(注意这里,L为多少则频率乘以L倍,直观点就是两个值的间隔多L-1的插值):

 所以,上采样的过程实际上就是往中间插入了L-1个零点。注意这里是数字信号,所以n是正整数,但是对应到时域,那就是在原本间隔为Ts的两个值有等间隔地插入三个值,相当于Ts除以了4,也即采样率Fs乘以了4。若不是很清楚这个过程可以去看本专栏的另一篇文章:【信号处理】采样定理的深入浅出。

得到上采样的序列后,采样器会根据得到的序列计算一个全新的序列,其计算式如下:

 内插之后就得到:

 我们可以看到,L=4的内插器的输入输出关系为:若此时n在插入的零值的位置上,内插的值就受到旁边的两个原本的值的影响,但是若n在原本的值上,它只受旁边三个距离以内的影响,而它三个距离以内都是0.所以原本的值不会被影响到,也就不会有失真

读者必须注意,这个得到的结果是根据上采样之后,插值仍然为0的 x_u[n] 计算而来的,刚学的时候通常会疑惑,比如我从n=0一直计算到n=5,那么原本为0的插值应该有值了才对啊,这样的话不会影响到原本的值吗?但其实算法不是这样的,它是像读表一样,计算内插后的序列 y[n] 的值的时候,我读 x_u[n] 的需要的值,进行计算后,填入 y[n]

二、MATLAB 仿真


这里是对音频信号的仿真,注意我这里用了我本专栏另一篇文章【信号处理】ADC中量化的更多细节的量化方法编码和解码。然后用双线性内插器插值。

%%
clear;clc;close all;
% Sampling at 44.1 kHz
[audio_signal,Fs]=audioread('Jacky_Audio_Signal.mp3'); % Sampling Interval: Ts=1/Fs

%%
% Sampling at Ts=8*(1/Fs)
audio_signal_sampled=audio_signal(1:8:end,1);
%sound(audio_signal_sampled,Fs/4);

%%
% non-uniform Quantizing & Source Coding
len_sig=size(audio_signal_sampled,1); % Length of the audio signal
parallel_code=zeros(len_sig,8); % A store
max_value=max(audio_signal_sampled); 
piece=max_value/2048;
for i=1:1:len_sig
    coding_value=audio_signal_sampled(i);
    
    % Step1: Sign Code
    if coding_value>0
        parallel_code(i,1)=1;
    else
        parallel_code(i,1)=0;
    end
    
    % Step2: Segment Codes
    coding_value_abs=abs(coding_value);
    if coding_value_abs>=max_value/2
        parallel_code(i,2)=1;
        parallel_code(i,3)=1;
        parallel_code(i,4)=1;
        
        % Step3: Inner Segment Codes
        bit_string=dec2bin( (coding_value_abs-max_value/2)/(64*piece),4);
        parallel_code(i,5)=str2double(bit_string(1));
        parallel_code(i,6)=str2double(bit_string(2));
        parallel_code(i,7)=str2double(bit_string(3));
        parallel_code(i,8)=str2double(bit_string(4));
        
    elseif (coding_value_abs>=max_value/4)&(coding_value_abs<max_value/2)
        parallel_code(i,2)=1;
        parallel_code(i,3)=1;
        parallel_code(i,4)=0;
        bit_string=dec2bin( (coding_value_abs-max_value/4)/(32*piece),4);
        parallel_code(i,5)=str2double(bit_string(1));
        parallel_code(i,6)=str2double(bit_string(2));
        parallel_code(i,7)=str2double(bit_string(3));
        parallel_code(i,8)=str2double(bit_string(4));
    elseif (coding_value_abs>=max_value/8)&(coding_value_abs<max_value/4)
        parallel_code(i,2)=1;
        parallel_code(i,3)=0;
        parallel_code(i,4)=1;
        bit_string=dec2bin( (coding_value_abs-max_value/8)/(16*piece),4);
        parallel_code(i,5)=str2double(bit_string(1));
        parallel_code(i,6)=str2double(bit_string(2));
        parallel_code(i,7)=str2double(bit_string(3));
        parallel_code(i,8)=str2double(bit_string(4));
    elseif (coding_value_abs>=max_value/16)&(coding_value_abs<max_value/8)
        parallel_code(i,2)=1;
        parallel_code(i,3)=0;
        parallel_code(i,4)=0;
        bit_string=dec2bin( (coding_value_abs-max_value/16)/(8*piece),4);
        parallel_code(i,5)=str2double(bit_string(1));
        parallel_code(i,6)=str2double(bit_string(2));
        parallel_code(i,7)=str2double(bit_string(3));
        parallel_code(i,8)=str2double(bit_string(4));
    elseif (coding_value_abs>=max_value/32)&(coding_value_abs<max_value/16)
        parallel_code(i,2)=0;
        parallel_code(i,3)=1;
        parallel_code(i,4)=1;
        bit_string=dec2bin( (coding_value_abs-max_value/32)/(4*piece),4);
        parallel_code(i,5)=str2double(bit_string(1));
        parallel_code(i,6)=str2double(bit_string(2));
        parallel_code(i,7)=str2double(bit_string(3));
        parallel_code(i,8)=str2double(bit_string(4));
    elseif (coding_value_abs>=max_value/64)&(coding_value_abs<max_value/32)
        parallel_code(i,2)=0;
        parallel_code(i,3)=1;
        parallel_code(i,4)=0;
        bit_string=dec2bin( (coding_value_abs-max_value/64)/(2*piece),4);
        parallel_code(i,5)=str2double(bit_string(1));
        parallel_code(i,6)=str2double(bit_string(2));
        parallel_code(i,7)=str2double(bit_string(3));
        parallel_code(i,8)=str2double(bit_string(4));
    elseif (coding_value_abs>=max_value/128)&(coding_value_abs<max_value/64)
        parallel_code(i,2)=0;
        parallel_code(i,3)=0;
        parallel_code(i,4)=1;
        bit_string=dec2bin( (coding_value_abs-max_value/128)/(1*piece),4);
        parallel_code(i,5)=str2double(bit_string(1));
        parallel_code(i,6)=str2double(bit_string(2));
        parallel_code(i,7)=str2double(bit_string(3));
        parallel_code(i,8)=str2double(bit_string(4));
    elseif (coding_value_abs>=0)&(coding_value_abs<max_value/128)
        parallel_code(i,2)=0;
        parallel_code(i,3)=0;
        parallel_code(i,4)=0;
        bit_string=dec2bin(coding_value_abs/piece,4);
        parallel_code(i,5)=str2double(bit_string(1));
        parallel_code(i,6)=str2double(bit_string(2));
        parallel_code(i,7)=str2double(bit_string(3));
        parallel_code(i,8)=str2double(bit_string(4));
    end
end

%%
% Source Decoding - Decode Quantilization
[nov,~]=size(parallel_code); % The amount of value

%%
% Decoding (This step takes too much time, and hopefully I can solve it in the future
audio_signal_retrieve=zeros(nov,1);
max_value=max(audio_signal_sampled); 
piece=max_value/2048;
for i=1:1:nov
    code=parallel_code(i,:);
    value=0;
    % Segment Decode
    seg_index=code(2)*2^2+code(3)*2^1+code(4);
    if seg_index==0
        gap=(max_value/128)/16;
        step=0;
    elseif seg_index==1
        gap=(max_value/128)/16;
        step=16*piece;
    elseif seg_index==2
        gap=(max_value/64)/16;
        step=32*piece;
    elseif seg_index==3
        gap=(max_value/32)/16;
        step=64*piece;
    elseif seg_index==4
        gap=(max_value/16)/16;
        step=128*piece;
    elseif seg_index==5
        gap=(max_value/8)/16;
        step=256*piece;
    elseif seg_index==6
        gap=(max_value/4)/16;
        step=512*piece;
    elseif seg_index==7
        gap=(max_value/2)/16;
        step=1024*piece;
    end
    
    % Inner Segment Code
    inner_seg_index=2^3*code(5)+2^2*code(6)+2*code(7)+code(8);
    value=inner_seg_index*gap+step;
    
    % Sign
    if code(1)==0
        value=-value;
    end
    audio_signal_retrieve(i)=value;
end

%%
% Test the audio
sound(audio_signal_retrieve,Fs/8);

%%
% 2 Factors Linear Interpolation
audio_signal_litp=zeros(2*nov,1);
audio_signal_litp(2:2:end)=audio_signal_retrieve;  % Upper Sampling
buffer=zeros(2*nov,1);
for i=3:2:2*nov-1
    buffer(i)=0.5*audio_signal_litp(i-1)+0.5*audio_signal_litp(i+1);
end
buffer(1,1)=audio_signal_litp(2,1)*0.5;
audio_signal_litp=audio_signal_litp+buffer;

%%
% Test the audio after interpolation
sound(audio_signal_litp,Fs/4);

 内插其实可以用MATLAB的函数:interp(signal,r)

signal就是你要内插的信号,r就是L,即上采样倍数。

三、仿真结果


我发现,对音频进行线性内插好像不是很能恢复原来的音质,但是内插绝对不会让原音频失真。内插后听起来会有些刺耳的杂音,估计是内插后得到的,总之效果不太好。

  • 4
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值