csc (cosecant) periodic equation and unexpected results - matlab

I can plot 1 (co-secant) every second over 2 seconds and it looks fine (the top plot). But when I plot the frequency of 100 csc (co-secant) signals I would expect / want 100 co-secant signals that are just repeating the same signal much like plotting y=.8*sin(100*t) would do but that doesn't occur what am I doing wrong? See code and plot below.
clear, clc
fs=8000
len_of_sig=2; %length of signal in seconds
t=linspace(0,2*pi*len_of_sig,fs*len_of_sig);
y_a=0.01*csc(1*t);
y_a(y_a >=1) = 1; %used to limit amplitude
y_a(y_a <=-1) = -1;
y_b=0.01*csc(100*t);
y_b(y_b >=1) = 1;
y_b(y_b <=-1) = -1;
t2=t./(2*pi); %converts time in radians to seconds
subplot(2,1,1);plot(t2(1:end),y_a(1:end));
subplot(2,1,2);plot(t2(1:end),y_b(1:end));
Ps: I'm using octave 4.0 which is like matlab

What you're seeing in the second subplot is the result of reduced sampling per cycle. You are increasing the frequency of y_b relative to y_a by a factor of 100, but still using the same vector of time points t, meaning you have 1/100th the number of points per cycle in y_b. These fewer points per cycle fall at slightly different offsets to the discontinuities, giving you the pattern above.
You can fix this by using an upsampled time vector for y_b:
t_up = linspace(0, 2*pi*len_of_sig, 100*fs*len_of_sig);
y_b = 0.01*csc(100*t_up);
y_b(y_b >= 1) = 1;
y_b(y_b <= -1) = -1;
subplot(2, 1, 2); plot(t_up./(2*pi), y_b);

Related

Generate a Rectangular Pulse in MATLAB

I need to create a rectangular pulse with width = 7 and a range (-T/2, T/2) where T 59 msec.
I wrote this code but I'm not sure if that's correct.
w = 7;
T = 59;
t = -T/2:1:T/2;
rect = rectpuls(t, w);
plot(t, rect);
This code generates a rectangular pulse but I'm not sure if it's right. Also, I'm not quite sure what the t = -T/2:1:T/2; means. I mean the range is from -29.5 to 29.5 with step 1. When I set this to 0.1 or 0.01 my pulse is better. Why does this affect my output?
Note that the second thing I have to do is to create a periodic sequence of clock pulses. I don't know if this affects the way I must implement my initial rectangular pulse.
When you increase the number of increments a numerical function (such as Matlab rectpuls) uses in its process of discretizing the continuous, you'll have as consequence that the accuracy of said function is going to improve, at the expense (in this case, negligible) of added computational cost. You are doing exactly this, when you discretize employing smaller time-steps, from 1 to 0.1 to 0.01.
To create a periodic sequence of identical rectangular pulses, you can call the function in a loop:
w = 7;
T = 59;
t = -T/2:1:T/2;
t_size = size(t);
N = 10;
rect = zeros(N, t_size(2));
interval = 20;
figure
plot(t, rectpuls(t, w));
xlim([-20 (N + 1)*interval]);
ylim([0 1.1]);
hold on
for i = 1:N
t = (-T/2 + i*interval): 1 :(T/2 + i*interval);
rect(i,:) = rectpuls(t - i * interval, w);
plot(t, rect(i,:));
hold on
end
The above should generate identical rectangular pulses every interval = 20 ms, over a time length of interval * (N + 1) = 220 ms.

How to break up a signal into equal blocks based on a threshold

I have a signal which is saved as a csv file. I'm trying to break up the signal into individual blocks of a fixed length (say 100 samples) for analysis (fft, wavelet, amplitude etc) when a threshold is crossed. If the threshold was to be placed at 5, I still need a bit before the threshold included in the block (say 30 of the 100 samples before the major peak, 70 after). How would I go about this, only getting 1 block output per signal pulse?
Many thanks in advance!
(https://imgur.com/IZuqgMM)
I've tried looping through the array to find data points where they're above the threshold but I'm struggling to reduce it to one point per pulse.
assuming your signal is in x, the following would find the index of the first peak that crosses the threshold.
threshold = 5;
n_pre = 30;
n_post = 70;
ind_first_peak = find(x > threshold, 1, 'first');
ind_pre = ind_first_peak - n_pre
ind_end = ind_first_peak + n_post;
ind_selection = ind_start:ind_end;
x_selection = x(ind_selection);
Now we can remove the first peak from the original signal, and repeat:
x_new = x;
x_new(x_selection) = []; % remove the first peak, so x_new can be used by find again.
This is not very robust, but depending on your signal and threshold could work. If you have access to the Signal Processing Toolbox, you could check findpeaks.

Generating a sine signal with time dependent frequency in Matlab

I want to generate a sine signal y(t) with a time dependent frequency f(t) in Matlab.
I've already tried to realise this using the sine function of Matlab:
h = 0.0001;
npoints = 150/h;
for i = 1:1:npoints
f(i) = 2 - 0.01*i*h;
y(i) = 0.5*sin(2*3.1415*f(i)*i*h)+0.5;
end
where the frequency is decreasing with time and h is the time step width.
My problem:
The signal y(t) doesn't look I expected it to look like. There appears a bump in the amplitude at a distinct time (have a look at the plot below).
Does anyone know why this happens and how to generate this sine signal correctly?
what about
y(i) = 0.5*real(exp(1i*2*pi*f(i)*i*h))+0.5;
You will get the plot below
If you just need a chirp signal starting from 2Hz down to 0.5Hz, the following should do the job
f_start = 2; % start frequency
f_end = 0.5; % end frequency
endtime = 150; % seconds
timestep = 0.0001;
times = timestep:timestep:endtime;
y = chirp(times,f_start,endtime,f_end);
and if you plot it you get
figure(2);plot(times,y);
You can achieve the same manually using below
f_start = 2; % start frequency
f_end = 0.5; % end frequency
timestep = 0.0001;
T = 150;
rate_of_change = (f_start - f_end)/T;
times = timestep:timestep:T;
y = sin(2*pi*(f_start*times - times.^2*rate_of_change/2));
It might be useful to read the following Wikipedia page on Chirp signal.
At 100 you have sin(2*pi*N), which is 0. Change f a little bit, say to 2.0123-... and it goes to the top.
As for the general probably unexpected shape, consider what function you are using in the end (= substitute f back in the formula). You see that you have something of the form y = ...sin(Ai-B*i^2)..., which has a minimum at 100.
The easiest solution here is to simply offset frequency a little more, and use something like f(i) = 3.1 - ..., which has a minimum outside of your considered range.
It looks like there isn't actually a "bump in frequency", but at the 100 value on the x-axis the entire signal is shifted by 180 degrees. Bear in mind that the amplitude still reaches 0 and does not become smaller (e.g. from 0.25 to 0.75)
This is because the i value becomes so high that the value of f(i) changes sign.
Another indicator of this is that the frequency starts to increase again after the shift instead of gradually becoming even lower.
Why do you start off with the value of 2 in f(i)?
Sorry for asking for clarification here, but I cannot post it as a comment.

period of sawtooth from measurements

I have a series of 2D measurements (time on x-axis) that plot to a non-smooth (but pretty good) sawtooth wave. In an ideal world the data points would form a perfect sawtooth wave (with partial amplitude data points at either end). Is there a way of calculating the (average) period of the wave, using OCTAVE/MATLAB? I tried using the formula for a sawtooth from Wikipedia (Sawtooth_wave):
P = mean(time.*pi./acot(tan(y./4))), -pi < y < +pi
also tried:
P = mean(abs(time.*pi./acot(tan(y./4))))
but it didn't work, or at least it gave me an answer I know is out.
An example of the plotted data:
I've also tried the following method - should work - but it's NOT giving me what I know is close to the right answer. Probably something simple and wrong with my code. What?
slopes = diff(y)./diff(x); % form vector of slopes for each two adjacent points
for n = 1:length(diff(y)) % delete slope of any two points that form the 'cliff'
if abs(diff(y(n,1))) > pi
slopes(n,:) = [];
end
end
P = median((2*pi)./slopes); % Amplitude is 2*pi
Old post, but thought I'd offer my two-cent's worth. I think there are two reasonable ways to do this:
Perform a Fourier transform and calculate the fundamental
Do a curve-fitting of the phase, period, amplitude, and offset to an ideal square-wave.
Given curve-fitting will likely be difficult because of discontinuities in saw-wave, so I'd recommend Fourier transform. Self-contained example below:
f_s = 10; # Sampling freq. in Hz
record_length = 1000; # length of recording in sec.
% Create noisy saw-tooth wave, with known period and phase
saw_period = 50;
saw_phase = 10;
t = (1/f_s):(1/f_s):record_length;
saw_function = #(t) mod((t-saw_phase)*(2*pi/saw_period), 2*pi) - pi;
noise_lvl = 2.0;
saw_wave = saw_function(t) + noise_lvl*randn(size(t));
num_tsteps = length(t);
% Plot time-series data
figure();
plot(t, saw_wave, '*r', t, saw_function(t));
xlabel('Time [s]');
ylabel('Measurement');
legend('measurements', 'ideal');
% Perform fast-Fourier transform (and plot it)
dft = fft(saw_wave);
freq = 0:(f_s/length(saw_wave)):(f_s/2);
dft = dft(1:(length(saw_wave)/2+1));
figure();
plot(freq, abs(dft));
xlabel('Freqency [Hz]');
ylabel('FFT of Measurement');
% Estimate fundamental frequency:
[~, idx] = max(abs(dft));
peak_f = abs(freq(idx));
peak_period = 1/peak_f;
disp(strcat('Estimated period [s]: ', num2str(peak_period)))
Which outputs a couple of graphs, and also the estimated period of the saw-tooth wave. You can play around with the amount of noise and see that it correctly gets a period of 50 seconds till very high levels of noise.
Estimated period [s]: 50

Find threshold cross in Matlab timeseries data, then ignore subsequent crosses for 60 seconds before finding next threshold cross

This is a little complicated to explain. I have time series data formatted like this: https://docs.google.com/spreadsheets/d/1B8mN0uD-t4kQr2U20gS713ZFHN6IgGB7OMR3-pqJjrw/edit?usp=sharing
That data represents voltage recordings at .01s intervals. When plotted it looks like this:
Essentially what I want to do is find the time at which the first peak in each very narrow pair occur (ie at ~.1, .75, 1.6, etc).
The time values are in a separate array, but the index values (row numbers) correspond between the two sets.
Any ideas on how to do this?
My initial attempt was something like this from the matlab manual
function [edges2] = risingEdge2(time, data)
threshold = 0.4;
offsetData = [data(2:end); NaN];
edges2 = find(data < threshold & offsetData > threshold);
end
I couldn't figure out a good way to ignore for n seconds after the first peak...I'm also getting many more peaks than expected...probably because of noisy data.
The following approach seems to work for the given data.
%// Define parameters
window_size = 200;
stepsize = 0.4; %// to be used for quantizing data into three levels - 0, 0.4, 0.8
%// Perform a sliding max to get rid of the dips within the spikes
slmax_data = nlfilter(data,[window_size 1],#max);
%// Quantize sliding max data to three levels as the plot seem to suggest
quantized_slmax_data = round((slmax_data-min(slmax_data))./stepsize);
If you zoom into the above figure, you will see ledges around the high peaks -
%// Get sliding mode to get rid of the short ledges around the high peaks
slmax_mode_data = nlfilter(quantized_slmax_data,[window_size 1],#mode);
%// Finally, find the indices where the mode data jump from 0 to 1 only, which
%// correspond to the start of spikes
index = find(diff(slmax_mode_data)==1)+window_size/2;
Output -
index =
682
8048
16487
24164
31797
Here -- find all rising edges, then find those that are very close together and take the first.
rising_edges = find(diff(data > .3) > 0);
first_of_paired_edges = find(diff(time(rising_edges)) < 500);
first_rising_edge_times = time(rising_edges(first_of_paired_edges));
You could then slide up the edge to the peak.
first_peak_times = time(arrayfun( #(n) n+find(diff(data(n+[0:1000]) < 0, 1, 'first'),
rising_edges(first_of_paired_edges));