MATLAB: Detecting transition in a noisy square wave

denoisefilterMATLABsquare wave

Hello guys,
I have a sequence of number that is similar to a pulse with noisy and I want to detect where the transition happens, but I couldn't get the correct result by using wdenoise(), sgolayfilt() or filter() together with ischange()… What may you suggest me to use in order to solve this problem?
Thanks in advance, Madjer.

Best Answer

Madjer, I think simple thresholding with removal of short pulses should work. Just remove pulses that are shorter than the known width - than the minimum width you believe the rectangular pulse should be. Here's a complete demo:
% Initialization steps. Brute force cleanup of everything currently existing to start with a clean slate.
% Just for the demo. If you put this into your own function you'll want to get rid of the close and clear commands.
clc; % Clear the command window.
fprintf('Beginning to run %s.m ...\n', mfilename);
close all; % Close all figures (except those of imtool.)
clear; % Erase all existing variables. Or clearvars if you want.
workspace; % Make sure the workspace panel is showing.
format long g;
format compact;
fontSize = 20;
y = readmatrix('a.txt');
thresholdValue = 0.6;
% writematrix(a(:), 'a.txt');
subplot(2, 3, 1)
plot(y, 'b.');
yline(thresholdValue, 'Color', 'r', 'LineWidth', 2);
grid on;
title('Original Noisy Signal', 'FontSize', fontSize);
xlabel('x', 'FontSize', fontSize);
ylabel('y', 'FontSize', fontSize);
% Get a histogram, just for curiosity.
subplot(2, 3, 2)
histogram(y);
grid on;
title('Histogram of Original Signal', 'FontSize', fontSize);
xlabel('y (signal) value', 'FontSize', fontSize);
ylabel('Count', 'FontSize', fontSize);
% Find out where the signal is above the threshold.
% Threshold at 0.6
aboveThreshold = y > 0.9;
subplot(2, 3, 3)
bar(aboveThreshold);
grid on;
title('Above Threshold (Logical Index)', 'FontSize', fontSize);
xlabel('x', 'FontSize', fontSize);
ylabel('True or False', 'FontSize', fontSize);
% Get width of spikes above thresholdValue
props = regionprops(aboveThreshold, 'Area');
allAreas = [props.Area];
subplot(2, 3, 4)
histogram(allAreas);
grid on;
title('Histogram of Spike Widths', 'FontSize', fontSize);
xlabel('Pulse Width', 'FontSize', fontSize);
ylabel('Count', 'FontSize', fontSize);
% Get rid of spikes less than 5 in width
aboveThreshold2 = bwareafilt(aboveThreshold, [5, inf]);
subplot(2, 3, 5)
bar(aboveThreshold2);
grid on;
title('Filtered, Above Threshold', 'FontSize', fontSize);
% Get rid of gaps of value 0 that are less than 500 in width
aboveThreshold3 = ~bwareafilt(~aboveThreshold2, [500, inf]);
subplot(2, 3, 5)
plot(aboveThreshold3, 'LineWidth', 2);
grid on;
ylim([0, 1.2]);
title('Filtered, Above Threshold (Logical Index)', 'FontSize', fontSize);
xlabel('x', 'FontSize', fontSize);
ylabel('True or False', 'FontSize', fontSize);
% Now find the mean value in the high and low regions.
meanHighValue = mean(y(aboveThreshold3))
meanLowValue = mean(y(~aboveThreshold3))
% Create final signal
finalSignal = meanLowValue * ones(1, length(y)); % First create the low value.
finalSignal(aboveThreshold3) = meanHighValue; % Then create the high value.
% Plot the final signal.
subplot(2, 3, 6)
plot(finalSignal, 'LineWidth', 2);
grid on;
ylim([0, 1.2]);
title('Final, Denoised Signal', 'FontSize', fontSize);
xlabel('x', 'FontSize', fontSize);
ylabel('y', 'FontSize', fontSize);
g = gcf;
g.WindowState = 'maximized'
You can adjust the threshold, shortest pulse width, final denoised signal levels, or other parameters if you want.