Reputation: 41
I'm developing a Direct Digital Synthesis (DDS) waveform generator on the Arduino Due in C/C++. But I'm first implementing an example in Matlab to make sure I understand the main components, which are: the Phase or Angle Accumulator (N-bits), the Lookup table (P-bits), and the Digital-to-Analog converter (12-bits). I understand these basic elements.
The Lookup table size will match the DAC resolution, so P=12. The Accumulator will be at least 16-bits long (N=16). So phase truncation must occur here. Therein lies my confusion and my question. How does this truncation work? What does it mean to take the P significant bits of N?
Upvotes: 3
Views: 1295
Reputation: 41
This binary math and bitwise manipulation is new to me, but I'm beginning to understand. I implemented a Direct Digital Synthesis (DDS) example in Matlab. Code below for others. May also run on Octave.
% INPUT PARAMETERS
%-----------------------
fs = 2^14; % Clock Sample Rate (hz)
NT = 1e4; % Total Samples for example
foutd = 80; % Desired Output Freq. (hz)
N = 16; % Accumulator resolution (bits)
P = 12; % Lookup Table resolution (bits)
% FREQUENCY TUNING WORD
%------------------------------
FTWf = foutd/fs*2^N; % float
FTW = round(foutd/fs*2^N); % actual integer term for accumulator
fout = FTW*fs/2^N; % actual output frequency
% SINE WAVE LOOKUP TABLE
%---------------------------
x = [0:2^P-1]';
y = sin(x*2*pi / (2^P-1) );
% INITIALIZE
%--------------------------
dt = 1/fs; % Time Step (sec)
t = [0:dt:dt*(NT-1)]'; % Time Vector
phase = zeros(NT,1); % Save phase vs. time
wave = zeros(NT,1); % Save wave amplitude vs. time
% SAMPLE THROUGH TIME
%-----------------------
pa = 0; % Phase accumulator
for ii=1:length(t)
% ACCUMULATE PHASE
pa = pa + FTW;
% ROLLOVER PHASE
if pa > 2^N
pa = 1;
end
% PHASE TRUNCATION
indx = ceil(pa * 2^(P-N));
% LOOKUP
phase(ii) = pa;
wave(ii) = y( indx );
end
figure;
subplot(211), plot(t, phase); grid on;
subplot(212), plot(t, wave); grid on; hold on
plot(t,sin(foutd*2*pi*t), 'r-.');
My next step is to implement this on the ArduinoDue. This algorithm will be the basis of the ISR interrupt function. I will definitely use binary operators to speed up the division (i.e., "Phase Truncation").
After that, I need to figure out how to handle non-integer frequency inputs.
Upvotes: 1
Reputation: 6467
In general, if you have N bit long value, one possible value, let say (in binary, i.e. epxressed using 2 bits (1's and 0's), where each bit, depending on its position represents a power of 2) is:
1000 1111 0000 1010
The most significant bits are the ones counting from left to right, i.e.: the four most significant bits in the example are: 1000. So, truncating by taking the P significant bits means that you count till P from left to right and what is left is ignored.
In decimal representation, i.e. expressed using 10 numbers (0,1,..,8,9), this will be analogous to: if your values is : 110124 and you take only P=3 significant numbers, you will remain with: 110000, i.e. the 3 least significant numbers (124) are not regarded, thereby loosing some detail.
Upvotes: 1