In a signal created like so:
Tinitial =0;
Tfinal = 1;
NbEch = 300;
Tech = (Tfinal - Tinitial)/(NbEch-1);
t = Tinitial : Tech: Tfinal; % time vector
signal = sin(2*pi*t*3) + 0.25*sin(2*pi*t*50) + randn(size(t))/10;
figure
plot(t,signal)
I want to calculate the signal maximum between 0% and 10% of the time and between 50% and 60% of the time. I've tried using ginput on the figure, but want this to be done automatically because I have several curves of the same type in a loop.
Calculate the time percentages
tpct = (t-Tinitial)/(Tfinal - Tinitial);
Calculate maximums using logical indexing and the percentage vector we just made.
sigMax0_to_10 = max( signal(tpct >= 0.0 & tpct <= 0.1) ); % max between 0% - 10% time
sigMax50_to_60 = max( signal(tpct >= 0.5 & tpct <= 0.6) ); % max between 50% - 60% time
You could easily adapt this to have your upper and lower thresholds in an array and loop over them.
Related
The code has an array or loop error or cannot use the information. I want to calculate for 1 to 100 all cycles. And from these Cycles it should find out the most dominant cycle length and plot this dominant one to the chart. Better would be to get the 3 most dominant cycles and put them together into one plotted line. Please help! unfortunately
TV has no functions for detecting dominant cycles and this should solve the problem but it hast some script Problems.
//#version=5
// Import the ta-lib library
indicator("ta-lib")
// Define the period range for the analysis
periodStart = 1
periodEnd = 100
// Define the data series
dataSeries = close
// Create an array to store the magnitude of the DFT for each period
magnitudeArray = array.new<float>(periodEnd)
// Loop over the periods
for period = periodStart to periodEnd
// Initialize the real and imaginary parts of the DFT for each period
re = 0.0
im = 0.0
// Loop over the data for each period
for i = 0 to period-1
re := re + dataSeries[i]*math.cos(-2*math.pi*i/period)
im := im + dataSeries[i]*math.sin(-2*math.pi*i/period)
// Calculate the magnitude of the complex numbers for each period
magnitudeArray[period] := math.sqrt(re*re + im*im)
// Initialize a variable to store the maximum magnitude and its corresponding period
maxMagnitude = 0.0
dominantCyclePeriod = 0
// Loop over the magnitude array to find the period with the highest magnitude
for period = periodStart to periodEnd
if array.max(magnitudeArray[period]) > maxMagnitude
maxMagnitude = array.max(magnitudeArray[period])
dominantCyclePeriod = period
// Plot the dominant cycle period on the chart
plot(dominantCyclePeriod)
I am using MATLAB R2020a on a MacOS. I have an ECG signal with a sampling frequency of 1kHz. From cycle to cycle, there are a different number of samples since the cycle lenghts are different. However, I would like to have an array which has an equal number of samples (around 800) for each cycle such that those 800 sample points are automatically fitted to the original sample points regardless of the number of original sample points. I know that the resample function allows resampling at a fraction of the frequency of the input signal, but I am not sure how this would help me achieve my aim given that I would like to resample for a fixed number of points.
I would very much appreciate any suggestions. Thanks in advance
Here is my code:
% Delimit cycles in original maximum amplitude signal using indices from
% Pan Tompkins algorithm
number_cycles = round(length(qrs_i_raw)/2);
number_samples = 900;
cycle_points_maxamp = zeros(number_cycles, length(number_samples));
x_eachcycle = zeros(number_cycles, length(number_samples));
values_x = zeros(length(number_samples), 1);
y_eachcycle = zeros(number_cycles, length(number_samples));
values_y = zeros(length(number_samples), 1);
z_eachcycle = zeros(number_cycles, length(number_samples));
values_z = zeros(length(number_samples), 1);
v_eachcycle = zeros(number_cycles, length(number_samples));
w_eachcycle = zeros(number_cycles, length(number_samples));
for currentcycle = 1:length(number_cycles)
values_maxamp = maxamp(qrs_i_raw(currentcycle):qrs_i_raw(currentcycle + 1)); % need to resample to only generate 900 samples
cycle_points_maxamp(currentcycle, 1:length(values_maxamp)) = values_maxamp;
values_z(1 + 2*tau_milli_rounded(currentcycle):end) = cycle_points_maxamp(currentcycle, 1:end - 2*tau_milli_rounded(currentcycle));
z_eachcycle(currentcycle, 1:length(values_z)) = values_z;
values_y(1 + tau_milli_rounded(currentcycle):end) = cycle_points_maxamp(currentcycle, 1:end - tau_milli_rounded(currentcycle));
y_eachcycle(currentcycle, 1:length(values_y)) = values_y;
values_x(1:end) = cycle_points_maxamp(currentcycle, 1:end);
x_eachcycle(currentcycle, 1:length(values_x)) = values_x;
values_v = ((1/sqrt(6))*(x_eachcycle(currentcycle, 1:length(values_x))) + (y_eachcycle(currentcycle, 1:length(values_y))) - 2*(z_eachcycle(currentcycle, 1:length(values_z))));
v_eachcycle(currentcycle, 1:length(values_v)) = values_v;
values_w = ((1/sqrt(2))*(x_eachcycle(currentcycle, 1:length(values_x))) - (y_eachcycle(currentcycle, 1:length(values_y))));
w_eachcycle(currentcycle, 1:length(values_w)) = values_w;
end
Here are the relevant variables:
maxamp
qrs_i_raw
cyclepointsarray
To resample a single cycle of the signal to have a length of 800 points/samples the resample() function can be used with parameters 800 and length(Random_Cycle). Here I used a sinc signal arbitrarily. The resample() function will interpolate (upsample) or decimate (downsample) according to the number of available sample points in the original signal. I would first partition your signal into separate cycles apply this type of resampling the concatenate the resampled components to generate your full resampled ECG signal.
Random_Cycle = sinc(-2*pi:0.5:2*pi);
subplot(1,2,1); stem(Random_Cycle);
title("Number of Samples: " + num2str(length(Random_Cycle)));
Resampled_Signal = resample(Random_Cycle,800,length(Random_Cycle));
subplot(1,2,2); stem(Resampled_Signal);
title("Number of Samples: " + num2str(length(Resampled_Signal)));
Ran using MATLAB R2019b
I have an EEG data base that I would like to plot.
The database is a 19*1000*134 matrix, with:
19 being the number of channel. On a first approach, I'm working with only one channel.
1000 the size of a sample (1000 points for a sampling rate of 500 Hz, i.e. 2 sec of data)
134 the number of epochs (number of different 2 second experience)
The idea is to plot epoch n right after epoch n-1 on the same graph. The (X,Y) matrix used to plot this has a 134 000 * not_much size, and I would like to be able to scroll horizontally on the plot, to see individually each epoch.
My code right now, plotting only one channel:
fs = s_EEG.sampling_rate;
[channel, length, nb_epoch] = size(s_EEG.data)
display(s_EEG.data, fs, length, channel, nb_epoch)
function display(data, fs, length, channel, nb_epoch)
figure("Name", "Epoch display")
for j = 1:nb_epoch
time = 0.002+(2*j-2):1/fs:2*j;
epoch = data(1,:,j);
plot(time, epoch)
hold on
end
hold off
end
Current output:
I'm completely new to Matlab, and I don't use it well yet, but I would like to find a way to see on the same graph, individually, and at a correct visualization scale, all of my 134 epochs (one color = one epoch above).
Thanks !
This is very similar to something I already had so I tweaked it a bit for you. Basically pass plotData your data matrix. It will plot each of your items sequentially as you already have now.
Pressing the slider will change your x-limits so that you will step through 1 element (epochs) at a time. Clicking in the area will advance 2-epochs at a time. It currently just displays what you currently viewed "epoch" # is at the command line disp(['Current Epoch: ' num2str(viewI)]) However, it should be easy for you to redirect that to a text box on the figure to more readily know which you are viewing ... besides mentally dividing the x-limits by 2.
Use the list box to switch to a new channel which will reset the plot & x-limits.
Call it like this at the command line.
>> plotData( data )
CODE: Save everything below as plotData.m
function plotData( data )
% data = rand(19,1000,134);
f = figure('Units','Normalized','Position',[0.25 0.25 0.5 0.5]);
a = axes('Units','Normalized','Position',[0.05 0.15, 0.75 0.75]);
s = uicontrol(f, 'Style','Slider', 'Units','Normalized','Position',[0.05 0.025, 0.75 0.05],...
'Min',1,'Max',size(data,3),'Value',1, 'Callback',{#sliderChange,a} );
l = uicontrol(f, 'Style','listbox','Units','Normalized','Position',[0.85 0.15, 0.1, 0.75],...
'String',cellstr(num2str([1:size(data,1)]')),'Callback',{#changeChannel,a,s,data} );
stepSize = 1/(s.Max - s.Min);
s.SliderStep = [stepSize 2*stepSize];
changeChannel(l,[],a,s,data)
function changeChannel(l,evtData,a,s,data)
cla(a);
chanNum = str2double(l.String{l.Value});
sR = 500; %500Hz
tempData = reshape(data(chanNum,:,:),[],size(data,3)); %Reshape each epoch into a column
tempTime = [0:1/sR:(size(data,2)-1)/sR]' + (0:1:size(data,3)-1)*2; %Build time array
plot(a,tempTime,tempData) %plot all the lines
s.Value = 1; %Rest Slider Position
function sliderChange(s,evtData,a)
viewI = round(s.Value);
disp(['Current Epoch: ' num2str(viewI)])
xlim(a,[(viewI-1)*2 viewI*2] + [-.1 .1])
Note: This uses implicit expansion so you need Matlab 2016b or higher.
I'm trying to create a contour plot with focus around a particular finite range from 1 to 1.05. At the same time, I need very high resolution closer to 1. I thought I could use something like the following but the spacing still looks linear
out=exp(linspace(log(1),log(1.05),100))
plot(diff(out))
What is the best way to enhance the nonlinearity of the spacing when the bounds are so tight? Again, I need to maintain high density near 1 with the resolution tapering off in a nonlinear way. I have a few ideas but I thought someone might have a quick 2 liner or something of the sort.
instead of applying the function f(x) = ex, to get a 'steeper' non-linearity, rather apply f(x) = eax
n = 20;
a = 100;
lower = 1;
upper = 1.05;
temp = exp(linspace(log(1)*a,log(1.05)*a,n))
% re-scale to be between 0 and 1
temp_01 = temp/max(temp) - min(temp)/max(temp)
% re-scale to be between your limits (i.e. 1 and 1.05)
out = temp_01*(upper-lower) + lower
now plot(diff(out),diff(out),'o') produces
Note that you can use the exact same scaling scheme above with logspace so just use
temp = logspace(...)
and then the rest is the same
You can generate a logarithmic distribution between, for example, 1 and 1000 and then scale it back to [1, 1.05]:
out = logspace(0, 3, 100);
out = ( (out-min(out(:)))*(1.05-1) ) / ( max(out(:))-min(out(:)) ) + 1;
Result:
plot(diff(out));
I have two signals, let's call them 'a' and 'b'. They are both nearly identical signals (recorded from the same input and contain the same information) however, because I recorded them at two different 'b' is time shifted by an unknown amount. Obviously, there is random noise in each.
Currently, I am using cross correlation to compute the time shift, however, I am still getting improper results.
Here is the code I am using to calculate the time shift:
function [ diff ] = FindDiff( signal1, signal2 )
%FINDDIFF Finds the difference between two signals of equal frequency
%after an appropritate time shift is applied
% Calculates the time shift between two signals of equal frequency
% using cross correlation, shifts the second signal and subtracts the
% shifted signal from the first signal. This difference is returned.
length = size(signal1);
if (length ~= size(signal2))
error('Vectors must be equal size');
end
t = 1:length;
tx = (-length+1):length;
x = xcorr(signal1,signal2);
[mx,ix] = max(x);
lag = abs(tx(ix));
shifted_signal2 = timeshift(signal2,lag);
diff = signal1 - shifted_signal2;
end
function [ shifted ] = timeshift( input_signal, shift_amount )
input_size = size(input_signal);
shifted = (1:input_size)';
for i = 1:input_size
if i <= shift_amount
shifted(i) = 0;
else
shifted(i) = input_signal(i-shift_amount);
end
end
end
plot(FindDiff(a,b));
However the result from the function is a period wave, rather than random noise, so the lag must still be off. I would post an image of the plot, but imgur is currently not cooperating.
Is there a more accurate way to calculate lag other than cross correlation, or is there a way to improve the results from cross correlation?
Cross-correlation is usually the simplest way to determine the time lag between two signals. The position of peak value indicates the time offset at which the two signals are the most similar.
%// Normalize signals to zero mean and unit variance
s1 = (signal1 - mean(signal1)) / std(signal1);
s2 = (signal2 - mean(signal2)) / std(signal2);
%// Compute time lag between signals
c = xcorr(s1, s2); %// Cross correlation
lag = mod(find(c == max(c)), length(s2)) %// Find the position of the peak
Note that the two signals have to be normalized first to the same energy level, so that the results are not biased.
By the way, don't use diff as a name for a variable. There's already a built-in function in MATLAB with the same name.
Now there are two functions in Matlab:
one called finddelay
and another called alignsignals that can do what you want, I believe.
corr finds a dot product between vectors (v1, v2). If it works bad with your signal, I'd try to minimize a sum of squares of differences (i.e. abs(v1 - v2)).
signal = sin(1:100);
signal1 = [zeros(1, 10) signal];
signal2 = [signal zeros(1, 10)];
for i = 1:length(signal1)
signal1shifted = [signal1 zeros(1, i)];
signal2shifted = [zeros(1, i) signal2];
d2(i) = sum((signal1shifted - signal2shifted).^2);
end
[fval lag2] = min(d2);
lag2
It is computationally worse than cross-calculation which can be speeded up by using FFT. As far as I know you can't do this with euclidean distance.
UPD. Deleted wrong idea about cross-correlation with periodic signals
You can try matched filtering in frequency domain
function [corr_output] = pc_corr_processor (target_signal, ref_signal)
L = length(ref_signal);
N = length(target_signal);
matched_filter = flipud(ref_signal')';
matched_filter_Res = fft(matched_filter,N);
corr_fft = matched_filter_Res.*fft(target_signal);
corr_out = abs(ifft(corr_fft));
The peak of the matched filter maximum-index of corr_out above should give you the lag amount.