magnitude squared coherence in matlab - frequency-analysis

I am tring to get magnitud squared coherence (MSC) and I am finding some problems.
In theory, the MSC is the result of the crospectra of two signals, devided by the autospectra of each signal.
Therefore, this is my code:
Fs = 1000; % Sampling frequency
T = 1/Fs; % Sampling period
L = length(myData(1,:)); % length of segment
Hz = Fs*(0:(L/2))/L; % frequency vector
dat1 = fft(myData(1,:));
dat2 = fft(myData(2,:));
pow1 = dat1.*conj(dat1); % autospectra signal 1
pow2 = dat2.*conj(dat2); % autospectra signal 2
cpow = abs(dat1.*conj(dat2)).^2; % crosspectra
coh = cpow./(pow1.*pow2); % getting the coherence
coherence = coh(1:L/2+1);
coherence(2:end-1) = coherence(2:end-1); % adjusting length to Nyquest freq
figure;
plot(Hz,coherence)
but the result are only "1" and it does not make much seance, so there must be I mistake but I just can't find it.
Thanks for your help

Related

Verify that all edges in a 2D graph are sufficiently far from each other

I have a graph where each node has coordinates in 2D (it's actually a geographic graph, with latitude and longitude.)
I need to verify that if the distance between two edges is less than MAX_DIST then they share a node. Of course, if they intersect, then the distance between them is zero.
The brute force algorithm is trivial, is there a more efficient algorithm?
I was thinking of trying to adapt https://en.wikipedia.org/wiki/Closest_pair_of_points_problem to graph edges (and ignoring pairs of edges with a shared node), but it is not trivial to do so.
I was curios to see how the rtree index idea would perform so I created a small script to test it using two really cool libraries for Python: Rtree and shapely
The snippet generates 1000 segments with 1 < length < 5 and coordinates in the [0, 100] interval, populates the index and then counts the pairs that are closer than MAX_DIST==0.1 (using the classic and the index-based method).
In my tests the index method was around 25x faster using the conditions above; this might vary greatly for your data set but the result is encouraging:
found 532 pairs of close segments using classic method
7.47 seconds for classic count
found 532 pairs of close segments using index method
0.28 seconds for index count
The performance and correctness of the index method depends on how your segments are distributed (how many are close, if you have very long segments, the parameters used).
import time
import random
from rtree import Rtree
from shapely.geometry import LineString
def generate_segments(number):
segments = {}
for i in range(number):
while True:
x1 = random.randint(0, 100)
y1 = random.randint(0, 100)
x2 = random.randint(0, 100)
y2 = random.randint(0, 100)
segment = LineString([(x1, y1), (x2, y2)])
if 1 < segment.length < 5: # only add relatively small segments
segments[i] = segment
break
return segments
def populate_index(segments):
idx = Rtree()
for index, segment in segments.items():
idx.add(index, segment.bounds)
return idx
def count_close_segments(segments, max_distance):
count = 0
for i in range(len(segments)-1):
s1 = segments[i]
for j in range(i+1, len(segments)):
s2 = segments[j]
if s1.distance(s2) < max_distance:
count += 1
return count
def count_close_segments_index(segments, idx, max_distance):
count = 0
for index, segment in segments.items():
close_indexes = idx.nearest(segment.bounds, 10)
for close_index in close_indexes:
if index >= close_index: # do not count duplicates
continue
close_segment = segments[close_index]
if segment.distance(close_segment) < max_distance:
count += 1
return count
if __name__ == "__main__":
MAX_DIST = 0.1
s = generate_segments(1000)
r_idx = populate_index(s)
t = time.time()
print("found %d pairs of close segments using classic method" % count_close_segments(s, MAX_DIST))
print("%.2f seconds for classic count" % (time.time() - t))
t = time.time()
print("found %d pairs of close segments using index method" % count_close_segments_index(s, r_idx, MAX_DIST))
print("%.2f seconds for index count" % (time.time() - t))

Octave - Mark zero crossings with an red X mark

Hi have made this code to plot a function.
I need to mark with an red X all the crossings between x = 0 and the blue wave line in the graph.
I have made some tries but with '-xr' in the plot function but it places X marks out of the crossings.
Anyone knows how to do it. Many thanks.
Code:
% entrada
a = input('Introduza o valor de a: ');
% ficheiro fonte para a função
raizes;
% chamada à função
x = 0:.1:50;
or = x;
or(:) = 0;
h = #(x) cos(x);
g = #(x) exp(a*x)-1;
f = #(x) h(x) - g(x);
zeros = fzero(f,0);
plot(x,f(x));
hold on
plot(zeros,f(zeros),'-xr')
hold off
Graph (it only marks one zero, i need all the zero crossings):
As mentioned in the comments above, you need to look for the zeros of your function before you can plot them. You can do this mathematically (in this case set f(x) = g(x) and solve for x) or you can do this analytically with something like fsolve.
If you read the documentation for fsolve, you will see that it searches for the zero closest to the provided x0 if passed a scalar or the first zero if passed an interval. What we can do for a quick attempt at a solution is to pass our x values into fsolve as initial guesses and filter out the unique values.
% Set up sample data
a = .05;
x = 0:.1:50;
% Set up equations
h = #(x) cos(x);
g = #(x) exp(a*x)-1;
f = #(x) h(x) - g(x);
% Find zeros of f(x)
crossingpoints = zeros(length(x), 1); % Initialize array
for ii = 1:length(x) % Use x data points as guesses for fzero
try
crossingpoints(ii) = fzero(f, x(ii)); % Find zero closest to guess
end
end
crossingpoints(crossingpoints < 0) = []; % Throw out zeros where x < 0
% Find unique zeros
tol = 10^-8;
crossingpoints = sort(crossingpoints(:)); % Sort data for easier diff
temp = false(size(crossingpoints)); % Initialize testing array
% Find where the difference between 'zeros' is less than or equal to the
% tolerance and throw them out
temp(1:end-1) = abs(diff(crossingpoints)) <= tol;
crossingpoints(temp) = [];
% Sometimes catches beginning of the data set, filter it out if this happens
if abs(f(crossingpoints(1))) >= (0 + tol)
crossingpoints(1) = [];
end
% Plot data
plot(x, f(x))
hold on
plot(crossingpoints, f(crossingpoints), 'rx')
hold off
grid on
axis([0 20 -2 2]);
Which gives us the following:
Note that due to errors arising from floating point arithmetic we have to utilize a tolerance to filter our zeros rather than utilizing a function like unique.

Flat top Pulse Amplitude Modulation

i want to plot flat-topped PAM of sinusoid. wave using matlab.
the sinusoidal signal has frequency = 10^4/(2*pi) HZ and sampling frequency = 8 kHZ. pulse duration T = 50 microseconds.
i wrote code for natural sampling, so how to do flat-top?
clear all;
close all;
Fs = 1e9;
t = 0:1/Fs:(0.2e-2);
fc = 8000; %sampling frequency
fm = 10^4/(2*pi); %message frequency
a = 1;
vm = a.*sin(2*pi*fm*t); %message
pulseperiods = [0:10]*1/fc;
pulsewidth = 50e-6;
vc = pulstran(t,pulseperiods,#rectpuls,pulsewidth);
y = vc.*vm;
figure
subplot(3,1,1);
plot(t,vm); % plot message
xlabel('Temps');
ylabel('Amplitude');
title('Message');
subplot(3,1,2);
plot(t,vc); % plot pulse
xlabel('Temps');
ylabel('Amplitude');
title('Switching waveform');
subplot(3,1,3);
plot(t,y); % plot PAM naturel
xlabel('Temps');
ylabel('Amplitude');
title('PAM naturel');
The flat-top PAM means the instantaneous sampling, i.e. the message signal is sampled only once per period, so modulated signal does not change its value until returning to zero and next sampling period. The sampling takes place at rising edge of carrier signal, so the solution is quite straightforward: by adding the for loop to your code:
for i = 2:length(t)
if vc(i) == 1 && vc(i-1) == 0 %if the rising edge is detected
y1(i) = vc(i) * vm(i); %sampling occurs
elseif vc(i) == 1 && vc(i-1) == 1 %and while the carrier signal is 1
y1(i) = y1(i-1); %the value of y1 remains constant
else
y1(i) = 0; %otherwise, y is zero
end
end
plot(t,y1); % flat-top PAM plot
xlabel('Temps');
ylabel('Amplitude');
title('PAM flat-top');
you get

Getting a cube with X volume in scilab or MATLAB?

I have a scilab program for averaging a 3D matrix and it works ok.However, instead of having the average just be a set value.I want it to be a certain sum of mass(sum(n*n*n).
K = 100
N = 5
A = 1
mid = floor(N/2)
volume = rand(K, K, K)
cubeCount = floor( K / N )
for x=0:cubeCount­1
for y=0:cubeCount­1
for z=0:cubeCount­1
// Get a cube of NxNxN size
cube = 20;
//Calculate the average value of the voxels in the cube
avg = sum( cube ) / (N * N * N);
// Assign it to the center voxel
volume( N*x+mid+1, N*y+mid+1, N*z+mid+1 ) = avg
end
end
end
disp( volume )
If anyone has a simple solution to this, please tell me.
You seem to have just about said it your self. All you would need to do would be change cube to equal.
cube = while sum(A * A * A) < 10,
A=A+1;
This will give you the correct sum of mass of the voxels.

How to generate a lower frequency version of a signal in Matlab?

With a sine input, I tried to modify it's frequency cutting some lower frequencies in the spectrum, shifting the main frequency towards zero. As the signal is not fftshifted I tried to do that by eliminating some samples at the begin and at the end of the fft vector:
interval = 1;
samplingFrequency = 44100;
signalFrequency = 440;
sampleDuration = 1 / samplingFrequency;
timespan = 1 : sampleDuration : (1 + interval);
original = sin(2 * pi * signalFrequency * timespan);
fourierTransform = fft(original);
frequencyCut = 10; %% Hertz
frequencyCut = floor(frequencyCut * (length(pattern) / samplingFrequency) / 4); %% Samples
maxFrequency = length(fourierTransform) - (2 * frequencyCut);
signal = ifft(fourierTransform(frequencyCut + 1:maxFrequency), 'symmetric');
But it didn't work as expected. I also tried to remove the center part of the spectrum, but it wielded a higher frequency sine wave too.
How to make it right?
#las3rjock:
its more like downsampling the signal itself, not the FFT..
Take a look at downsample.
Or you could create a timeseries object, and resample it using the resample method.
EDIT:
a similar example :)
% generate a signal
Fs = 200;
f = 5;
t = 0:1/Fs:1-1/Fs;
y = sin(2*pi * f * t) + sin(2*pi * 2*f * t) + 0.3*randn(size(t));
% downsample
n = 2;
yy = downsample([t' y'], n);
% plot
subplot(211), plot(t,y), axis([0 1 -2 2])
subplot(212), plot(yy(:,1), yy(:,2)), axis([0 1 -2 2])
A crude way to downsample your spectrum by a factor of n would be
% downsample by a factor of 2
n = 2; % downsampling factor
newSpectrum = fourierTransform(1:n:end);
For this to be a lower-frequency signal on your original time axis, you will need to zero-pad this vector up to the original length on both the positive and negative ends. This will be made much simpler using fftshift:
pad = length(fourierTransform);
fourierTransform = [zeros(1,pad/4) fftshift(newSpectrum) zeros(1,pad/4)];
To recover the downshifted signal, you fftshift back before applying the inverse transform:
signal = ifft(fftshift(fourierTransform));
EDIT: Here is a complete script which generates a plot comparing the original and downshifted signal:
% generate original signal
interval = 1;
samplingFrequency = 44100;
signalFrequency = 440;
sampleDuration = 1 / samplingFrequency;
timespan = 1 : sampleDuration : (1 + interval);
original = sin(2 * pi * signalFrequency * timespan);
% plot original signal
subplot(211)
plot(timespan(1:1000),original(1:1000))
title('Original signal')
fourierTransform = fft(original)/length(original);
% downsample spectrum by a factor of 2
n = 2; % downsampling factor
newSpectrum = fourierTransform(1:n:end);
% zero-pad the positive and negative ends of the spectrum
pad = floor(length(fourierTransform)/4);
fourierTransform = [zeros(1,pad) fftshift(newSpectrum) zeros(1,pad)];
% inverse transform
signal = ifft(length(original)*fftshift(fourierTransform),'symmetric');
% plot the downshifted signal
subplot(212)
plot(timespan(1:1000),signal(1:1000))
title('Shifted signal')
Plot of original and downshifted signals http://img5.imageshack.us/img5/5426/downshift.png

Resources