lmax = 4 alm = np.zeros((lmax * (lmax + 2), )) blm = np.zeros((lmax * (lmax + 2), )) # Set one specific component to one blm[16] += 1 sphfield = sphtools.field(target_points, alm, blm, lmax) target_field = sphfield / np.max(sphfield[:, 0]) coil.plot_mesh(opacity=0.2) mlab.quiver3d(*target_points.T, *sphfield.T) target_spec = { "coupling": coil.B_coupling(target_points), "abs_error": 0.1, "target": target_field, } #%% # Run QP solver import mosek coil.s, prob = optimize_streamfunctions( coil, [target_spec], objective="minimum_inductive_energy", solver="MOSEK", solver_opts={"mosek_params": { mosek.iparam.num_threads: 8
figure=f, magnification=4, ) mlab.close() #%% # Create bfield specifications used when optimizing the coil geometry # The absolute target field amplitude is not of importance, # and it is scaled to match the C matrix in the optimization function target_field = np.zeros(target_points.shape) target_field[:, 0] += 1 # Homogeneous field on X-axis target_spec = { "coupling": coil.B_coupling(target_points), "abs_error": 0.005, "target": target_field, } stray_spec = { "coupling": coil.B_coupling(stray_points), "abs_error": 0.01, "target": np.zeros((n_stray_points, 3)), } bfield_specification = [target_spec, stray_spec] #%% # Run QP solver import mosek
fgcolor=(0.5, 0.5, 0.5), size=(800, 800)) coil.s.plot(figure=f, contours=20) shieldcoil.s.plot(figure=f, contours=20) #%% # Compute the field and scalar potential on an XY-plane x = y = np.linspace(-8, 8, 150) X, Y = np.meshgrid(x, y, indexing="ij") points = np.zeros((X.flatten().shape[0], 3)) points[:, 0] = X.flatten() points[:, 1] = Y.flatten() CB1 = coil.B_coupling(points) CB2 = shieldcoil.B_coupling(points) CU1 = coil.U_coupling(points) CU2 = shieldcoil.U_coupling(points) B1 = CB1 @ coil.s B2 = CB2 @ shieldcoil.s U1 = CU1 @ coil.s U2 = CU2 @ shieldcoil.s #%% # Now, plot the field streamlines and scalar potential from bfieldtools.contour import scalar_contour
mesh = data["mesh"] p = data["p"] n = data["n"] mesh = trimesh.Trimesh(vertices=data["vertices"], faces=data["faces"]) evoked = mne.Evoked(SAVE_DIR + "left_auditory-ave.fif") #%% # Fit the surface current for the auditory evoked response c = MeshConductor(mesh_obj=mesh, basis_name="suh", N_suh=150) M = c.mass sensor_coupling = np.einsum("ijk,ij->ik", c.B_coupling(p), n) # a = np.linalg.pinv(sensor_coupling, rcond=1e-15) @ field ss = np.linalg.svd(sensor_coupling @ sensor_coupling.T, False, False) # reg_exps = [0.5, 1, 2, 3, 4, 5, 6, 7, 8] reg_exps = [1] rel_errors = [] for reg_exp in reg_exps: _lambda = np.max(ss) * (10 ** (-reg_exp)) # Laplacian in the suh basis is diagonal BB = sensor_coupling.T @ sensor_coupling + _lambda * (-c.laplacian) / np.max( abs(c.laplacian) ) a = np.linalg.solve(BB, sensor_coupling.T @ field) s = StreamFunction(a, c)
# Use lines below to get coulings with different normalization # from bfieldtools.sphtools import compute_sphcoeffs_mesh # A1, Beta1 = compute_sphcoeffs_mesh(mesh1, 5, normalization='energy', R=1) # A2, Beta2 = compute_sphcoeffs_mesh(mesh2, 5, normalization='energy', R=1) # Beta1 = Beta1[:, coil1.inner_vertices] # Beta2 = Beta2[:, coil2.inner_vertices] x = y = np.linspace(-0.8, 0.8, 50) # 150) X, Y = np.meshgrid(x, y, indexing="ij") points = np.zeros((X.flatten().shape[0], 3)) points[:, 0] = X.flatten() points[:, 1] = Y.flatten() CB1 = coil1.B_coupling(points) CB2 = coil2.B_coupling(points) CU1 = coil1.U_coupling(points) CU2 = coil2.U_coupling(points) #%% Precalculations for the solution # alpha[15] = 1 # Minimization of magnetic energy with spherical harmonic constraint C = Beta1 + Beta2 @ P M = M11 + M21.T @ P from scipy.linalg import eigvalsh ssmax = eigvalsh(C.T @ C, M, eigvals=[M.shape[1] - 1, M.shape[1] - 1])
# c = MeshConductor(mesh_obj=mesh, basis_name="suh", N_suh=35) # M = c.mass # B_sensors = np.einsum("ijk,ij->ik", c.B_coupling(p), n) # # # asuh = np.linalg.pinv(B_sensors, rcond=1e-15) @ field # # s = StreamFunction(asuh, c) # b_filt = B_sensors @ s #%% Suh fit c = MeshConductor(mesh_obj=mesh, basis_name="suh", N_suh=150) M = c.mass B_sensors = np.einsum("ijk,ij->ik", c.B_coupling(p), n) ss = np.linalg.svd(B_sensors @ B_sensors.T, False, False) reg_exp = 1 plot_this = True rel_errors = [] _lambda = np.max(ss) * (10**(-reg_exp)) # Laplacian in the suh basis is diagonal BB = B_sensors.T @ B_sensors + _lambda * (-c.laplacian) / np.max( abs(c.laplacian)) a = np.linalg.solve(BB, B_sensors.T @ field) s = StreamFunction(a, c) reco_suh = B_sensors @ s
fgcolor=(0.5, 0.5, 0.5), size=(800, 800)) coil.plot_mesh(figure=f, opacity=0.2) shield.plot_mesh(figure=f, opacity=0.2) mlab.points3d(*target_points.T) #%% # Compute C matrices that are used to compute the generated magnetic field mutual_inductance = coil.mutual_inductance(shield) # Take into account the field produced by currents induced into the shield # NB! This expression is for instantaneous step-function switching of coil current, see Eq. 18 in G.N. Peeren, 2003. shield.M_coupling = np.linalg.solve(-shield.inductance, mutual_inductance.T) secondary_C = shield.B_coupling(target_points) @ -shield.M_coupling #%% # Create bfield specifications used when optimizing the coil geometry # The absolute target field amplitude is not of importance, # and it is scaled to match the C matrix in the optimization function target_field = np.zeros(target_points.shape) target_field[:, 1] = target_field[:, 1] + 1 target_spec = { "coupling": coil.B_coupling(target_points), "abs_error": 0.01, "target": target_field, }
f.scene.camera.zoom(1.1) #%% # Let's design a coil without taking the magnetic shield into account # The absolute target field amplitude is not of importance, # and it is scaled to match the C matrix in the optimization function target_field = np.zeros(target_points.shape) target_field[:, 0] = target_field[:, 0] + 1 # Homogeneous Y-field target_abs_error = np.zeros_like(target_field) target_abs_error[:, 0] += 0.005 target_abs_error[:, 1:3] += 0.01 target_spec = { "coupling": coil.B_coupling(target_points), "rel_error": 0, "abs_error": target_abs_error, "target": target_field, } import mosek coil.s, coil.prob = optimize_streamfunctions( coil, [target_spec], objective="minimum_inductive_energy", solver="MOSEK", solver_opts={"mosek_params": { mosek.iparam.num_threads: 8 }},