I'm trying to find a way to timestamp a string value received from a USB port in real time - every 0.5 s - and save it into a file.
So far I'm using the 'record' function to save the string value, but I haven't been able to add the timestamp to it. Reading through the questions, found someone had used the 'now' funciton, but they do not describe the way to do it. The string value I'm using as example to produce the code is the following:
1 Recording on 12-Feb-2015 at 15:57:13.940. Binary data in little endian format.
2 < 34 ascii values.
Timestamp,4.5,5.5,6.5,7.5,8.5,...
3 < 34 ascii values.
Timestamp,4.5,5.5,6.5,7.5,8.5,...
4 < 34 ascii values.
Timestamp,4.5,5.5,6.5,7.5,8.5,..."
and the code that so far I have developed is the following:
%// start code
delete(instrfind);
s = serial('COM5');
set(s,'BaudRate',57600);
set(s,'terminator','CR');
%// Open Serial COM Port
fopen(s);
%// start save file
s.RecordDetail = 'verbose';
s.RecordName = datestr(now,30)
record(s,'on')
%// start time
tic;
hold on;
count = 1;
t = 0;
keepLooping = true;
while keepLooping
time(count)=toc;
count = count +1;
out = fscanf(s);
fprintf(s,'%s','RS232?')
out1 = strsplit(out,',');
s.UserData = count;
p(count) = str2double(out1(2));
k(count) = str2double(out1(3));
g(count) = str2double(out1(4));
h(count) = str2double(out1(5));
%// plotting of the variables continues from this point.
I guess that the problem is that you get some system time making no sense. For a comprehensive time stamp you can do following:
datestr(datetime,'yyyy-mmm-dd HH:MM:SS:FFF')
You get the time as a char vector using the datetime function for the time and the datestr function for the format and casting. Since you seem to have done some programming before I think that you will be able to google this later to find the format you want to use. That may differ country by country I guess.
Please comment if this is not what you want. Good Luck!
Related
I am generating time stamps for 10 days in the format of yyyymmddHHMMSS for each second which means there are 10*24*60*60 timestamp values. Similarly, I am generating 10*24*60*60 Heart rate values which are uniformly distributed between 50 and 70. Both streams(arrays) are generated fine and then I want to join these arrays separated by a comma in which I am getting some issues as special characters are shown in Joined array. The final step is to save this joined matrix to file which will serve as input for my simulation.
So basically file should contain 10*24*60*60 data values in format yyyymmddHHMMSS,HeartRate
An example would be `20170102114512,58'. The code I used for generating timestamps and heart rate is
clear all
close all
clc
startDate = datetime(2017,1,1,12,0,1);
endDate = datetime(2017,1,2,12,0,0);
days = 1;
numberOfSeconds = 60*60*24*days
data = startDate:seconds(1):endDate ;
timestamps = datestr(data,'yyyymmddHHMMSS');
number1 = size(timestamps, 1);
% generating heart rates
heart_rate = 50 +(70-50) * rand (numberOfSeconds,1);
intHeartRate = int64(heart_rate);
number2 = size(intHeartRate, 1);
% hist(heart_rate)
% joining time and sensor data
joined = horzcat( timestamps,intHeartRate)
dlmwrite('/Users/amar/Desktop/data/heart.txt', joined);
I have now two Issues
output is generated as below in terminal and it has special characters at end of each value
writing joined matrix into File using dlmwrite adds an extra comma to all the values, but I want to output to be written in file as yyyymmddHHMMSS, HeartRate format
Convert int HeartRate to a string then it should work.
Join = hortcat(dates,num2str(intHeartRate))
With the esteem advice of #Jim, I found out that the issue was int and string, so I converted both arrays to a string using num2str and then used strcat to concatenate two strings. In order to write joined array to file I used dlmwrite with delimiter ''
Code is working like charm 😀
clear all
close all
clc
startDate = datetime(2017,1,1,12,0,1);
endDate = datetime(2017,1,2,12,0,0);
days = 1;
numberOfSeconds = 60*60*24*days
data = startDate:seconds(1):endDate ;
timestamps = datestr(data,'yyyymmddHHMMSS');
number1 = size(timestamps, 1);
% generating heart rates
heart_rate = 50 +(70-50) * rand (numberOfSeconds,1);
intHeartRate = int64(heart_rate);
number2 = size(intHeartRate, 1);
% hist(heart_rate)
% joining time and sensor data
joinedStream = strcat(num2str(timestamps),{','},num2str(intHeartRate))
dlmwrite('/Users/amar/Desktop/geenrated/heart.txt', joinedStream,'delimiter','');
I want to change the Day, Month and Year of a serial date number in matlab
e.g.: 7.367985930307407e+05
gives me 13-Apr-2017 14:13:57.
I need: 01-Jan-2017 14:13:57
I get the serial date number from a simulink model, where is a matlab emb. code block with:
function t = sysTime
coder.extrinsic('now');
t=0;
t = now
end
Anyone can help? Read the matlab datenum and now docu but I still couldnt figure it out :(
You can use a datetime object to alter specific portions of the date
d = 7.367985930307407e+05;
dt = datetime(datevec(d));
dt.Month = 1;
dt.Day = 1;
% 01-Jan-2017 14:13:57
% And if you need the serial date number back:
result = datenum(dt);
In your function sysTime, the output is set to now, which gives you the current time as returned by your system. Try the following instead:
function t = sysTime
coder.extrinsic('now');
t=0;
t=datenum(2017,1,1) + rem(now,1);
end
Matlab date numbers are numbers of type double that represent the number of days since a reference date. Thus, the number before the decimal point gives you a date, the nubers after the decimal point give you the time of day.
With the datenum function you can get the date number for your desired date and add the fractional part of the system time to get what you want. In the long run it would probably be better to parameterize your reference date in the matlab block.
I would like to recursively find the maximum value in a series of matrices (column 8, to be specific), then use the index of that maximum value to set all values in the array with index up to the max index to NaN (for columns 14:16). It is straight forward to find the max value and index, but using a for loop to do it for multiple arrays I am stumped.
Here is how I can do it without a for loop:
[C,Max] = max(wy2000(:,8));
wy2000(1:Max,14:16) = NaN;
[C,Max] = max(wy2001(:,8));
wy2001(1:Max,14:16) = NaN;
[C,Max] = max(wy2002(:,8));
wy2002(1:Max,14:16) = NaN;
and so on and so forth...
Here are two ways I have tried using a for loop:
startyear = 2000;
endyear = 2009;
for n=startyear:endyear
currentYear = sprintf('wy%d',n);
[C,Max] = max(currentYear(:,8));
currentYear(1:Max,14:16) = NaN;
end
Here is another way I tried, using the eval function
for n=2000:2009;
currentYear = ['wy' int2str(n)];
var2 = ['maxswe' int2str(n)];
eval([var2 ' = max(currentYear(:,8))']);
end
In both cases, the problem seems to be that MATLAB doesn't recognize the 'currentYear' variable to be the array that corresponds to the wyXXXX that I already have created in my workspace.
Based on Peters answer, here is some more info about my data. I am starting with a matrix of data called all_data which holds 16 columns of data, spanning the time period 1982 - 2012. I am only interested in the period 2000 - 2009, and I am also interested in analyzing each year individually (2000, 2001,...,2009).
To get the data into individual years, I use the following code:
for n=2000:2009;
s = datenum(n-1,10,1);
e = datenum(n,9,30);
startcell = find(TIME(:,7)==s);
endcell = find(TIME(:,7)==e);
var1 = ['wy' int2str(n)];
eval([var1 '= all_data3(startcell:endcell,:)']);
eval(['save ', var1]);
end
For clarification, it is the period 10/1/YEAR1 to 9/30/YEAR2 that I am interested in, and TIME is a matrix holding the dates and times of my data.
So at the end of the above for-loop, I have a new matrix for each water-year (wy). I then want to find the date of maximum snow-accumulation (column 8) and exclude all data prior to that date from my analysis. this is where the original question comes from.
Peter's solution works, but I was hoping to find a more simple solution to find the max date and set the values prior to that date to NaN, without having to declare a bunch of variables (or entries in a cell array).
If I could write a loop that would create the cell array that Peter suggested based on a start and end year, that would make the code transferable to other datasets, but when i try to do this I run into the issue that the index for the cell-array is 1:length(years), but the wy arrays are named according to the actual year, so there is an inconsistency when using the eval function.
Matt
You've discovered the problem with eval and dynamically named variables. They're messy. I'd recommend recoding this as a cell array, with the cell array index being the index for the year:
years = 2000:2009;
wy{1} = wy2000;
wy{2} = wy2001;
% etc...
% Then,
for n=1:length(years)
[C, maxval] = max(wy{n}(:,8));
% etc.
end
You really only need the actual year when you input the data and when you display it. Now, if you're starting from a huge pile of arrays already named this way, that's the time to use eval: to convert them into this form that's easier to use. Just form the eval strings so they read, for example, 'wy{1} = wy2000;'
I have the following code:
for i = 1450:9740:89910
n = i+495;
range = ['B',num2str(i),':','H',num2str(n)];
iter = xlsread('BrokenDisplacements.xlsx' , range);
displ = iter;
displ = [displ; iter];
end
Which takes values from an Excel file from a number of ranges I want and outputs them as matricies. However, this code just uses the final value of displ and creates the total matrix from there. I would like to total these outputs (displ) into one large matrix saving values along the way, how would I go about doing this?
Since you know the size of the block of data you are reading, you can make your code much more efficient as follows:
firstVals = 1450:9740:89910;
displ = zeros((firstVals(end) - firstVals(1) + 1 + 496), 7);
for ii = firstVals
n = ii + 495;
range = sprintf('B%d:H%d', ii, ii+495);
displ((ii:ii+495)-firstVals(1)+1,:) = xlsread('BrokenDiplacements.xlsx', range);
end
Couple of points:
I prefer not to use i as a variable since it is built in as sqrt(-1) - if you later execute code that assumes that to be true, you're in trouble
I am not assuming that the last value of ii is 89910 - by first assigning the value to a vector, then finding the last value in the vector, I sidestep that question
I assign all space in iter at once - otherwise, as it grows, Matlab keeps having to move the array around which can slow things down a lot
I used sprintf to generate the string representing the range - I think it's more readable but it's a question of style
I assign the return value of xlsread directly to a block in displ that is the right size
I hope this helps.
How about this:
displ=[];
for i = 1450:9740:89910
n = i+495;
range = ['B',num2str(i),':','H',num2str(n)];
iter = xlsread('BrokenDisplacements.xlsx' , range);
displ = [displ; iter];
end
no time scores
1 10 123
2 11 22
3 12 22
4 50 55
5 60 22
6 70 66
. . .
. . .
n n n
Above a the content of my txt file (thousand of lines).
1st column - number of samples
2nd column - time (from beginning to end ->accumulated)
3rd column - scores
I wanted to create a new file which will be the total of every three sample of the scores divided by the time difference of the same sample.
e.g. (123+22+22)/ (12-10) = 167/2 = 83.5
(55+22+66)/(70-50) = 143/20 = 7.15
new txt file
83.5
7.15
.
.
.
n
so far I have this code:
fid=fopen('data.txt')
data = textscan(fid,'%*d %d %d')
time = (data{1})
score= (data{2})
for sample=1:length(score)
..... // I'm stucked here ..
end
....
If you are feeling adventurous, here's a vectorized one-line solution using ACCUMARRAY (assuming you already read the file in a matrix variable data like the others have shown):
NUM = 3;
result = accumarray(reshape(repmat(1:size(data,1)/NUM,NUM,1),[],1),data(:,3)) ...
./ (data(NUM:NUM:end,2)-data(1:NUM:end,2))
Note that here the number of samples NUM=3 is a parameter and can be substituted by any other value.
Also, reading your comment above, if the number of samples is not a multiple of this number (3), then simply discard the remaining samples by doing this beforehand:
data = data(1:fix(size(data,1)/NUM)*NUM,:);
Im sorry, here's a much simpler one :P
result = sum(reshape(data(:,3), NUM, []))' ./ (data(NUM:NUM:end,2)-data(1:NUM:end,2));
%# Easier to load with importdata
data = importdata('data.txt',' ',1);
%# Get the number of rows
n = size(data,1);
%# Column IDs
time = 2;score = 3;
%# The interval size (3 in your example)
interval = 3;
%# Pre-allocate space
new_data = zeros(numel(interval:interval:n),1);
%# For each new element in the new data
index = 1;
%# This will ignore elements past the closest (floor) multiple of 3 as requested
for i = interval:interval:n
%# First and last elements in a batch
a = i-interval+1;
b = i;
%# Compute the new data
new_data(index) = sum( data(a:b,score) )/(data(b,time)-data(a,time));
%# Increment
index = index+1;
end
For what it's worth, here is how you would go about to do that in Python. It is probably adaptable to Matlab.
import numpy
no, time, scores = numpy.loadtxt('data', skiprows=1).T
# here I assume that your n is a multiple of 3! otherwise you have to adjust
sums = scores[::3]+scores[1::3]+scores[2::3]
dt = time[2::3]-time[::3]
result = sums/dt
I suggest you use the importdata() function to get your data into your variable called data. Something like this:
data = importdata('data.txt',' ', 1)
replace ' ' by the delimiter your file uses, the 1 specifies that Matlab should ignore 1 header line. Then, to compute your results, try this statement:
(data(1:3:end,3)+data(2:3:end,3)+data(3:3:end,3))./(data(3:3:end,2)-data(1:3:end,2))
This worked on your sample data, should work on the real data you have. If you figure it out yourself you'll learn some useful Matlab.
Then use save() to write the results back to a file.
PS If you find yourself writing loops in Matlab you are probably doing something wrong.