Real-Time DAC with DSP tool box

3 views (last 30 days)
Jaime Estarellas Cifre
Jaime Estarellas Cifre on 30 Sep 2024
I am having trouble implementing a real time DAC in my code. I am working with an NI USB-6356 and I have succesfully implemented in my Matlab Code an ADC than reads the real time signal and process it. I am trying to implement a DAC with the DSP tool box (as I did with the ADC) but for some reason it doesn't work. There aren't any apparent errors so it is being difficult to solve the problem. Can someone tell me what's happening?
dev = 'Dev1';
channels = {'ai0', 'ai1'};
ao = 'ao0'; % DAC output channel
fs = 1000; % Sampling Frequency
fc = 10; % Carrier Frequency
fsub = 10; % Subcarrier Frequency
D = 1; % Decimation factor
bits = 16; % DAC Resolution
Kc = 0.01; % Proportional control gain
% Create TimeScope for visualization
scope = timescope('NumInputPorts', 3, 'TimeSpan', 2, 'SampleRate', fs, ...
'ShowLegend', true, 'YLimits', [-5 5], ...
'Title', 'Real-time Signal and Processed Signal', ...
'ChannelNames', {'DAC Output', 'Input Signal', 'Modulated Signal'});
%% Data Acquisition Setup
daqSession = daq.createSession('ni');
for i = 1:length(channels)
addAnalogInputChannel(daqSession, dev, channels{i}, 'Voltage');
end
daqSession.Rate = fs;
daqSession.IsContinuous = true;
addAnalogOutputChannel(daqSession, dev, ao, 'Voltage');
% Initialize NCO phase accumulator
nco_phase = 0;
lh = addlistener(daqSession, 'DataAvailable', ...
@(src, event) processSignal(src,event, fc, fs, fsub, scope, nco_phase, Kc, D));
% Create an initial buffer to queue for DAC output
initialDACData = zeros(fs, 1); % Buffer of zeros to start with (length depends on initial session requirements)
queueOutputData(daqSession, initialDACData);
startBackground(daqSession);
disp('Press any key to stop');
pause;
stop(daqSession);
delete(lh);
release(scope);
disp('Stopping data acquisition...');
%% Function to process the signal and update DAC output
function OUT_signal = processSignal(src,event, fc, fs, fsub, scope, nco_phase, Kc, D)
% Input signal from ADC
signal = event.Data;
input_signal = signal(:, 2); % Input signal (from ai1)
dac_signal = signal(:, 1); % Read back the DAC signal (from ai0)
%===MANUAL NUMERICALLY CONTROLLED OSCILLATOR===
t = event.TimeStamps; % Time vector
% Set the control to adjust fc every second
onesec = 0;
tic;
persistent elapsed_time
if isempty(elapsed_time)
elapsed_time = 0;
end
% Update elapsed time
elapsed_time = elapsed_time + t(end) - t(1); % Time since last callback
% When elapsed time exceeds 1 second, update carrier frequency
if elapsed_time >= 1
% Save the current carrier frequency
% Calculate new fc using your control law: fc = fc + Kc * atan(Ik1/Qk1)
fc = fc + Kc * atan(Ik1/Qk1);
% Reset elapsed time
elapsed_time = 0;
onesec = toc;
end
% Generate DAC output
OUT_Signal = 0.5*sin(2*pi*(fc/fs)*t); % Using filtered AM as DAC signal
% Write to DAC (update Analog Output Channel)
src.queueOutputData(OUT_signal);
% Visualization
scope(input_signal, dac_signal, OUT_Signal);
end

Answers (2)

Ayush
Ayush on 3 Oct 2024
I understand that your code may be encountering issues despite not displaying any errors.
When working with hardware interfacing, some potential sources of errors you can consider at:
  1. Incorrect Sampling rate: verify the sampling rate. It must not be set too high or too low for the device capabilities. So, Verify the device specifications and adjust “daqSession.Rate” accordingly.
  2. Try updating the driver Toolbox.
  3. Try logging the output signals to get better understanding of the picture.
Although your code’s logic seems fine, these errors could be the potential reasons your code might be failing.
Hope this helps. If the issue is persistant then if possible, kindly provide a little more description of the actual behavior of the code versus the expected behavior so that we can compare the results and find the root cause.

Jaime Estarellas Cifre
Jaime Estarellas Cifre on 3 Oct 2024
Hi @Ayush,
There are a few problems.
  1. The DSP Toolbox Signal can't generate a proper continuous signal infinitelly. If I try using start(dq,"continuous"), the signal will only last as long as the buffer from preload(...), otherwise it underflows: Output underflow event: Last valid output was scan number 9848. If I use "repeatingoutput" the signal is not actually continuous but it simulates continuity, if I were to increase the frequency it would show problems as the "blocks of signal" preloaded would overstack with each other. (for example if you have a fs = 10000Hz and a frequency of signal of f = 5000Hz)
  2. Performing a DAC of a processed signal coming from an ADC: My objective was to create a signal with one DAC, read it with an ADC and then processes it before doing another DAC. The problem comes when the signal processing becomes slightly complex (for example a modulation), that the code just does not work. There are no errors, it just doesn't plot, here is an example:
clear;
close all;
clc;
% === DAC and ADC === %
% Create DataAcquisition object for NI device
dq = daq("ni");
% Add Analog Output Channels to generate the signal on "ao0" and "ao1"
addoutput(dq, "Dev1", "ao0", "Voltage");
addoutput(dq, "Dev1", "ao1", "Voltage");
ch_out = dq.Channels(1:2);
ch_out(1).Name = "ao0_out";
ch_out(2).Name = "ao1_out";
% Add an Analog Input Channel to acquire the signal on "ai1"
addinput(dq, "Dev1", "ai1", "Voltage");
% Set the sample rate
rate = 10000; % Hz
dq.Rate = rate;
% Specify the output signal - A square wave with a DC offset
f = 100; % Frequency of 10 Hz
t = (0:rate-1)/rate; % Time vector for 1 second
output = 1.25 + 0.25*square(2*pi*f*t); % Generate square wave with DC offset
% Create timescope to visualize the signals in real time
scope = timescope('SampleRate', rate, 'TimeSpanSource', 'Property', 'TimeSpan', 0.1, ...
'YLimits', [-2 2], 'Title', 'Output vs Input Signals', ...
'ShowLegend', true, 'ChannelNames', {'Inintal Signal DAC_1', 'Processed Signal DAC_2'});
% Set the callback function to execute when data is available
batchSize = rate; % Read data for 1 second at a time for more frequent updates
dq.ScansAvailableFcnCount = batchSize;
dq.ScansAvailableFcn = @(src, evt) plotAndWriteSignals(src, output, scope, rate);
% Preload the output data for "ao0"
preloadData = [output', zeros(length(output), 1)]; % Preload output for ao0, set ao1 to zero initially
preload(dq, preloadData);
% Start the output and input simultaneously in continuous mode
start(dq, "repeatoutput"); %IF I WERE TO USE start(dq,"continuous") the error mentioned occurs
% Stop the generation and acquisition after key press
disp('Press any key to stop the continuous generation and acquisition.');
pause();
stop(dq);
disp("Generation and acquisition stopped.");
% Callback function to read data, plot input and output using timescope, and write to ao1 in real-time
function plotAndWriteSignals(src, output, scope, rate)
% Read available data in chunks as defined by ScansAvailableFcnCount
tic;
[data, ~] = read(src, src.ScansAvailableFcnCount, "OutputFormat", "Matrix");
processedSignal = sin(2*pi*data.Time).*data;
% Ensure that both 'data' and 'outputToPlot' are column vectors and have the same length
len = length(processedSignal);
outputToPlot = output(1:len)';
if isrow(processedSignal)
processedSignal = processedSignal';
end
% Update the timescope with the output and input signals
% The input data and output data must have consistent row sizes
scope([outputToPlot, processedSignal]);
% Write the acquired input data to the output channel "ao1"
% Create a matrix where each row contains values for both output channels
outputData = [outputToPlot, processedSignal]; % First column for ao0, second column for ao1
write(src, outputData);
elapsed_time = toc;
processing_time = sprintf('Elapsed time between ADC and second DAC is %.4f seconds', elapsed_time);
disp(processing_time);
end
I might be doing something wrong but I don't know what. I have studied the DSP tool box, but nothing seems to acomplish what I am looking for. Do you have any example, demo, or documentation about real-time processing of analog signals with an NI DAQ?
Thanks Ayush

Products


Release

R2021b

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!