如何找到不均匀波形的包络

How to find envelope of uneven waveform

我有一个波形,其中包含从射频收发器获得的相移信息。它不是规则的波形,而是不均匀的,如下图所示。我已经使用油漆绘制了信封图,我该如何在 MATLAB 中执行此操作?

我也附上了waveform.csv。在我的 MATLAB 代码中,我已经使用平均滤波器来平滑原始信号。

Waveform csv file

envelope.m:

clc; clear all; close all;

%% Extract data from .csv
file = '150825_px6_human_rotcw_0to60cm_Ch1.csv';
data = csvread(file, 0, 3);

%% Shift time
shift = data(1,1);
for i = 1:length(data)
    t(i) = data(i,1) - shift;
end

%% Low pass filter
filterlen = 500;
y = myfilter(data(:,2), filterlen);

%% Plot
figure;
plot(data(:,1), data(:,2));
title('Raw signal');

figure;
plot(t(1:end-filterlen+1), y);
title('After low pass filter');

myfilter.m (simple averaging filter):

function y = myfilter(x,a) 
    for i = 1:(length(x)-(a-1))
        y(i) = sum(x(i:(i+a-1)))/a;
    end
    y = y';
end

一个简单的 envelope detector 可以根据二极管检测器的想法很容易地实现,使用:

envelope = data(1,2);
for  i = 2:length(data)
    if (abs(data(i,2)) > envelope)
        envelope = abs(data(i,2));
    else
        envelope  = envelope * decayfactor;
        data(i,2) = envelope;
    end
end

应该选择 decayfactor 使其衰减时间常数比不均匀信号的变化长得多,但小于预期信号包络带宽的倒数。您可能需要进行一些试验,但是 decayfactor=exp(-fmax/fs)(其中 fmax 是您的包络带宽,fs 是采样频率)应该是一个很好的起始值。

这之后通常会跟一个低通滤波器(例如您提供的 myfilter)。

作为基于所提供数据的示例执行,使用 decayfactor=exp(-5/5000) 和具有 300 个样本的平均过滤器 window 产生以下图(原始数据为蓝色,包络为红色):

阅读下面的代码。这应该按要求得到信封。它的简单代码任何人都可以编写类似的 class 而不是使用此实现(其 GPL 代码),我发布此代码以供参考/解释。

/*
*      _______                       _____   _____ _____  
*     |__   __|                     |  __ \ / ____|  __ \ 
*        | | __ _ _ __ ___  ___  ___| |  | | (___ | |__) |
*        | |/ _` | '__/ __|/ _ \/ __| |  | |\___ \|  ___/ 
*        | | (_| | |  \__ \ (_) \__ \ |__| |____) | |     
*        |_|\__,_|_|  |___/\___/|___/_____/|_____/|_|     
*                                                         
* -------------------------------------------------------------
*
* TarsosDSP is developed by Joren Six at IPEM, University Ghent
*  
* -------------------------------------------------------------
*
*  Info: http://0110.be/tag/TarsosDSP
*  Github: https://github.com/JorenSix/TarsosDSP
*  Releases: http://0110.be/releases/TarsosDSP/
*  
*  TarsosDSP includes modified source code by various authors,
*  for credits and info, see README.
* 
*/


package be.tarsos.dsp;

/**
 * An envelope follower follows the envelope of a signal. Sometimes the name
 * envelope detector is used. From wikipedia:
 *  <blockquote> An envelope detector
 * is an electronic circuit that takes a high-frequency signal as input and
 * provides an output which is the envelope of the original signal. The
 * capacitor in the circuit stores up charge on the rising edge, and releases it
 * slowly through the resistor when the signal falls. The diode in series
 * rectifies the incoming signal, allowing current flow only when the positive
 * input terminal is at a higher potential than the negative input terminal.
 * </blockquote>
 * 
 * The resulting envelope is stored in the buffer in the processed AudioEvent. The class can be used thusly:
 * 
 * <pre>
 * EnvelopeFollower follower = new EnvelopeFollower(44100);
 *      
 * AudioDispatcher dispatcher = AudioDispatcher.fromFloatArray(sine, 44100, 1024, 0);
 *  
 *  
 *  dispatcher.addAudioProcessor(follower);
 *  dispatcher.addAudioProcessor(new AudioProcessor() {
 *  
 *      public boolean process(AudioEvent audioEvent) {
 *          //envelope
 *          float buffer[] = audioEvent.getFloatBuffer();
 *          for(int i = 0 ; i < buffer.length ; i++){
 *              System.out.println(buffer[i]);
 *          }
 *          return true;
 *      }
 *          
 *      public void processingFinished() {
 *      }
 *  });
 *  dispatcher.run();
 *  </pre>
 *  
 * 
 * @author Joren Six
 * 
 */
public class EnvelopeFollower implements AudioProcessor {

    /**
     * Defines how fast the envelope raises, defined in seconds.
     */
    private static final double DEFAULT_ATTACK_TIME =  0.0002;//in seconds
    /**
     * Defines how fast the envelope goes down, defined in seconds.
     */
    private static final double DEFAULT_RELEASE_TIME =  0.0004;//in seconds

    float gainAttack ;
    float gainRelease;
    float envelopeOut = 0.0f;

    /**
     * Create a new envelope follower, with a certain sample rate.
     * @param sampleRate The sample rate of the audio signal.
     */
    public EnvelopeFollower(double sampleRate){
        this(sampleRate,DEFAULT_ATTACK_TIME,DEFAULT_RELEASE_TIME);
    }

    /**
     * Create a new envelope follower, with a certain sample rate.
     * @param sampleRate The sample rate of the audio signal.
     * @param attackTime Defines how fast the envelope raises, defined in seconds.
     * @param releaseTime Defines how fast the envelope goes down, defined in seconds.
     */
    public EnvelopeFollower(double sampleRate, double attackTime,double releaseTime){
        gainAttack = (float) Math.exp(-1.0/(sampleRate*attackTime));
        gainRelease = (float) Math.exp(-1.0/(sampleRate*releaseTime));
    }

    @Override
    public boolean process(AudioEvent audioEvent) {
        float[] buffer = audioEvent.getFloatBuffer();
        calculateEnvelope(buffer);
        return true;
    }

    public void calculateEnvelope(float[] buffer){
        for(int i = 0 ; i < buffer.length ; i++){
            float envelopeIn = Math.abs(buffer[i]);
            if(envelopeOut < envelopeIn){
                envelopeOut = envelopeIn + gainAttack * (envelopeOut - envelopeIn);
            } else {
                envelopeOut = envelopeIn + gainRelease * (envelopeOut - envelopeIn);
            }
            buffer[i] = envelopeOut;
        }
    }

    @Override
    public void processingFinished() {

    }
}