function [correctedsignal] = phasecorrection( signal, fs, f90, inv, bypass, delay )
%Phase correction of a single channel signal using a first order all-pass
%filter, a 180 degree inversion and a simple delay line.
%By Daniel Clinch, University of Sydney
%
% [correctedsignal] = phasecorrection( signal, fs, f90, inv, bypass, delay )
% [correctedsignal] = phasecorrection( signal, fs, f90, inv, bypass )
% [correctedsignal] = phasecorrection( signal, fs, f90, inv )
% [correctedsignal] = phasecorrection( signal, fs, f90 )
%
% phasecorrection alters the phase of a single channel signal from zero
% to 180 degrees using a first order all-pass filter and can also perform
% a 180 phase inversion.
%
% signal
% This array represents the single channel input signal that is
% to be processed.
%
% fs
% This value is the sampling frequency of the input signal.
%
% f90
% This is the frequency component of the input signal that will have a
% phase shift of 90 degrees with respect to the input. An all pass filter
% does not change the amplitude of the frequency components, it
% progressively delays the frequency components resulting in an increasing
% phase shift with frequency. In the case of a first order all pass filter
% there is very little phase shift at frequencies close to zero Hertz so
% the output and the input signals are relatively in phase. However at
% frequencies approaching the Nyquist frequency the delay is at its
% maximum and these higher frequencies will be close to 180 degrees out
% of phase when compared to the input.
%
% inv
% This performs a 180 phase inversion or flip of the input signal
% and can only have a value of 1 or -1. If inv has a value of -1 the
% function will perform the flip. This input value is optional and if
% left out then the function assumes a value of 1 and will not perform
% the inversion.
%
% bypass
% This allows the all-pass filter to be bypassed if only the 180 degree
% phase invert is required. A value of 0 will bypass the all-pass filter
% while a value of 1 will run the all-pass filter. This input value is
% optional and if left out a value of 1 is assumed and the all-pass
% filter is run
%
% delay
% This is a simple delay line for correcting time delay issues. The delay
% time is in milliseconds.
%
%References
%Zolzer, Udo, DAFX Digital Audio Effects, New York, John Wiley and sons
%Ltd, 2002. Ch 3, p 66.
%
if nargin < 6, delay = 0; end % if there are only five input arguments
% presented then the value of delay is set to zero
if nargin < 5, bypass = 1; end % if there are only four input arguments
% presented then the value of bypass is set to one and the all pass filter
% will be active
if nargin < 4, inv = 1; end %if there are only three input arguments
% presented then the value of inv is set to one
%delay
del = fs .* (delay/1000); %This converts the input delay time from
% millseconds to samples
N = zeros (del,1); %Creates a vertical array of zeros equal to the delay time
delayedsignal = [N; signal]; %Concatenates the array of zeroes to the front
% of the original signal.
%180 degree invert multiplies the signal by -1 to change the sign of the
%samples. When multiplied by one the signs are retained and the phase flip
%is not performed.
input = delayedsignal .* inv;
%allpass filter
c = (tan(pi*f90/fs)-1)/(tan(pi*f90/fs)+1); %calculates the coefficient (alpha)
%for the given cutoff frequency
BL= c; %feed forward blend coefficient (alpha)
FB= -c; %feedback blend coefficient (-alpha)
FF=1; %feed forward coefficient
apfdelay = 1; % delay of one sample for a first order all-pass filter
Delayline=zeros(apfdelay,1); % memory allocation for length Delayline
for n=1:length(input) ;
xh=input(n)+FB*Delayline(apfdelay) ;
y(n)=FF*Delayline(apfdelay)+BL*xh;
Delayline=[xh;Delayline(1:apfdelay-1)];
end;
apfout = y'; %corrects the delay output by transposing a row to a column
%Output
switch bypass
case 0
correctedsignal = input; % Do not run allpass filter
case 1
correctedsignal = apfout; % Run all pass filter
end