I have a Matlab file that reads a text file getting values for r, c and Beta. Using those 3 columns I want to combine this with a file in Matlab with airfoil coordinates which I eventually split up in slices (I want around 30 pieces) of X and Y coordinates.
The problem I'm facing is that the dlmwrite doesn't give any output files. The file did work before, but now I don't see any xls file appearing. I have looked at the dlmwrite specifically, but I can't find my mistake.
n is the number of slices I want to create, which is equal to the number of lines in the text file which contains r, c and Beta. The Z = ones(81,1) is the number of airfoil coordinates (X and Y together counts as 1)
clear all
close all
clc
%Create and output propeller geometry text files for solidworks
Propeller_Geometry = 'lllllaatsten.txt';
Airfoil_Geometry = 'as5048.txt'; %airfoil x_c, z_c
[r, c, beta] = textread(Propeller_Geometry) % (m, m, deg)
[x_c, z_c] = textread(Airfoil_Geometry); %(-, -)
c = c * 1000; % Chord Length (mm)
r = r * 1000; % Radius Length (mm)
beta = beta * pi / 180; % Angle from rotational velocity vector to lower blade edge (rad)
n = 50; % Number of slices
hold on
plot(x_c, z_c, '-b')
axis([0 1 -0.5 0.5])
xlabel('Unit Chord ( x/c)', 'fontsize', 14)
ylabel('Unit Height (z/c)', 'fontsize', 14)
title('TA22 Airfoil Geometry', 'fontsize', 14)
%Create dimensional slices
for i=1:n+1
x = x_c * c(i); % Dimensional Chord (mm)
y = z_c * c(i); % Dimensional Height (mm)
X = x * cos(-beta(i)) - y * sin(-beta(i)); % Rotated x-coordinate
Y = y * cos(-beta(i)) + x * sin(-beta(i)); % Rotated y-coordinate
Z = ones(81,1) * r(i);
P = horzcat(-X, Y, Z);
%dlmwrite(['Slice_' int2str(i)'.xls'], P, 'delimiter', '\t', 'precision', 8)
%dlmwrite(['stuk_' int2str(i) '.txt'], P, 'delimiter', '\t', 'precision', 8)
dlmwrite (['stuk_' int2str(i) '.xls'], P, '-append', 'delimiter', '\t', 'newline', 'pc')
plot3(Z, -X, Y); %cm
axis([0 50 -30 0 -7 1])
xlabel('Radius (mm)', 'fontsize', 18)
ylabel('Chord (mm)', 'fontsize', 18)
zlabel('Height (cm)', 'fontsize', 18)
title('Propeller geometry', 'fontsize', 18)
grid
end
Related
I have a unit circle with n roots of unity marked. I would like to be able to rotate, translate, and scale a line resting on the x-axis (between -1 and 1) to connect any pair of marked roots. Currently my code can do this in some cases, but doesn't work in general. I want to avoid hard-coding how the line should move for each possible pair. Here's what I have so far:
clear
%% Roots of unity
n = 10;
roots = zeros(1, n);
for k = 1 : n
roots(k) = exp(2 * k* pi * 1i / n);
end
%% Move line
% Pair of roots the line should connect
point_1 = roots(2);
point_2 = roots(6);
% Coordinates of pair of roots
x1 = real(point_1);
x2 = real(point_2);
y1 = imag(point_1);
y2 = imag(point_2);
d = sqrt((x1-x2)^2+(y1-y2)^2); % Euclidean distance between pair of roots
m = (y1 - y2) / (x1 - x2); % Gradient of line connecting pair of roots
c = y1 - m * x1; % y-intercept of line
int = -c / m; % x-coordinate that the rotation should occur at
shift = [int; 0];
x = linspace(-1, 1, 10); % Initial line lying purely on x-axis
y = 0 * x;
v = [x; y];
theta = atan((y2-shift(2))/(x2-shift(1))); % Angle by which to rotate
rot = [cos(theta), -sin(theta); sin(theta), cos(theta)]; % Rotation matrix
u = v * (d / 2); % Scale initial line
if m < 1e-3 % Horizontal case
shift = [0; 0];
end
w = (rot * (u - shift)) + shift; % Apply rotation
% Another shift that seems necessary
% This is definitely a problematic section
shift_x = w(1, 1) - x2;
shift_y = w(2, 1) - y2;
shift_2 = [shift_x; shift_y];
w = w - shift_2;
%% Plot
fig = figure;
fig.Units = 'inches';
fig.Position = [1, 1, 9, 9];
ax = gca;
tt = title(ax, 'Title');
tt.FontWeight = 'bold';
tt.FontSize = 20;
st = subtitle(ax, sprintf('More text here'));
st.FontAngle = 'italic';
st.FontSize = 15;
hold on
hCircle = viscircles([0, 0], 1, 'Color', 'k');
for i = 1 : n
x_point = real(roots(i));
y_point = imag(roots(i));
hPin = plot(x_point, y_point, 'Marker', 'o', 'MarkerSize', 20, 'MarkerfaceColor', 'red', ...
'MarkerEdgeColor', 'black');
end
% Plot original and shifted line, split into colours so direction is easier to see
plot(v(1,1:4), v(2,1:4), 'b');
plot(v(1,4:7), v(2,4:7), 'r');
plot(v(1,7:end), v(2,7:end), 'g');
plot(w(1,1:4), w(2,1:4), 'b');
plot(w(1,4:7), w(2,4:7), 'r');
plot(w(1,7:end), w(2,7:end), 'g');
For example, keeping point_1 = roots(2); and changing only point_2 = roots(p); works as intended for only p=3, 4, 6, 7, 8.
Any guidance on how to get this working would be greatly appreciated, thanks!
Edit:
To give some more details, basically I have an array of numbers between 0 and 1 (rather than just a line) which I want to plot on the line that would connect two roots. E.g. if my array is x=[0.2, 0.5, 0.9], then I want three points between point_1 and point_2, the first being 0.2d down the connecting line away from point_1, the second 0.5d (i.e. halfway), and the final being 0.9d away.
First of all, since the points you want to connect are complex numbers, it is easier to work with complex coordinate directly.
Roots of unity
I have simplified your code a bit.
Some may raise a flag on naming a variable roots since roots is a built-in matlab function. I am fine with it, as long as the usage does not cause any confusion, namely, don't use roots as a variable and as a function in the same context.
As matlab provides so many built-in functions, it is impossible to avoid name collision unless one knows them all by heart or searches before naming every single variable.
n = 10;
k = 1:n;
roots = exp(2 * k * pi * 1i / n);
Scaling, rotating, and translating
% Pair of roots the line should connect
point_1 = roots(2);
point_2 = roots(6);
d = abs(point_2 - point_1); % distance between pair of roots
theta = angle(point_2 - point_1); % rotation angle
p_on_line = linspace(-1, 1, 10); % Initial line lying on x-axis
p_on_line = p_on_line * d/2; % scale
p_on_line = p_on_line * exp(1i*theta); % rotate
p_on_line = p_on_line + (point_1 - p_on_line(1)); % translate
Plot
I added some scatter points and removed irrevelant parts (e.g. title, fonts).
fig = figure;
fig.Units = 'inches';
fig.Position = [1, 1, 9, 9];
hold on
hCircle = viscircles([0, 0], 1, 'Color', 'k');
hPin = plot(roots, 'o', 'MarkerSize', 20, 'MarkerfaceColor', 'red', ...
'MarkerEdgeColor', 'black');
% Plot line connecting roots
plot(p_on_line(1:4), 'b.-', 'MarkerSize', 20);
plot(p_on_line(4:7), 'r.-', 'MarkerSize', 20);
plot(p_on_line(7:end), 'g.-', 'MarkerSize', 20);
% Plot original line
original_x = linspace(-1, 1, 10);
original_y = zeros(1, 10);
plot(original_x(1:4), original_y(1:4), 'b.-', 'MarkerSize', 20);
plot(original_x(4:7), original_y(4:7), 'r.-', 'MarkerSize', 20);
plot(original_x(7:end), original_y(7:end), 'g.-', 'MarkerSize', 20);
hold off
This should work for all combinations of root pairs.
My goal is to fit a sinusoid to data goming from a datalogger using Octave.
The datalogger logs force which is produced using an excenter, so it theoretically should be a sine wave.
I could not find any hint on how to do this elsewhere.
Currently I'm using the function "splinefit" followd by "ppval" to fit my data but I don't realy get the results I hoped from it...
Has anybody an idea how I could fit a sinusoid to my data?
Here's my current code I use to fit the data and a scrennshot of the result:
## splinefit force left
spfFL = splinefit(XAxis,forceL,50);
fitForceL=ppval(spfFL,XAxis);
##middle force left
meanForceL=mean(fitForceL);
middleedForceL=fitForceL-meanForceL;
result spline fit
on the X-Axis I have the 30'000 measurepoints or logs
on the Y-Axis I have the actual measured force values
the data comes from the datalogger in a .csv-file like this
You can do a simple regression using the sine and cosine of your (time) input as your regression features.
Here's an example
% Let's generate a dataset from a known sinusoid as an example
N = 1000;
Range = 100;
w = 0.25; % known frequency (e.g. from specs or from fourier analysis)
Inputs = randi(Range, [N, 1]);
Targets = 0.5 * sin( w * Inputs + pi/3 ) + 0.05 * randn( size( Inputs ) );
% Y = A + B sin(wx) + C cos(wx); <-- this is your model
Features = [ ones(N, 1), sin(w * Inputs), cos(w * Inputs) ];
Coefs = pinv(Features) * Targets;
A = Coefs(1); % your solutions
B = Coefs(2);
C = Coefs(3);
% print your nice solution against the input dataset
figure('position', [0, 0, 800, 400])
ax1 = axes()
plot(Inputs, Targets, 'o', 'markersize', 10, ...
'markeredgecolor', [0, 0.25, 0.5], ...
'markerfacecolor', [0, 0.5, 1], ...
'linewidth', 1.5)
set(ax1, 'color', [0.9, 0.9, 0.9])
ax2 = axes()
X = 1:0.1:Range;
plot( X, A + B*sin(w * X) + C*cos(w * X), 'k-', 'linewidth', 5 ); hold on
plot( X, A + B*sin(w * X) + C*cos(w * X), 'g-', 'linewidth', 2 ); hold off
set(ax2, 'xlim', get(ax1, 'xlim'), 'ylim', get(ax1, 'ylim'), 'color', 'none')
You could do a least squares optimization, using fminsearch
% sine to fit (in your case your data)
x = 0:0.01:50;
y = 2.6*sin(1.2*x+3.1) + 7.3 + 0.2*rand(size(x)); % create some noisy sine with known parameters
% function with parameters
fun = #(x,p) p(1)*sin(p(2)*x+p(3)) + p(4); % sine wave with 4 parameters to estimate
fcn = #(p) sum((fun(x,p)-y).^2); % cost function to minimize the sum of the squares
% initial guess for parameters
p0 = [0 0 0 0];
% parameter optimization
par = fminsearch(fcn, p0);
% see if estimated parameters match measured data
yest = fun(x, par)
plot(x,y,x,yest)
Replace x and y with your data. The par variable contains the parameters of the sine, as defined in fun.
I'm using random points to determine the area below a curve (Monte-Carlo):
X: 1xn vector of x values for the function
Y: 1xn vector of y = f(x)
RP: mxn matrix of m random y for each x
I would like to split RP into RPA and RPB depending on it being above or below the curve. The idea is then to plot RPA and RPB against X, in different colors. This code doesn't work because RPA and RPB number of columns is not the same than X:
clf
f = #(x) sin(x/10) + cos(x/60); % Function
xMin = 1; xMax = 100; % x interval
X = [xMin:xMax];
Y = f(X);
plot(X,Y), hold on % Plot function
yMin = min(Y); yMax = max(Y); % Axes limits
set(gca, 'xlim', [xMin, xMax], 'ylim', [yMin, yMax])
m = 20; % Random points per x value
RP = rand(m, columns(X)) .* (yMax-yMin) .+ yMin;
% Split points (doesn't work)
RPA = RP(RP>Y);
RPB = RP(RP<=Y);
br = size(RPB) / size(RP) % Ratio of points below
a = (xMax - xMin) * (yMax - yMin) * br % Area below
% Plot points
plot(X, RPA, 'r.') % Above
plot(X, RPB, 'g.') % Below
Is there a possibility to build RPA and RPB so that they are the same size than RP, with the excluded points y being NaN or something similar, which can be counted and plotted?
You gave a good answer yourself. You can build RPA and RPB with strategic NaNs:
% Split points (works!)
RPA = RP;
RPA(RP<=Y) = NaN;
RPB = RP;
RPB(RPB > Y) = NaN;
And than calculating the ration as the not-NaN:
br = sum(~isnan(RPB)) / sum(~isnan(RP)) % Ratio of points below
I get this nice image:
I am trying to draw a (10,000 x 10,000) hexagonal lattice which is randomly half black and half white.I don't know how to fill hexagons of this lattice randomly to black and white.(this is a sample of what i really want from this code but I couldn't make it.).here is the code(written in matlab):
clc
x=input('enter the value of x: ');
y=input('enter the value of y: ');
r=input('enter the value of R: ');
n=input('enter the value of N: ');
d=sqrt(3*n)*r
axis([0 x 0 y ])
c=r;
v=30:60:390;
cv=r*cosd(v);
sv=r*sind(v);
for y=0:2:y
for w=0:2:x
line(w*sqrt(3)/2*c+cv,y*1.5*c+sv,'tag','h');
end
end
for m=1:2:y
for k=1:2:x
line(k*sqrt(3)/2*c+cv,m*1.5*c+sv,'tag','h');
end
end
can anyone help me through this?
Not recommended!
You can achieve your desired output using fill and by coordinating through the lattice correctly:
m = 100; % horizontal count
n = 50; % vertical count
blackratio = 0.5; % here you can choose the ratio of black hexagons
% parametric definition of a hexagon
t = (1/12:1/6:1)'*2*pi;
x = cos(t);
y = sin(t);
blacks = rand(m, n) < blackratio;
d=sqrt(3)/2;
figure;
hold on
for ii = 1:m
for jj = 1:n
if blacks(ii, jj)
% draw a black hexagon
fill(x + d*(mod(2*ii+jj, 2*m)), y+1.5*jj, 'k', 'EdgeColor', 'None')
else
% draw a white hexagon
fill(x + d*(mod(2*ii+jj, 2*m)), y+1.5*jj, 'w', 'EdgeColor', 'None')
end
end
end
axis equal tight off
With this output:
Note that on my laptop for 100x50 it took 6 seconds to get the result. For 1000x1000 my computer crashed.
The second fill function in my code replaces the transparency with white color. If you are fine with having transparency instead of white filling, you can remove this part of the code and double the speed.
You can plot multiple filled polygons using patch. This approach is extremely faster than drawing hexagons with fill one by one in a loop.
m = 100; % horizontal count
n = 50; % vertical count
blackratio = 0.5; % here you can choose the ratio of black hexagons
blacks = rand(m, n) > blackratio;
hexcount = sum(blacks(:));
whitecount = m * n - hexcount;
% parametric definition of a hexagon
t = (1/12:1/6:1)' * 2 * pi;
x = cos(t);
y = sin(t);
% coordinates of all black hexagons
Xb = zeros(6, hexcount);
Yb = zeros(6, hexcount);
% coordinates of all white hexagons
Xw = zeros(6, whitecount);
Yw = zeros(6, whitecount);
d=sqrt(3)/2;
bcount = 0;
wcount = 0;
for ii = 1:m
for jj = 1:n
if blacks(ii, jj)
bcount = bcount + 1;
Xb(:, bcount) = x + d * (mod(2 * ii + jj, 2 * m));
Yb(:, bcount) = y + 1.5 * jj;
else
wcount = wcount + 1;
Xw(:, wcount) = x + d * (mod(2 * ii + jj, 2 * m));
Yw(:, wcount) = y + 1.5 * jj;
end
end
end
figure; hold on
patch(Xb, Yb, 'k', 'EdgeColor', 'None')
patch(Xw, Yw, 'w', 'EdgeColor', 'None')
axis equal off
This gives you the desired output:
I'm looking for a simple way for creating a random unit vector constrained by a conical region. The origin is always the [0,0,0].
My solution up to now:
function v = GetRandomVectorInsideCone(coneDir,coneAngleDegree)
coneDir = normc(coneDir);
ang = coneAngleDegree + 1;
while ang > coneAngleDegree
v = [randn(1); randn(1); randn(1)];
v = v + coneDir;
v = normc(v);
ang = atan2(norm(cross(v,coneDir)), dot(v,coneDir))*180/pi;
end
My code loops until the random generated unit vector is inside the defined cone. Is there a better way to do that?
Resultant image from test code bellow
Resultant frequency distribution using Ahmed Fasih code (in comments).
I wonder how to get a rectangular or normal distribution.
c = [1;1;1]; angs = arrayfun(#(i) subspace(c, GetRandomVectorInsideCone(c, 30)), 1:1e5) * 180/pi; figure(); hist(angs, 50);
Testing code:
clearvars; clc; close all;
coneDir = [randn(1); randn(1); randn(1)];
coneDir = [0 0 1]';
coneDir = normc(coneDir);
coneAngle = 45;
N = 1000;
vAngles = zeros(N,1);
vs = zeros(3,N);
for i=1:N
vs(:,i) = GetRandomVectorInsideCone(coneDir,coneAngle);
vAngles(i) = subspace(vs(:,i),coneDir)*180/pi;
end
maxAngle = max(vAngles);
minAngle = min(vAngles);
meanAngle = mean(vAngles);
AngleStd = std(vAngles);
fprintf('v angle\n');
fprintf('Direction: [%.3f %.3f %.3f]^T. Angle: %.2fº\n',coneDir,coneAngle);
fprintf('Min: %.2fº. Max: %.2fº\n',minAngle,maxAngle);
fprintf('Mean: %.2fº\n',meanAngle);
fprintf('Standard Dev: %.2fº\n',AngleStd);
%% Plot
figure;
grid on;
rotate3d on;
axis equal;
axis vis3d;
axis tight;
hold on;
xlabel('X'); ylabel('Y'); zlabel('Z');
% Plot all vectors
p1 = [0 0 0]';
for i=1:N
p2 = vs(:,i);
plot3ex(p1,p2);
end
% Trying to plot the limiting cone, but no success here :(
% k = [0 1];
% [X,Y,Z] = cylinder([0 1 0]');
% testsubject = surf(X,Y,Z);
% set(testsubject,'FaceAlpha',0.5)
% N = 50;
% r = linspace(0, 1, N);
% [X,Y,Z] = cylinder(r, N);
%
% h = surf(X, Y, Z);
%
% rotate(h, [1 1 0], 90);
plot3ex.m:
function p = plot3ex(varargin)
% Plots a line from each p1 to each p2.
% Inputs:
% p1 3xN
% p2 3xN
% args plot3 configuration string
% NOTE: p1 and p2 number of points can range from 1 to N
% but if the number of points are different, one must be 1!
% PVB 2016
p1 = varargin{1};
p2 = varargin{2};
extraArgs = varargin(3:end);
N1 = size(p1,2);
N2 = size(p2,2);
N = N1;
if N1 == 1 && N2 > 1
N = N2;
elseif N1 > 1 && N2 == 1
N = N1
elseif N1 ~= N2
error('if size(p1,2) ~= size(p1,2): size(p1,2) and/or size(p1,2) must be 1 !');
end
for i=1:N
i1 = i;
i2 = i;
if i > N1
i1 = N1;
end
if i > N2
i2 = N2;
end
x = [p1(1,i1) p2(1,i2)];
y = [p1(2,i1) p2(2,i2)];
z = [p1(3,i1) p2(3,i2)];
p = plot3(x,y,z,extraArgs{:});
end
Here’s the solution. It’s based on the wonderful answer at https://math.stackexchange.com/a/205589/81266. I found this answer by googling “random points on spherical cap”, after I learned on Mathworld that a spherical cap is this cut of a 3-sphere with a plane.
Here’s the function:
function r = randSphericalCap(coneAngleDegree, coneDir, N, RNG)
if ~exist('coneDir', 'var') || isempty(coneDir)
coneDir = [0;0;1];
end
if ~exist('N', 'var') || isempty(N)
N = 1;
end
if ~exist('RNG', 'var') || isempty(RNG)
RNG = RandStream.getGlobalStream();
end
coneAngle = coneAngleDegree * pi/180;
% Generate points on the spherical cap around the north pole [1].
% [1] See https://math.stackexchange.com/a/205589/81266
z = RNG.rand(1, N) * (1 - cos(coneAngle)) + cos(coneAngle);
phi = RNG.rand(1, N) * 2 * pi;
x = sqrt(1-z.^2).*cos(phi);
y = sqrt(1-z.^2).*sin(phi);
% If the spherical cap is centered around the north pole, we're done.
if all(coneDir(:) == [0;0;1])
r = [x; y; z];
return;
end
% Find the rotation axis `u` and rotation angle `rot` [1]
u = normc(cross([0;0;1], normc(coneDir)));
rot = acos(dot(normc(coneDir), [0;0;1]));
% Convert rotation axis and angle to 3x3 rotation matrix [2]
% [2] See https://en.wikipedia.org/wiki/Rotation_matrix#Rotation_matrix_from_axis_and_angle
crossMatrix = #(x,y,z) [0 -z y; z 0 -x; -y x 0];
R = cos(rot) * eye(3) + sin(rot) * crossMatrix(u(1), u(2), u(3)) + (1-cos(rot))*(u * u');
% Rotate [x; y; z] from north pole to `coneDir`.
r = R * [x; y; z];
end
function y = normc(x)
y = bsxfun(#rdivide, x, sqrt(sum(x.^2)));
end
This code just implements joriki’s answer on math.stackexchange, filling in all the details that joriki omitted.
Here’s a script that shows how to use it.
clearvars
coneDir = [1;1;1];
coneAngleDegree = 30;
N = 1e4;
sol = randSphericalCap(coneAngleDegree, coneDir, N);
figure;plot3(sol(1,:), sol(2,:), sol(3,:), 'b.', 0,0,0,'rx');
grid
xlabel('x'); ylabel('y'); zlabel('z')
legend('random points','origin','location','best')
title('Final random points on spherical cap')
Here is a 3D plot of 10'000 points from the 30° spherical cap centered around the [1; 1; 1] vector:
Here’s 120° spherical cap:
Now, if you look at the histogram of the angles between these random points at the coneDir = [1;1;1], you will see that the distribution is skewed. Here’s the distribution:
Code to generate this:
normc = #(x) bsxfun(#rdivide, x, sqrt(sum(x.^2)));
mysubspace = #(a,b) real(acos(sum(bsxfun(#times, normc(a), normc(b)))));
angs = arrayfun(#(i) mysubspace(coneDir, sol(:,i)), 1:N) * 180/pi;
nBins = 16;
[n, edges] = histcounts(angs, nBins);
centers = diff(edges(1:2))*[0:(length(n)-1)] + mean(edges(1:2));
figure('color','white');
bar(centers, n);
xlabel('Angle (degrees)')
ylabel('Frequency')
title(sprintf('Histogram of angles between coneDir and random points: %d deg', coneAngleDegree))
Well, this makes sense! If you generate points from the 120° spherical cap around coneDir, of course the 1° cap is going to have very few of those samples, whereas the strip between the 10° and 11° caps will have far more points. So what we want to do is normalize the number of points at a given angle by the surface area of the spherical cap at that angle.
Here’s a function that gives us the surface area of the spherical cap with radius R and angle in radians theta (equation 16 on Mathworld’s spherical cap article):
rThetaToH = #(R, theta) R * (1 - cos(theta));
rThetaToS = #(R, theta) 2 * pi * R * rThetaToH(R, theta);
Then, we can normalize the histogram count for each bin (n above) by the difference in surface area of the spherical caps at the bin’s edges:
figure('color','white');
bar(centers, n ./ diff(rThetaToS(1, edges * pi/180)))
The figure:
This tells us “the number of random vectors divided by the surface area of the spherical segment between histogram bin edges”. This is uniform!
(N.B. If you do this normalized histogram for the vectors generated by your original code, using rejection sampling, the same holds: the normalized histogram is uniform. It’s just that rejection sampling is expensive compared to this.)
(N.B. 2: note that the naive way of picking random points on a sphere—by first generating azimuth/elevation angles and then converting these spherical coordinates to Cartesian coordinates—is no good because it bunches points near the poles: Mathworld, example, example 2. One way to pick points on the entire sphere is sampling from the 3D normal distribution: that way you won’t get bunching near poles. So I believe that your original technique is perfectly appropriate, giving you nice, evenly-distributed points on the sphere without any bunching. This algorithm described above also does the “right thing” and should avoid bunching. Carefully evaluate any proposed algorithms to ensure that the bunching-near-poles problem is avoided.)
it is better to use spherical coordinates and convert it to cartesian coordinates:
coneDirtheta = rand(1) * 2 * pi;
coneDirphi = rand(1) * pi;
coneAngle = 45;
N = 1000;
%perfom transformation preventing concentration of points around the pole
rpolar = acos(cos(coneAngle/2*pi/180) + (1-cos(coneAngle/2*pi/180)) * rand(N, 1));
thetapolar = rand(N,1) * 2 * pi;
x0 = rpolar .* cos(thetapolar);
y0 = rpolar .* sin(thetapolar);
theta = coneDirtheta + x0;
phi = coneDirphi + y0;
r = rand(N, 1);
x = r .* cos(theta) .* sin(phi);
y = r .* sin(theta) .* sin(phi);
z = r .* cos(phi);
scatter3(x,y,z)
if all points should be of length 1 set r = ones(N,1);
Edit:
since intersection of cone with sphere forms a circle first we create random points inside a circle with raduis of (45 / 2) in polar coordinates and as #Ahmed Fasih commented to prevent concentration of points near the pole we should first transform this random points, then convert polar to cartesian 2D coordinates to form x0 and y0
we can use x0 and y0 as phi & theta angle of spherical coordinates and add coneDirtheta & coneDirphi as offsets to these coordinates.
then convert spherical to cartesian 3D coordinates