我想在matlab中实现一个功能,我给定两个三维向量(不共线),首先先在3维图中画出这两个向量,再画...
Creato il: 8 febbraio 2026
Risposto usando GPT-5.2 Thinking da Chat01
Creato il: 8 febbraio 2026
Risposto usando GPT-5.2 Thinking da Chat01
我想在matlab中实现一个功能,我给定两个三维向量(不共线),首先先在3维图中画出这两个向量,再画出这两个向量所处在的平面,假设这两个向量令为v1,v2 (3*1的向量),我该怎么写程序?
下面给你一份可以直接跑的 MATLAB 示例:输入两个 3×1 的非共线向量 v1, v2,它会:
原理:平面就是
{ a*v1 + b*v2 | a,b ∈ ℝ }。用网格的a,b采样生成一片面。
matlab%% 输入:两个 3x1 向量(确保不共线) v1 = [1; 2; 1]; v2 = [2; -1; 1]; %% 基本检查 assert(all(size(v1)==[3 1]) && all(size(v2)==[3 1]), 'v1,v2 必须是 3x1 向量'); n = cross(v1, v2); assert(norm(n) > 1e-10, 'v1 和 v2 不能共线(叉积接近 0)'); %% 画向量 + 平面 figure; hold on; grid on; axis equal; xlabel('X'); ylabel('Y'); zlabel('Z'); title('Vectors v1, v2 and the plane they span'); % 1) 画两个向量(从原点出发) quiver3(0,0,0, v1(1),v1(2),v1(3), 0, 'LineWidth',2); quiver3(0,0,0, v2(1),v2(2),v2(3), 0, 'LineWidth',2); % 标注向量端点 text(v1(1),v1(2),v1(3), ' v1', 'FontSize',12); text(v2(1),v2(2),v2(3), ' v2', 'FontSize',12); % 2) 生成平面上的点:p = a*v1 + b*v2 % 面片大小:用向量长度决定一个合适尺度 L = max([norm(v1), norm(v2)]); s = 1.2 * L; % 你也可以手动改大/改小 t = linspace(-1, 1, 25); % 网格密度(越大越细) [A,B] = meshgrid(t, t); X = (A*v1(1) + B*v2(1)) * s; Y = (A*v1(2) + B*v2(2)) * s; Z = (A*v1(3) + B*v2(3)) * s; % 画平面(半透明) surf(X, Y, Z, ... 'FaceAlpha',0.25, ... 'EdgeAlpha',0.15); % 3) 画坐标轴参考线(可选) m = 1.5 * s; plot3([0 m],[0 0],[0 0],'k:'); % x轴方向虚线参考 plot3([0 0],[0 m],[0 0],'k:'); % y轴 plot3([0 0],[0 0],[0 m],'k:'); % z轴 % 视角与范围 view(45, 25); xlim([-m m]); ylim([-m m]); zlim([-m m]); legend({'v1','v2','span(v1,v2) plane'}, 'Location','best'); hold off;
1)平面不是过原点,而是过某个点 p0:
把平面点改成 p = p0 + a*v1 + b*v2,例如:
matlabp0 = [1; 0; 2]; X = p0(1) + (A*v1(1) + B*v2(1)) * s; Y = p0(2) + (A*v1(2) + B*v2(2)) * s; Z = p0(3) + (A*v1(3) + B*v2(3)) * s;
2)让平面范围“更贴合”两向量而不是对称方形:
可以让 A,B 的范围不一样,或让 s 用你想要的尺寸。
如果你把 v1,v2 的具体数值发我(或者你希望平面显示多大、是否要显示法向量),我也可以把图做得更“论文风”(比如加法向量 n=cross(v1,v2)、加上平面方程等)。
我加入了你的内容,得到了很好的效果,这是我如下的代码:
clear all
clc
m(1)=3;
m(2)=1;
m(3)=0.8;
nn=1;
ee=1;
tau=1;
hbar=1;
a=1;
b=0;
c=1;
a1=a/sqrt(a^2+b^2+c^2);
b1=b/sqrt(a^2+b^2+c^2);
c1=c/sqrt(a^2+b^2+c^2);
Theta=acos(c1);
if c1==1
Phi=0;
elseif b1>0
Phi=acos(a1/sin(Theta));
else
Phi=2*pi-acos(a1/sin(Theta));
end
A=[cos(Theta)*cos(Phi),-sin(Phi),sin(Theta)*cos(Phi);cos(Theta)*sin(Phi),cos(Phi),sin(Theta)*sin(Phi);-sin(Theta),0,cos(Theta)];
mmup=zeros(3,3);
mmdn=zeros(3,3);
mmup(1,1)=(1/m(1)+1/m(2))/2;
mmup(2,2)=(1/m(1)+1/m(2))/2;
mmup(1,2)=(1/m(1)-1/m(2))/2;
mmup(2,1)=(1/m(1)-1/m(2))/2;
mmup(3,3)=1/m(3);
mmdn=mmup;
mmdn(1,2)=(1/m(2)-1/m(1))/2;
mmdn(2,1)=(1/m(2)-1/m(1))/2;
sigma_c=nnee^2tau*(mmup+mmdn);
sigma_s=nnee^2tau*(mmup-mmdn);
phi=linspace(0,2pi,1000);
n=length(phi);
theta=pi/2ones(1,n);
E=zeros(3,n);
Jc=zeros(3,n);
Js=zeros(3,n);
v1=3A[1;0;0];
v2=3A[0;1;0];
for i=1:n
E(:,i)=[sin(theta(i))*cos(phi(i));sin(theta(i))*sin(phi(i));cos(theta(i))];
textJc(:,i)=sigma_c*A*E(:,i); Js(:,i)=sigma_s*A*E(:,i); Js1(:,i)=Js(:,i)-dot(Js(:,i),Jc(:,i))*Jc(:,i)/norm(Jc(:,i))^2; Jcc(i)=norm(Jc(:,i)); Jss(i)=norm(Js(:,i)); Jss1(i)=norm(Js1(:,i));
end
figure
plot(phi,Jss1,'LineWidth',2);
figure
x = -3:0.05:3;
y = -3:0.05:3;
z = -3:0.05:3;
[X, Y, Z] = meshgrid(x, y, z);
E1 = hbar^2/2*(mmup(1,1)*X.^2+mmup(2,2)Y.^2+2mmup(1,2)*X.*Y+mmup(3,3)Z.^2);
E2 = hbar^2/2(mmup(1,1)*X.^2+mmup(2,2)Y.^2-2mmup(1,2)*X.*Y+mmup(3,3)*Z.^2);
h1 = patch(isosurface(X, Y, Z, E1, 1));
isonormals(X, Y, Z, E1, h1);
hold on
h2 = patch(isosurface(X, Y, Z, E2, 1));
isonormals(X, Y, Z, E2, h2);
assert(all(size(v1)==[3 1]) && all(size(v2)==[3 1]), 'v1,v2 必须是 3x1 向量');
n = cross(v1, v2);
assert(norm(n) > 1e-10, 'v1 和 v2 不能共线(叉积接近 0)');
grid on; axis equal;
xlabel('X'); ylabel('Y'); zlabel('Z');
title('Vectors v1, v2 and the plane they span');
% 1) 画两个向量(从原点出发)
quiver3(0,0,0, v1(1),v1(2),v1(3), 0, 'LineWidth',2);
quiver3(0,0,0, v2(1),v2(2),v2(3), 0, 'LineWidth',2);
% 标注向量端点
text(v1(1),v1(2),v1(3), ' v1', 'FontSize',12);
text(v2(1),v2(2),v2(3), ' v2', 'FontSize',12);
% 2) 生成平面上的点:p = av1 + bv2
% 面片大小:用向量长度决定一个合适尺度
L = max([norm(v1), norm(v2)]);
s = 1.2 * L; % 你也可以手动改大/改小
t = linspace(-1, 1, 25); % 网格密度(越大越细)
[A1,B1] = meshgrid(t, t);
X = (A1v1(1) + B1v2(1)) * s;
Y = (A1v1(2) + B1v2(2)) * s;
Z = (A1v1(3) + B1v2(3)) * s;
% 画平面(半透明)
surf(X, Y, Z, ...
'FaceAlpha',0.25, ...
'EdgeAlpha',0.15);
% 3) 画坐标轴参考线(可选)
m = 1.5 * s;
plot3([0 m],[0 0],[0 0],'k:'); % x轴方向虚线参考
plot3([0 0],[0 m],[0 0],'k:'); % y轴
plot3([0 0],[0 0],[0 m],'k:'); % z轴
% 设置图像属性
h1.FaceColor = [0 0 1];
h1.EdgeColor = 'none';
h2.FaceColor = [1 0 0];
h2.EdgeColor = 'none';
alpha(1);
view([1, 1, 1]);
axis equal;
% axis off;
camlight('right');
lighting gouraud;
xlabel('x'); ylabel('y'); zlabel('z');
hold off;
但我想在此基础上更进一步,我想再做一张图,这张图是图2的切面图。(这个体系的背景是算RuO2这个交错磁体的能带,你注意到我使用了各向异性电子气体模型,图二画了RuO2的费米面和所切割的晶面,我想看这个图的切面图,画到第三个图上即可)
可以的。你现在图2里画的是两张等能面(E1=1、E2=1)+ 由 v1,v2 张成的平面。你要的“切面图”最常见的理解就是:
把 3D 等能面限制到该平面上,在平面内画出
E1=1、E2=1的交线(在 2D 平面坐标里就是两条闭合曲线/截线)。
下面这段代码直接接在你图2代码后面(v1,v2,mmup,hbar 都已经有了)就能生成图3:切面截线图。
matlab%% ===== Figure 3: Cut (cross-section) of the Fermi surfaces by plane span(v1,v2) ===== box = 3; % 你图2里 meshgrid 的范围是 -3~3,这里保持一致 Eiso = 1; % 等能面取值(你图2里 isosurface 用的是 1) % 1) 构造平面内的正交单位基 e1,e2(e1沿v1,e2在平面内且与e1正交) e1 = v1 / norm(v1); tmp = v2 - dot(v2,e1)*e1; e2 = tmp / norm(tmp); % e3 = cross(e1,e2); % 如果你想要法向量可用这个 % 2) 为了让切面覆盖你 3D 盒子 [-box,box]^3,把盒子 8 个角点投影到 (u,v) 得到范围 corners = box * [ -1 -1 -1; -1 -1 1; -1 1 -1; -1 1 1; 1 -1 -1; 1 -1 1; 1 1 -1; 1 1 1 ]'; u_c = e1.' * corners; % 1x8 v_c = e2.' * corners; % 1x8 u_min = min(u_c); u_max = max(u_c); v_min = min(v_c); v_max = max(v_c); % 3) 在平面内建立 2D 网格 (U,V),映射回 3D 坐标 (Xp,Yp,Zp) Nu = 700; Nv = 700; % 分辨率(想更细就调大) [U,V] = meshgrid(linspace(u_min,u_max,Nu), linspace(v_min,v_max,Nv)); Xp = e1(1)*U + e2(1)*V; Yp = e1(2)*U + e2(2)*V; Zp = e1(3)*U + e2(3)*V; % 可选:只保留落在你原来 3D box 内的点(避免图上出现“盒子外”的无关区域) mask = abs(Xp)<=box & abs(Yp)<=box & abs(Zp)<=box; Xp(~mask) = NaN; Yp(~mask) = NaN; Zp(~mask) = NaN; % 4) 直接用解析式在切面上算能量(比从 3D 网格插值更干净) E1_cut = hbar^2/2*( mmup(1,1)*Xp.^2 + mmup(2,2)*Yp.^2 + 2*mmup(1,2)*Xp.*Yp + mmup(3,3)*Zp.^2 ); E2_cut = hbar^2/2*( mmup(1,1)*Xp.^2 + mmup(2,2)*Yp.^2 - 2*mmup(1,2)*Xp.*Yp + mmup(3,3)*Zp.^2 ); % 5) 画切面截线:E1=Eiso 与 E2=Eiso figure; hold on; grid on; axis equal; [C1,hc1] = contour(U, V, E1_cut, [Eiso Eiso], 'LineWidth', 2); [C2,hc2] = contour(U, V, E2_cut, [Eiso Eiso], 'LineWidth', 2, 'LineStyle','--'); xlabel('u (along v1)'); ylabel('v (in-plane, orthogonalized from v2)'); title('Cross-section on plane span(v1,v2): E1=1 and E2=1'); legend([hc1 hc2], {'E1=1 cut','E2=1 cut'}, 'Location','best');
你前面 m 既当了质量数组 m(1)=3...,后面又写了 m = 1.5*s;(标尺),这会把质量数组覆盖掉。
同理你也把 n=length(phi) 后面又 n=cross(v1,v2) 覆盖了。
建议你把质量改名,例如:
m → massn(length)→ nphin(法向量)→ nvec这样后面扩展会省很多麻烦。
你如果想把图3算出来的截线再映射回 3D,并叠加到图2的 3D 画面里,我也可以给你一段把 contour 输出 C1/C2 解析成曲线点,再 plot3 回去的代码(这样能直观看交线是不是就在你那块平面上)。
只要你告诉我:你希望交线也叠加在图2上,还是只要图3即可。
好了,你能帮我把最后两条线一个改为蓝色,一个改为红色吗
可以,contour 返回的句柄 hc1 / hc2 直接改颜色就行。把你图3里画两条线那几行改成下面这样(我也顺手把线型保留成实线/虚线方便区分):
matlab% 5) 画切面截线:E1=Eiso 与 E2=Eiso figure; hold on; grid on; axis equal; [C1,hc1] = contour(U, V, E1_cut, [Eiso Eiso], 'LineWidth', 2); hc1.LineColor = 'b'; % 蓝色 [C2,hc2] = contour(U, V, E2_cut, [Eiso Eiso], 'LineWidth', 2, 'LineStyle','--'); hc2.LineColor = 'r'; % 红色 xlabel('u (along v1)'); ylabel('v (in-plane, orthogonalized from v2)'); title('Cross-section on plane span(v1,v2): E1=1 and E2=1'); legend([hc1 hc2], {'E1=1 cut','E2=1 cut'}, 'Location','best');
如果你想两条都是实线,只要把第二条里的 'LineStyle','--' 删掉即可。