time-nuts@lists.febo.com

Discussion of precise time and frequency measurement

View all threads

Re: [time-nuts] frequency generation algorithm.

HM
Hal Murray
Tue, Jun 28, 2016 8:32 PM

I'm looking for a quick and dirty algorithm or method to generate a  pulse
train at arbitrary frequencies based on a fixed clock source. This will be
run as code in a timer ISR in a microcontroller, so some

Google for DDS.

The hardware implementation is simple.  Consider a register, as wide as you
like.  Think of that register as a fraction.  An overflow would be a whole
integer 1.

Each cycle, you add a number to that register.  The output signal is the top
bit.

If your register is N bits wide and you add K each cycle:
Fout = Fin * K/2^N
K = 2^N * Fout / Fin

The output signal will have spurs.  (unless there is only 1 bit turned on in K)

The output frequency will be rock solid, but it may not be the one you want.  You can get closer by making the N bigger (register wider) and filling in more low order bits of K.

If you have a graphics background, it's the same math as Bresenham's algorithm for drawing slanted lines.

--
These are my opinions.  I hate spam.

dan@irtelemetrics.com said: > I'm looking for a quick and dirty algorithm or method to generate a pulse > train at arbitrary frequencies based on a fixed clock source. This will be > run as code in a timer ISR in a microcontroller, so some Google for DDS. The hardware implementation is simple. Consider a register, as wide as you like. Think of that register as a fraction. An overflow would be a whole integer 1. Each cycle, you add a number to that register. The output signal is the top bit. If your register is N bits wide and you add K each cycle: Fout = Fin * K/2^N K = 2^N * Fout / Fin The output signal will have spurs. (unless there is only 1 bit turned on in K) The output frequency will be rock solid, but it may not be the one you want. You can get closer by making the N bigger (register wider) and filling in more low order bits of K. If you have a graphics background, it's the same math as Bresenham's algorithm for drawing slanted lines. -- These are my opinions. I hate spam.
GR
Gabs Ricalde
Wed, Jun 29, 2016 4:44 AM

I did something similar in the Beaglebone Black AM335x PRU. Division is
done using a delay loop with variable number of cycles instead of an
interrupt. Converting a delay with a fractional amount to integer is
essentially a quantization problem. I'm using a triangular PDF dither
and first order noise shaping/error feedback ([1], last slide). The
dither randomizes the errors which should eliminate spurs. The feedback
reduces the error at DC to zero but will increase the jitter at high
frequencies. Zero error at DC means the time interval error (TIE) will
not drift. I don't have equipment to test the implementation in the BBB
so I'm just assuming it works.

The disadvantage is that you need a PRNG and do fixed point arithmetic.

I think this method is related to sigma-delta fractional-N techniques in
PLLs.

[1] Udo Zölzer, Quantization_Web_Summary.pdf
http://www.hsu-hh.de/ant/index_vNIYuPdokWfAvSaT.html

The code below is a Matlab/Octave simulation which plots the TIE and TIE
jitter spectrum.

% -------------------------------------------------------------------------
% cycle period (200 MHz)
T = 1/200e6;
% output frequency
f = 24000;
% delay in clock cycles, with fractional part
delay = 1/(f*T);
% enable/disable error feedback
feedback = true;

err = 0;
t = zeros(2048, 2);
for i = 2:2048
% exact
t(i,1) = t(i-1,1) + delay;

d2 = delay - err;
% add triangular PDF noise then quantize
qd = floor(d2 + rand()+rand()-0.5);
if feedback
    err = qd - d2;
end
% delay d3 cycles
t(i,2) = t(i-1,2) + qd;

end
tie = t(:,1)-t(:,2);
plot(tie);
title('Time interval error (cycles)');
figure;
f = fft(tie);
f = f(1:end/2);
plot(20*log10(abs(f)));
title('TIE jitter spectrum');

I did something similar in the Beaglebone Black AM335x PRU. Division is done using a delay loop with variable number of cycles instead of an interrupt. Converting a delay with a fractional amount to integer is essentially a quantization problem. I'm using a triangular PDF dither and first order noise shaping/error feedback ([1], last slide). The dither randomizes the errors which should eliminate spurs. The feedback reduces the error at DC to zero but will increase the jitter at high frequencies. Zero error at DC means the time interval error (TIE) will not drift. I don't have equipment to test the implementation in the BBB so I'm just assuming it works. The disadvantage is that you need a PRNG and do fixed point arithmetic. I think this method is related to sigma-delta fractional-N techniques in PLLs. [1] Udo Zölzer, Quantization_Web_Summary.pdf http://www.hsu-hh.de/ant/index_vNIYuPdokWfAvSaT.html The code below is a Matlab/Octave simulation which plots the TIE and TIE jitter spectrum. % ------------------------------------------------------------------------- % cycle period (200 MHz) T = 1/200e6; % output frequency f = 24000; % delay in clock cycles, with fractional part delay = 1/(f*T); % enable/disable error feedback feedback = true; err = 0; t = zeros(2048, 2); for i = 2:2048 % exact t(i,1) = t(i-1,1) + delay; d2 = delay - err; % add triangular PDF noise then quantize qd = floor(d2 + rand()+rand()-0.5); if feedback err = qd - d2; end % delay d3 cycles t(i,2) = t(i-1,2) + qd; end tie = t(:,1)-t(:,2); plot(tie); title('Time interval error (cycles)'); figure; f = fft(tie); f = f(1:end/2); plot(20*log10(abs(f))); title('TIE jitter spectrum');