Clear Filters
Clear Filters

TCP communication, send matrix cut in package, and reconnect the package in the client

23 views (last 30 days)
Hi,
I create two codes that communicate together through a TCP connexion (one compute, two Matlab instances open). One is the server, the second is the client. My goal is to simulate the recording of signal from an amplifier. The server act as the amplifier, the client as my GUI that record the signal.
In the server I load a data file of signal, which contains 120 channels by XX samples. To simulate the connexion with an amplifier, I use a timer and write every 0.1 second a package of few samples equivalent to the samplifing frequency of the real amplifier (2048 Hz).
This package is a piece of signal cut from the original signal in the function of timer. This package is a matrix of 120 by XXsamples double that I reshape in a 1 by XX samples and turn it in int16 to be written by the server.
The client is running also with a timer, every 0.2 second. The client read in the TCP connexion what is available. So it gets one or more packages reshaped 1 by XX samples int16. Then, I do the opposite operation in the client, turn it back to double and reshape it in a 120 by XXsamples matrix.
My issue is the recomposed signal in the client when plotted doesn't look like the orignal one, and the reason is the concatenation make me losing the orginal package 'orgnisation', when I reshape, I think I'm not reshaping my signal in a good way. And I don't find any answer of how to do it.
Is there a way to send package of signal and to read them and reorganize them correctly ?
You can find below the two codes I did: the server first then the client.
Thank you in advance
%% VIRTUAL AMPLIFIER %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% When opened you can select between different file that will be read in %
% a loop forever, those file of EMG recorded on a participant will be %
% written in a server that the GUI can have access like it was any %
% amplifictor %
close all; clear; clc;
global parameters
signal = load('contraction30sec120channels2048Hz.mat');
fsamp = 2048;
% Timer for Amplifier
parameters.TimerVirtualAmplifier = timer();
parameters.TimerVirtualAmplifier.ExecutionMode = 'fixedRate';
parameters.TimerVirtualAmplifier.Period = 0.01;
parameters.TimerVirtualAmplifier.TimerFcn = @(src,evt) TimerVirtualAmplifierFunction(src,evt); % you can use function handle or an anonymous function.
parameters.data = signal.data;
% 1- Prepare variables for reading in an endless loop the loaded file
parameters.PreviousSize = 1;
parameters.TimeRunning = 0;
parameters.PackageSize = round(parameters.TimerVirtualAmplifier.Period*fsamp);
% 2- Prepare Server
% Find Host Name and Address
% Find the host name and address of the machine where the server is
% created. The client uses this address to connect to the server.
[~,hostname] = system('hostname');
hostname = string(strtrim(hostname));
address = resolvehost(hostname,"address");
% Create Server
% Create the tcpserver object using the address of the machine and port 5000.
% Create a callback function called connectionFcn to write data when a TCP/IP
% client connects to the server. Set the ConnectionChangedFcn property to the
% callback function connectionFcn. You can find the connectionFcn function
% at the end of this example.
try
delete(parameters.server) % In case server haven't been close correctly
catch
end
parameters.server = tcpserver(address,5000,"ConnectionChangedFcn",@connectionFcn);
parameters.server.ByteOrder = 'little-endian';
disp('Server is on')
disp('Waiting for client to connect')
% Start the timer
warning off
%% Callback Functions
% Run the timer to update the data
function TimerVirtualAmplifierFunction(~, ~)
global parameters
newpackageposition = parameters.PreviousSize+parameters.PackageSize;
if newpackageposition > size(parameters.data,1)
package = parameters.data(parameters.PreviousSize:end,:);
parameters.PreviousSize = 1;
else
package = parameters.data(parameters.PreviousSize:parameters.PreviousSize+parameters.PackageSize,:);
parameters.PreviousSize = parameters.PreviousSize+parameters.PackageSize;
end
% Write on server
DataReShapePackage = reshape((package),[],1);
% DataReShapePackage = reshape((package),1,[]);
% Write data only if a TCP Client is connected
if isempty(parameters.server.ClientPort) == 0
DataReShapePackage = int16(DataReShapePackage);
write(parameters.server,DataReShapePackage,"int16");
elseif isempty(parameters.server.ClientPort) == 1
% If the client disconnect (press stop), stop the timer
disp("Client disconnected from the server.")
disp('Waiting for client to reconnect.')
stop(parameters.TimerVirtualAmplifier);
end
end
% Connection Callback Function to Write Binary Data
% This function calls write to write data to the connected TCP/IP client.
function connectionFcn(src, ~)
global parameters
if src.Connected
% If the client is connected, start the timer
disp("Client connection accepted by server.")
start(parameters.TimerVirtualAmplifier);
else
disp("Client not connected to the server.")
end
end
%%%%%%%%%%%%%%%%%%%%% Virtual Amplifier Client %%%%%%%%%%%%%%%%%%%%
close all; clear ; clc
global parameters
%% TIMER %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
parameters.TQuattrocento = timer();
parameters.TQuattrocento.ExecutionMode = 'fixedRate';
parameters.TQuattrocento.Period = 0.2;
parameters.TQuattrocento.TimerFcn = @(src,evt) QuattroncentobackgroundRunningfunction(src,evt); % you can use function handle or an anonymous function.
%% SETTINGS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
parameters.Xlength = 40; % Length of the plot
parameters.EMGGainFactor = 5/2^16/150*1000; %Provide amplitude in mV
parameters.AuxGainFactor = 5/2^16/0.5; % Gain factor to convert Aux Channels in V
parameters.offsetQuattrocento = 50;
parameters.Fsamp = 8; % Codes to set the sampling frequency [0 8 16 24];
parameters.FsampVal = 2048; % Sampling frequency values
parameters.NumChan = 0; % Codes to set the number of channels [0 2 4 6];
parameters.NumChanVal = 72; % Channels numbers
%% TCP Connexion
% Find Host Name and Address
% Find the host name and address of the machine where the server is
% created. The client uses this address to connect to the server.
[~,hostname] = system('hostname');
hostname = string(strtrim(hostname));
parameters.TCPPort = 5000; % Number of TCP socket port
parameters.IP = resolvehost(hostname,"address"); % Virtual amplifier IP adress
parameters.tcpSocket = tcpclient(parameters.IP,parameters.TCPPort, "Timeout",10, "EnableTransferDelay",true);
parameters.tcpSocket.ByteOrder = 'little-endian'; % 'big-endian'
parameters.refreshrate = 1;
parameters.NsampVal = floor(parameters.FsampVal*parameters.TQuattrocento.Period/parameters.refreshrate);
%% Pre allocation
parameters.time = linspace(0, 1, parameters.NsampVal*parameters.Xlength); % this one will be the full time vector for the plot
parameters.signal = (repmat(1:parameters.NumChanVal,parameters.NsampVal*parameters.Xlength,1)) * parameters.offsetQuattrocento;
parameters.PlotChansignalEMG = (0:1:63)* parameters.offsetQuattrocento;
% parameters.PlotChansignalAUX = (0:1:15)* parameters.offsetQuattrocento;
parameters.PlotChansignalAUX = (0:1:1)* parameters.offsetQuattrocento;
parameters.PlotChansignalACESS = (0:1:7)* parameters.offsetQuattrocento;
parameters.temporarymatrix = zeros(round(parameters.FsampVal*parameters.TQuattrocento.Period),parameters.NumChanVal); % in this one the EMG will be stored temporarelly
%% Figure preparation
% parameters.Multiplein(1,:) = 33:96;
% parameters.AUX = 97:112;
% parameters.Accessories = 113:120;
parameters.Multiplein(1,:) = 1:64;
parameters.AUX = 65:66;
parameters.Accessories = 67:72;
parameters.figuresignalQuattrocento = figure(); parameters.figuresignalQuattrocento.Position = [10 400 1700 600];
parameters.axhIN1 = axes('Parent',parameters.figuresignalQuattrocento);parameters.axhIN1.Position = [0.1 0.50 0.8 0.45];
parameters.axhINAUX = axes('Parent',parameters.figuresignalQuattrocento); parameters.axhINAUX.Position = [0.1 0.20 0.8 0.20];
parameters.axhINAcess = axes('Parent',parameters.figuresignalQuattrocento); parameters.axhINAcess.Position = [0.1 0.03 0.8 0.10];
parameters.LineMLTIN1 = line(parameters.axhIN1,parameters.time,parameters.signal(:,parameters.Multiplein(1,:))); title(parameters.axhIN1,'Multiple in 1')
parameters.LineAUX = line(parameters.axhINAUX,parameters.time,parameters.signal(:,parameters.AUX)); title(parameters.axhINAUX,'Auxillary')
parameters.LineAcess = line(parameters.axhINAcess,parameters.time,parameters.signal(:,parameters.Accessories(4))); title(parameters.axhINAcess,'Accessories')
parameters.axhIN1.YLim = [parameters.offsetQuattrocento*-1 parameters.offsetQuattrocento*65];
parameters.axhINAUX.YLim = [parameters.offsetQuattrocento*-0.4 parameters.offsetQuattrocento*18];
parameters.axhINAcess.YLim = [0 parameters.offsetQuattrocento*4];
%% TIMER %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
parameters.i = 0;
DataQuattrocento = fread(parameters.tcpSocket)'; % empty the buffer before starting the function
clear DataQuattrocento
start(parameters.TQuattrocento);
% Wait for user to manually stop the session
uiwait(msgbox('Press OK to stop data acquisition.', 'Stop Acquisition', 'modal'));
%% Stop the DAQ and TCP
stop(parameters.TQuattrocento)
% Close the communication\
flush(parameters.tcpSocket)
delete(parameters.tcpSocket)
clear parameters.tcpSocket
%% Handle function
function QuattroncentobackgroundRunningfunction(src, ~)
tic;
global parameters
parameters.i = parameters.i + 1;
disp(['iteration: ' num2str(parameters.i)])
NumBytesAvailable = parameters.tcpSocket.NumBytesAvailable;
disp(['NumBytesAvailable: ' num2str(NumBytesAvailable)])
Remainder = rem(NumBytesAvailable, 2880);
disp(['Remainder: ' num2str(Remainder)])
NumBytesAvailable = (NumBytesAvailable-Remainder)/2;
disp(['NumBytesAvailableTotal: ' num2str(NumBytesAvailable)])
disp('------------------------------------------------------------')
if NumBytesAvailable <= 0
else
toc
tic
try
DataQuattrocento = read(parameters.tcpSocket, NumBytesAvailable, 'int16')';
% keyboard
toc
tic
DataQuattrocento = reshape((DataQuattrocento),parameters.NumChanVal,[]);
sizedata = size(DataQuattrocento,2);
parameters.NsampVal = ceil(sizedata/parameters.refreshrate);
parameters.refreshedmatrix = DataQuattrocento(:,1:parameters.refreshrate:end); % Apply downscale if necessary
parameters.signal(1+parameters.NsampVal:end,1:parameters.NumChanVal) =...
parameters.signal(1:end-parameters.NsampVal,1:parameters.NumChanVal);
parameters.signal(1:parameters.NsampVal,1:parameters.NumChanVal) = parameters.refreshedmatrix';
% Multiple in 1 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
Ysignal{1} = ((parameters.signal(:,parameters.Multiplein(1,:))*parameters.EMGGainFactor)+parameters.PlotChansignalEMG)';
Ysignalmultiplein1 = num2cell(Ysignal{1},2);
set(parameters.LineMLTIN1, {'YData'}, Ysignalmultiplein1)
% Aux %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
Ysignal{2} = (parameters.signal(:,parameters.AUX)+parameters.PlotChansignalAUX)';
YsignalAUX = num2cell(Ysignal{2},2);
set(parameters.LineAUX, {'YData'}, YsignalAUX)
% Accessories %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
Ysignal{3} = (parameters.signal(:,parameters.Accessories(4))+parameters.PlotChansignalACESS(:,4))';
YsignalAccess = num2cell(Ysignal{3},2);
set(parameters.LineAcess, {'YData'}, YsignalAccess)
clear DataQuattrocento
tcpserverfind
catch
keyboard
end
toc
end
end

Answers (0)

Products


Release

R2024a

Community Treasure Hunt

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

Start Hunting!