如何找到不均匀波形的包络
How to find envelope of uneven waveform
我有一个波形,其中包含从射频收发器获得的相移信息。它不是规则的波形,而是不均匀的,如下图所示。我已经使用油漆绘制了信封图,我该如何在 MATLAB 中执行此操作?
我也附上了waveform.csv。在我的 MATLAB 代码中,我已经使用平均滤波器来平滑原始信号。
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() {
}
}
我有一个波形,其中包含从射频收发器获得的相移信息。它不是规则的波形,而是不均匀的,如下图所示。我已经使用油漆绘制了信封图,我该如何在 MATLAB 中执行此操作?
我也附上了waveform.csv。在我的 MATLAB 代码中,我已经使用平均滤波器来平滑原始信号。
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() {
}
}