Receive serial data in MATLAB - matlab

I have a problem about receiving 16-bit data in MATLAB.I cannot receive 16-bit data at high speed through UART in MATLAB software.
Using stm32, I divide a 16-bit data belonging to a sensor into two 8-bit data and send it to MATLAB through UART. And in MATLAB software, I combine these two 8-bit data together and 16-bit sensor data is obtained. In MATLAB software, at first a valid data is sent to stm32. until this data is not sent to stm32, stm32 does not send data, This is so that MATLAB gets the data order right, but it only happens once.
With the test I did, I realized that the process of separating and combining the data is done correctly.
But when I want to receive sensor data, only the first data is stored in each loop (2530) and for example if I receive 1000 data, 1000 of the first data are stored (2530).
I received the sent data of the stm32 using a serial plotter software on the computer and the data is sent to the computer correctly.
When I put a delay of 20 milliseconds in the stm32, the problem is solved and I think that the code I wrote for MATLAB is not optimal and maybe there is a better code for this task.
And the delay of 20 milliseconds is too much for my work . I need to send the data to MATLAB as fast as possible and the data will be ploted live in MATLAB.
When I delete the plot command from MATLAB, the performance of the program improves, but the problem is not solved
What should I do to fix this problem?
clear
close all;
load('fi4.mat');
clc
serialportObj = serialport("COM3",115200);
i=2
tim=0;
data=0;
w=0;
data_valid=0;
validate=11;
write(serialportObj, validate, "uint8");
while(1)
tic
data=read(serialportObj,2,"uint8");
res = double(typecast([uint8(data(2)), uint8(data(1))], 'uint16'))
%FilterdSignal=filter(Hd, res);
sig(i)=res;
w(i)=sig(i)+(0.95*w(i-1));
ff(i)=w(i)-w(i-1);
if i <=300
figure(2)
plot (sig);
else
figure(2)
plot(sig(end-300:end));
end
i=i+1;
c=toc;
tim=c+tim;
end

Related

Trigger Timestamps during a continous sample input Matlab

I have a continous data sample stream from an amp feeding into matlab. Matlab creates random triggers and sends them via a serial port back to the amp which sends them back to matlab... a simple loop...
I now want to test the delay, so the time between sending the trigger and recieving it again...
I'm not asking for the exact lines of code, I just wanna know what kind of function would be best suited to create such timestamps within matlab. I need a relatively high precicion (ms range)...
Any tips?
Cheers,
toxic

serial communication beteen arduino and MATLAB

I'm currently working on my final year study project , i'm using arduino due and the ultrasonic sensors which are placed on a wheelchair to make an autonomous one.
so my problem is that i'm reading the distances from the sensors and i need to send them tomatlab simulink to use them in the fuzzy logic controller block but i can't because what i'm sending in the serial monitor from ardiuno is something like "
#distance1#distance2#...#distance10# " which is a string type,so how can i get the data (distances) using serial port to use them in matlab simulink.
Do i have to change the arduino code or should i use some block in simulink?
any response might be helpfull
You need to parse the input, based on the delimiter, and decide you often you should sample the sensor.
You want your input to be split at the hash. You should use something like:
str = input; % from arduino buffer
delimiter = "#";
C = strsplit(str,delimiter)
C = int(C) % type case to an int
You probably should read every 5th signal based on the frequency of the sensor. If the sensor takes 100 measures per second you probably only need 20 to be processed. This looks like:
C = C[1:5:end]
Maybe...
Processing the signal you might want to use error std from the data sheet of the sensor somewhere. Parse the input probably either before it gets passed into simulink, or as one of the first blocks. It is kind of up to you (I don't know if there is a best practise).
I hope that helped!
The docs for str split is here:
http://au.mathworks.com/help/matlab/ref/strsplit.html

How to synchronize readout of binary streams on serial port of Matlab

I'm having an issue which is partially Matlab- and partially general programming-related, I'm hoping that somebody can help me brainstorm for solutions.
I have an external microcontroller that generates a large stream of binary data (~40kb) every 400ms and sends it via UART to a PC running Matlab scripts. The data is not encoded in hexa or dec characters, but true binary (hence, there's no terminator defined as all 256 values are possible, valid combinations of data). Baudrate is set at 1024000. In short, it takes roughly 375ms for a whole stream of data to be sent, with 25ms of dead time in between streams
In Matlab, the serial port is configured correctly (also 1024000, 8x bits, 1x stop bit, no parity, no hardware flow control, etc.). I am able to readout the data I'm sending via the microcontroller correctly (i.e. there's no corruption of data), but I'm not being able to synchronize the serial readout on Matlab. My script is as follows:
function data_show = GetDATA
if ~isempty(instrfind)
fclose(instrfind);
end
DATA_TOTAL_SIZE = 38400;
DATA_buffer = uint8(zeros(DATA_TOTAL_SIZE,1));
DATA_show = reshape(DATA_buffer(1:2:end)',[160,120])';
f_data_in = false;
f_data_out = true;
serialport = serial('COM11','BaudRate',1024000,'DataBits',8,'FlowControl','none','Parity','none','StopBits',1,...
'BytesAvailableFcnCount',DATA_TOTAL_SIZE,'BytesAvailableFcnMode','byte','InputBufferSize',DATA_TOTAL_SIZE * 2,...
'BytesAvailableFcn',#GetPortData);
fopen(serialport);
while (get(serialport,'BytesAvailable') ~= 0) % Skip first packet which might be incomplete
fread(serialport,DATA_TOTAL_SIZE,'uint8');
end
f_data_out = true;
while (1)
if (f_data_in)
DATA_buffer = fread(serialport,DATA_TOTAL_SIZE,'uint8');
DATA_show = reshape(DATA_buffer(1:2:end)',[160,120])'; %Reshape array as matrix
DATAsc(DATA_show);
disp('DATA');
end
pause(0.01);
end
fclose(serialport);
delete(serialport);
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function GetPortData (obj,~)
if f_data_out
f_data_in = true;
end
end
end
The problem I see is that what I end up reading is always the correct size, but belongs to multiple streams, because I haven't found a way to tell Matlab that these 25ms of no data should be used to synchronize (i.e. data from before and after that blank period should belong to different streams).
Does anyone have any suggestions for this?
Thanks a lot!
For completeness, I would like to post the current implementation I have fixing this issue, which is probably not a suitable solution in all cases but might be useful in some.
The approach I took consists in moving into a bi-directional communication protocol, in which Matlab initiates the streaming by sending a very short command as a trigger (e.g. single, non-printable character). Given the high baudrate it does not add significant delay due to processing in the microcontroller's side.
The microcontroller, upon reception of this trigger, proceeds to transmit only one full package (as opposed to continuously streaming package at a 5Hz rate). By forcing Matlab to pickup a serial package of the known length right after issuing the trigger, it ensures that only one package and without synchronization issues is received.
Then it becomes just a matter of encapsulating the Matlab script in a routine with a 5Hz tick given by a timer, in which the sequence is repeated (send trigger, retrieve package, do whatever processing, and repeat).
Advantages of this:
It solves the synchronization problems
Disadvantages of this:
Having Matlab running on a timer tick does not ensure perfect periodicity, and hence the triggers might not always be sent at exactly 5Hz. If triggers are sent at "inconvenient" times for the microcontroller, packages might need to be skipped in order to avoid that a package is updated in memory while it is still being transmitted (since transmission takes a significant part of the 200ms time slot)
From experience, performance can vary a lot depending on what the PC running Matlab is doing. For example, it works fine when the PC is left on its own to do the acquisition, but if another program is used (e.g. Chrome), Matlab begins to lag and that results in delays in transmission of triggers.
As mentioned above, it's not a complete answer, but it is an approach that might be sufficient in some situations. If someone has a more efficient option, please fell free to share!

Achieving 2 hertz data logging with Matlab serial

I am trying to use matlab for data acquisition with a licor820 instrument. The instrument outputs data at 2 hertz.
I have tried many different methods using infinite loops with asynchronous sampling (readasync) and timed readings but I am unable to get 2 hertz data. I am getting reads in the .51 s range. here are three examples of my methods. Any advice on what I may be doing wrong or how to properly sample at the highest frequency would be greatly appreciated!
example1: using readasync
tinit=tic; %initialization timer
s=serial('COM4') %,'InputBufferSize',40);
fopen(s)
while toc(tinit)<2 %allow time to initialize
end
while 1<2 %infinite loop for continuous sampling
readasync(s)
data=fscanf(s)
toc %allows me to see time between data acquisitions
tic
end
example 2: using bytes available.
My thinking here is to acquire data when I have the minimum amount of bytes necessary. Although I am unsure exactly how to determine how many bytes are necessary for my instrument, besides through visually looking at the data and narrowing it down to around 40 bytes:
while 1<2 %infinite loop for continuous sampling
if s.BytesAvailable >35
scandata=fscanf(s);
toc
tic
end
end
example 3: time forcing.
Since I need 2 hertz data my thinking here was to just force read the buffer every .49 seconds. The weird thing I see here is that it initially provides samples every .49 seconds, but while I monitor the bytes available at the port I see it steady dropping from 512 until it gets to 0 and then I stop getting .49 second samples. I guess I don't really understand how to use serial efficiently.
while 1<2 %infinite loop
if toc(t2)>=.49 %only sample after .49 seconds have passed
t2=tic; %reinitiate the tic for this forced time loop
bytes=s.BytesAvailable %to monitor how many bytes there are at the port
scandata=fscanf(s);
if ~isempty(scandata) && length(scandata)== 3 %checks for successful read
toc
tic
end
end
end
I feel there must be some way to sample completely in sync with the an instrument but I can't figure it out. Any help, suggestions, or ideas would be greatly appreciated! Thanks!
Dont rely on tic and toc. These functions use the time supplied by the OS calls. Mathworks claims to use high resolution timers, but do not rely on this! If you do not use a realtime OS these measurements are subject to unknown variation.
Sampling should be performed by realtime capable hardware. In your case I suspect that your sampling rate is actually controlled by your instrument. The output of the instrument is buffered by your serial interface. Therefore it seems to me that Matlab does not influence the sampling rate at all. (As long as the buffer does not overflow)
Try to acquire about 2000 samples or more and see how long it takes. Then divide the total time by the number of samples (-1) and compare this to the expected 0.5 s. If there is a difference, try adjusting the configuration of your instrument.

Using MATLAB to send multiple serial signals through the same port

I'd like to send multiple signals (4 inputs and outputs and 7 outputs) from my Laptop to a microcontroller. I'm thinking of using a USB to serial converter and multiplexing the data through the port. I'll need to write codes both in the laptop end and in the microcontroller to multiplex the data.
Eg:
Tx of microcontroller:
1.Temperature sensor ADC output->Laptop
2.Voltage sensor to laptop
3.Current Sensor to Laptop
4.Photodiode current to Laptop
So I need to write a program in the microcontroller to send the data in this order. How can I accomplish this? I was thinking of an infinite loop which sends the data with time delays in between.
At the Rx pin of Microcontroller,
Seven bit sequences. Each bit sequence will be used to set the duty cycle of a PWM generated by the microcontroller.
I also need the same multiplexing or demultiplexing arrangement in the matlab end. Here too, I'm thinking of allotting some virtual 'channels' at different instants of time. What kind of algorithm would I need?
In case you always send all the inputs/outputs at the same rate, you could simply pack them into 'packets', which always start with one or more bytes with a fixed value that form a 'packet header'. The only risk is that one of the bytes of the sensor data might have the same value as the start-byte at the moment you try to start receiving bytes and you are not yet synchronized. You can reduce this risk by making the header longer, or by choosing a start-byte that is illegal output for the sensors (typically OxFF or so).
The sending loop on the microcontroller is really easy (pseudocode):
while True:
measure_sensors()
serial.send(START_BYTE)
serial.send(temperature)
serial.send(voltage)
serial.send(current)
serial.send(photodiode)
end while
The receiving loop is a bit more tricky, since it needs to synchronize first:
while True:
data = serial.receive()
if data != START_BYTE:
print 'not synced'
continue #restart at top of while
end if
temperature = serial.receive()
voltage = serial.receive()
current = serial.receive()
photodiode = serial.receive()
do_stuff_with_measurements()
end while
This same scheme can be used for communication in both directions.