I am working on a code where digital mixing is to be performed for down-conversion of incoming signal. The mixer signal is created using the phase accumulation approach. However it was observed that the phase error between a signal created with phase accumulation vs that created with a fixed duration time signal had some error which was observed to grow. Can anyone explain the difference and suggest how to avoid this. Code and example result below.

clear all;close all;
sig_mix_lref=cos(2*pi*f_mix*t)+j*sin(2*pi*f_mix*t);%create mixer reference
ph_ref=wrapToPi(2*pi*f_mix*t);%phase ref for comparison with accumulated phase

ph_acc(1)=0;%init phase
ph_inc=2*pi*f_mix*1/fs;%phase increment at desired rate

for i=1:2048:length(sig_mix_lref)-2048
    for k=1:2048
        sig_mix_l_c(k)=exp(1*j*ph_acc(ind-1));%create mixer block later appended for comparison with reference
        %do block mixing here with incoming data stream



title('mixer comparison error real part')

title('mixer comparison error imag part')

title('mixer accum phase error wrt to ref phase') 

enter image description here enter image description here enter image description here

Although the error scale is negligible, but can anyone explain the reason for growth, how to resolve it?


This is numerical noise. You are using floating point math which is never "exact" but only approximate. The problematic line here is

ph_ref=wrapToPi(2*pi*f_mix*t);%phase ref for comparison with accumulated phase

The argument into your phase wrapping function can get large and the larger the argument, the larger the phase wrapping error will be.

You can simulate the effect by taking any angle add a large number of multiples of $2\pi$ unwrap it and look at the difference to the original angle. The result looks roughly like the graph below (for 64 bit double precision floating point).

Note that the phase accumulation is better. It always keeps the phase between $0$ and $2\pi$ and the unwrapping can simply be done with if phase > 2*pi, phase = phase - 2*pi; end which avoids division and/or modulo calculations.

enter image description here

Here is the code to generate this graph

%% look at phase wrapping error as a function of length

a = 2*pi*(0.5:999.5)'/1000; % test vector with 100 angles
numberOfPeriods = 10.^(0:15)'; % number of peroids to unwrap
n = length(numberOfPeriods);
errorDb = zeros(n,1);
% loop over all prders of magnitudes
for i = 1:n
  x = numberOfPeriods(i)*2*pi;
  % wrap angle to [0, 2*pi|
  wrappedAngle = (x+a)-2*pi*floor((x+a)./(2*pi));
  % calculate  angle difference
  angleDiff = wrappedAngle-a;
  % relative error in dB
  errorDb(i) = 10*log10(mean(angleDiff.^2)./mean(a.^2));

%% and plot the result
h = semilogx(numberOfPeriods,errorDb);
xlabel('Number of Periods in vector');
ylabel('Relative error in dB');
title('Phase wrapping error');
  • $\begingroup$ Thank you for your response. I will go simulate and go through what you said in detail, on a side note, is this phenomenon of any practical concern for such applications i.e is such a drift acceptable? $\endgroup$ – malik12 Jun 8 at 12:42
  • $\begingroup$ Depends a lot on your specific application, but clock drift it is indeed a concern in many cases and a PLL and/or some sort of clock recovery is required. It's not necessarily due to numerical issues but also due to independent clocks drifting against each other. No two oscillators have exactly the same frequency unless you lock them somehow. $\endgroup$ – Hilmar Jun 8 at 13:25

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.