使用Moco工具生成人体蹲起运动并分析辅助器械作用

本文主要是介绍使用Moco工具生成人体蹲起运动并分析辅助器械作用,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

1. 思路和解释

2. 代码逻辑

3. 代码注释

4. 关节扭矩驱动与肌肉驱动的模型处理方法

1. 思路和解释

Moco可以通过轨迹优化生成预测的运动,并用来进行优化模型参数。本篇文章以蹲起运动为例子进行说明。优化目标为最小化肌肉激活度平方和(权重:1.0)与动作持续时间(权重:1.0)。初始状态被设定为蹲姿[74],最终状态被设定为直立站姿。没有使用动捕的运动数据。该模型包含了躯干和9块肌肉驱动的单右腿,其中6块肌肉设置有顺应性肌腱动力学(腘绳肌、股直肌、股外侧肌、腓肠肌、比目鱼肌和胫骨前肌)。为了简化将模拟双腿合为一腿,力量加倍。足部与地面设定为焊接接触,进行了简化。模型中包含了先前mocoInverse相同的髌骨的运动学约束,初始猜测值是变量界限的中点,肌肉激励和激活的初始猜测值是0.05。起立过程中,臀大肌、腘绳肌和股外侧肌等伸肌表现出了显著的活动性。

关节扭矩驱动与肌肉驱动的模型处理方法中,关节扭矩驱动会移除模型中的肌肉并添加致动器,肌肉驱动中,会对肌肉参数进行配置。

2. 代码逻辑

study(study.solve)_关节扭矩驱动的轨迹优化,或者说是运动预测

1. 导入.osim肌肉骨骼模型,创建MocoStudy和problem

2. 设置状态量和时间的边界条件,addGoal设置最小力为cost

3. 配置solver参数

4. study.solve()求解结果,并.write保存.sto运动轨迹数据predictSolution.sto,包含以下关节角度和速度状态量等条目/jointset/ankle_r/ankle_angle_r/value    /jointset/knee_r/knee_angle_r/value    /jointset/patellofemoral_r/knee_angle_r_beta/value    /jointset/hip_r/hip_flexion_r/value    /jointset/ankle_r/ankle_angle_r/speed    /jointset/knee_r/knee_angle_r/speed    /jointset/patellofemoral_r/knee_angle_r_beta/speed    /jointset/hip_r/hip_flexion_r/speed    /tau_hip_flexion_r    /tau_knee_angle_r    /tau_ankle_angle_r    lambda_cid4_p0    gamma_cid4_p0

track(MocoStateTrackingGoal)_关节扭矩驱动的追踪问题,以上面生成运动轨迹为参考

1.TableProcessor加载predictSolution.sto数据并滤波

2. MocoStateTrackingGoal载入TableProcessor数据并添加到addGoal,.setWeight设置cost项的权重

3. 配置study的solver,使用setGuessFile()载入生成的predictSolution.sto运动轨迹数据,作为初始猜测值,生成trackingSolution.sto数据。包含条目与predictSolution相同,都是关节坐标状态。

inverse(.MocoInverse)_肌肉驱动的逆动力问题,求解肌肉力量

1. 创建MocoInverse实例化

2. ModelProcessor加载模型,模型的自由度提供额外的驱动力,并加载到inverse中

3. setKinematics加载TableProcessor 作为运动参考

4. 配置inverse时间点,网格数等边界条件,以及肌肉激活度为目标

5. solve,并将运动数据保存到inverseSolution.sto中,包含以下条目内容# activation,# normalized_tendon_force,# joint angle,joint speed,# muscle force,reserve jointset force,# implicitderiv_normalized_tendon_force,包含状态量,tendon_force,muscle_force。inverseSolution.sto条目如下

/forceset/bifemsh_r/activation    /forceset/bifemsh_r/normalized_tendon_force    /forceset/med_gas_r/activation    /forceset/med_gas_r/normalized_tendon_force    /forceset/glut_max2_r/activation    /forceset/glut_max2_r/normalized_tendon_force    /forceset/psoas_r/activation    /forceset/psoas_r/normalized_tendon_force    /forceset/rect_fem_r/activation    /forceset/rect_fem_r/normalized_tendon_force    /forceset/semimem_r/activation    /forceset/semimem_r/normalized_tendon_force    /forceset/soleus_r/activation    /forceset/soleus_r/normalized_tendon_force    /forceset/tib_ant_r/activation    /forceset/tib_ant_r/normalized_tendon_force    /forceset/vas_int_r/activation    /forceset/vas_int_r/normalized_tendon_force    /jointset/ankle_r/ankle_angle_r/value    /jointset/ankle_r/ankle_angle_r/speed    /jointset/knee_r/knee_angle_r/value    /jointset/knee_r/knee_angle_r/speed    /jointset/patellofemoral_r/knee_angle_r_beta/value    /jointset/patellofemoral_r/knee_angle_r_beta/speed    /jointset/hip_r/hip_flexion_r/value    /jointset/hip_r/hip_flexion_r/speed    /forceset/bifemsh_r    /forceset/med_gas_r    /forceset/glut_max2_r    /forceset/psoas_r    /forceset/rect_fem_r    /forceset/semimem_r    /forceset/soleus_r    /forceset/tib_ant_r    /forceset/vas_int_r    /forceset/reserve_jointset_knee_r_knee_angle_r    /forceset/reserve_jointset_ankle_r_ankle_angle_r    /forceset/reserve_jointset_hip_r_hip_flexion_r    lambda_cid4_p0    /forceset/bifemsh_r/implicitderiv_normalized_tendon_force    /forceset/med_gas_r/implicitderiv_normalized_tendon_force    /forceset/glut_max2_r/implicitderiv_normalized_tendon_force    /forceset/psoas_r/implicitderiv_normalized_tendon_force    /forceset/rect_fem_r/implicitderiv_normalized_tendon_force    /forceset/semimem_r/implicitderiv_normalized_tendon_force    /forceset/soleus_r/implicitderiv_normalized_tendon_force    /forceset/tib_ant_r/implicitderiv_normalized_tendon_force    /forceset/vas_int_r/implicitderiv_normalized_tendon_force

6. 使用STOFileAdapter工具,将inverseSolution导出到muscleOutputs.sto。muscleOutputs.sto文件包含以下每条肌肉的fiber_length和passive_force条目,单纯与肌肉相关。

/forceset/bifemsh_r|normalized_fiber_length    /forceset/bifemsh_r|passive_force_multiplier    /forceset/med_gas_r|normalized_fiber_length    /forceset/med_gas_r|passive_force_multiplier    /forceset/glut_max2_r|normalized_fiber_length    /forceset/glut_max2_r|passive_force_multiplier    /forceset/psoas_r|normalized_fiber_length    /forceset/psoas_r|passive_force_multiplier    /forceset/rect_fem_r|normalized_fiber_length    /forceset/rect_fem_r|passive_force_multiplier    /forceset/semimem_r|normalized_fiber_length    /forceset/semimem_r|passive_force_multiplier    /forceset/soleus_r|normalized_fiber_length    /forceset/soleus_r|passive_force_multiplier    /forceset/tib_ant_r|normalized_fiber_length    /forceset/tib_ant_r|passive_force_multiplier    /forceset/vas_int_r|normalized_fiber_length    /forceset/vas_int_r|passive_force_multiplier

inverse_器械辅助下的肌肉驱动逆问题,求解器械辅助力

主要是修改模型,在膝盖坐标添加一个SpringGeneralizedForce弹簧阻尼模型。

1. 在knee_angle_r关节添弹簧元件,并添加到模型中

2. 模型中添加1个reserve actuators

3. inverse.solve求解,并保存inverseDeviceSolution.sto运动数据结果

4. getObjective获取最终cost,并画图,inverseSolution对比inverseDeviceSolution,观察肌肉激活度,肌腱力tendon_force的对比

/forceset/bifemsh_r/activation    /forceset/bifemsh_r/normalized_tendon_force    /forceset/med_gas_r/activation    /forceset/med_gas_r/normalized_tendon_force    /forceset/glut_max2_r/activation    /forceset/glut_max2_r/normalized_tendon_force    /forceset/psoas_r/activation    /forceset/psoas_r/normalized_tendon_force    /forceset/rect_fem_r/activation    /forceset/rect_fem_r/normalized_tendon_force    /forceset/semimem_r/activation    /forceset/semimem_r/normalized_tendon_force    /forceset/soleus_r/activation    /forceset/soleus_r/normalized_tendon_force    /forceset/tib_ant_r/activation    /forceset/tib_ant_r/normalized_tendon_force    /forceset/vas_int_r/activation    /forceset/vas_int_r/normalized_tendon_force    /jointset/ankle_r/ankle_angle_r/value    /jointset/ankle_r/ankle_angle_r/speed    /jointset/knee_r/knee_angle_r/value    /jointset/knee_r/knee_angle_r/speed    /jointset/patellofemoral_r/knee_angle_r_beta/value    /jointset/patellofemoral_r/knee_angle_r_beta/speed    /jointset/hip_r/hip_flexion_r/value    /jointset/hip_r/hip_flexion_r/speed    /forceset/bifemsh_r    /forceset/med_gas_r    /forceset/glut_max2_r    /forceset/psoas_r    /forceset/rect_fem_r    /forceset/semimem_r    /forceset/soleus_r    /forceset/tib_ant_r    /forceset/vas_int_r    /forceset/reserve_jointset_knee_r_knee_angle_r    /forceset/reserve_jointset_ankle_r_ankle_angle_r    /forceset/reserve_jointset_hip_r_hip_flexion_r    lambda_cid4_p0    /forceset/bifemsh_r/implicitderiv_normalized_tendon_force    /forceset/med_gas_r/implicitderiv_normalized_tendon_force    /forceset/glut_max2_r/implicitderiv_normalized_tendon_force    /forceset/psoas_r/implicitderiv_normalized_tendon_force    /forceset/rect_fem_r/implicitderiv_normalized_tendon_force    /forceset/semimem_r/implicitderiv_normalized_tendon_force    /forceset/soleus_r/implicitderiv_normalized_tendon_force    /forceset/tib_ant_r/implicitderiv_normalized_tendon_force    /forceset/vas_int_r/implicitderiv_normalized_tendon_force

# 第0部分:加载Moco库和opensim内置模型
import opensim as osim
import exampleSquatToStand_helpers as helpers
import mocoPlotTrajectory as plot
import os
import numpy as np
# 导入扭矩驱动模型和肌肉驱动模型
torqueDrivenModel = helpers.getTorqueDrivenModel()
muscleDrivenModel = helpers.getMuscleDrivenModel()## Part 1: 求解关节扭矩驱动的预测问题,即由起始位置生成中间运动
# Part 1a: 创建MocoStudy类
study = osim.MocoStudy()# Part 1b: 获取problem引用并加载模型
problem = study.updProblem()
problem.setModel(torqueDrivenModel)# Part 1c: 边界设置
#
# 时间边界输入参数格式problem.setTimeBounds(initial_bounds, final_bounds)
# 状态量边界输出参数格式problem.setStateInfo(path, trajectory_bounds, inital_bounds, final_bounds)
#
# 所有边界参数可以设置为一个范围, [lower upper]; 或一个数值,表示上下界相等,或空的符号[],表示默认值;
# 可以同时设置多个状态setStateInfoPattern(),格式如下:
# problem.setStateInfoPattern(pattern, trajectory_bounds, inital_bounds, ...
#       final_bounds)
#
# setStateInfoPattern函数支持“pattern”参数中的正则表达式;
# 使用'.*'匹配状态/控制路径的任何子字符串,例如,以下将设置所有坐标值状态信息:
# problem.setStateInfoPattern('/path/to/states/.*/value', ...)# 时间边界设置[0, 1],1秒之内从蹲到站起
problem.setTimeBounds(0, 1)# 位置约束: 模型需要从蹲姿开始并以站姿结束
# 设定了了三个关节角度,
# 髋关节屈曲角度,膝关节角度,踝关节角度
# 关节角度上下界,初始位置上下界,和结束位置的上下界
# 髋关节屈曲角度,关节角度上下界[-114.59°, 28.65°],初始值-114.59°,结束0°
problem.setStateInfo('/jointset/hip_r/hip_flexion_r/value', [-2, 0.5], -2, 0)
problem.setStateInfo('/jointset/knee_r/knee_angle_r/value', [-2, 0], -2, 0)
problem.setStateInfo('/jointset/ankle_r/ankle_angle_r/value', [-0.5, 0.7], -0.5, -0.1)# 速度界限:所有坐标 在开始和结束是都是静止
problem.setStateInfoPattern('/jointset/.*/speed', [], 0, 0)# 添加控制量作为cost项,命名为myeffort
problem.addGoal(osim.MocoControlGoal('myeffort'))# 配置求解器
# 前两行是必须的
solver = study.initCasADiSolver()
solver.set_num_mesh_intervals(25)
# 后面的选择项,可以不设置
solver.set_optim_convergence_tolerance(1e-4)
solver.set_optim_constraint_tolerance(1e-4)# 如果'predictSolution.sto'这个文件不存在,执行求解并保存新的
if not os.path.isfile('predictSolution.sto'):# Part 1f: Solve! Write the solution to file, and visualize.predictSolution = study.solve()predictSolution.write('predictSolution.sto')# study.visualize(predictSolution)## Part 2: 扭矩驱动的追踪问题,即给出运动轨迹参考
# 使用上述预测结果,使用TableProcessor加载数据,并低通滤波
# 将滤波数据,追加到tableProcessor中
tableProcessor = osim.TableProcessor('predictSolution.sto')
tableProcessor.append(osim.TabOpLowPassFilter(6))# 使用MocoStateTrackingGoal将状态量作为Cost
# 生成的预测的TableProcessor作为参考轨迹
# 启用setAllowUnusedReference忽略不需要的列数据
tracking = osim.MocoStateTrackingGoal()
tracking.setName('mytracking')
tracking.setReference(tableProcessor)
tracking.setAllowUnusedReferences(True)
problem.addGoal(tracking)# Part 2c: 使用track时,为了追踪轨迹的误差更小,一般会减小控制量惩罚项的权重
problem.updGoal('myeffort').setWeight(0.001)# Part 2d: 使用predictSolution.sto作为初始猜测值
solver.setGuessFile('predictSolution.sto')
# 减小收敛公差,以确保平稳控制。
solver.set_optim_convergence_tolerance(1e-6)# 如果'trackingSolution.sto'这个文件不存在,执行求解并保存新的
if not os.path.isfile('trackingSolution.sto'):# Part 2e: Solve! Write the solution to file, and visualize.trackingSolution = study.solve()trackingSolution.write('trackingSolution.sto')# study.visualize(trackingSolution)## Part 3: 对比 Predictive与Tracking结果
# 使用绘图函数mocoPlotTrajectory.m,加载.sto运动数据文件
plot.mocoPlotTrajectory('predictSolution.sto', 'trackingSolution.sto', 'predict', 'track')## Part 4: 肌肉驱动的逆动力问题,求解肌肉力量
# MocoInverse实例化
inverse = osim.MocoInverse()# 使用ModelProcessor加载.osim肌肉骨骼模型,可以通过.append操作符来修改模型
modelProcessor = osim.ModelProcessor(muscleDrivenModel)
# 将备用执行器添加到模型中,给模型的自由度提供额外的驱动力或控制
# 添加model,operation,AddReserves
# 2为optimalForce,该自由度最大的力
modelProcessor.append(osim.ModOpAddReserves(2))
# 将配置完成的模型选项给到MocoInverse实例中	
inverse.setModel(modelProcessor)# 使用TableProcessor 作为运动参考
inverse.setKinematics(tableProcessor)# Part 4c: Set the time range, mesh interval, and convergence tolerance.
# 初始时间0s,终止时间1s,间隔为0.05s.
inverse.set_initial_time(0)
inverse.set_final_time(1)
inverse.set_mesh_interval(0.05)
#后面两行可以不设置
inverse.set_convergence_tolerance(1e-4)
inverse.set_constraint_tolerance(1e-4)# 默认情况下,运动学数据包含额外的列,Moco会报错。
# 在这里,告诉Moco允许(并忽略)这些额外的列。
inverse.set_kinematics_allow_extra_columns(True)
# 设置肌肉激活程度最小
inverse.set_minimize_sum_squared_activations(True)# 设定特定肌肉结果的关键字属性,设置muscleOutputs.sto文件的表头
inverse.append_output_paths('.*normalized_fiber_length')
inverse.append_output_paths('.*passive_force_multiplier')# Part 4d: 求解! 将结果进行保存到 inverseSolution.sto文件中
# 内容是如下,每列个表头为一列数据
# activation,
# normalized_tendon_force,
# joint angle,joint speed,
# muscle force,reserve jointset force, 
# implicitderiv_normalized_tendon_force
inverseSolution = inverse.solve()
solution = inverseSolution.getMocoSolution()
solution.write('inverseSolution.sto')# Part 4e: 将inverse结果写入到 muscleOutputs.sto中
# 内容是每个肌肉的fiber_length和passive_force_multiplier
inverseOutputs = inverseSolution.getOutputs()
sto = osim.STOFileAdapter()
sto.write(inverseOutputs, 'muscleOutputs.sto')## Part 5: 器械辅助下的肌肉驱动逆问题,求解器械辅助力
# Part 5a: 修改肌肉驱动模型,膝盖坐标添加一个SpringGeneralizedForce。# 在knee_angle_r广义坐标上添加一个弹簧阻尼组件,输入坐标名称
device = osim.SpringGeneralizedForce('knee_angle_r')
device.setStiffness(50)
device.setRestLength(0)
device.setViscosity(0)
# 在模型中添加力组件
muscleDrivenModel.addForce(device)# Part 5b: Create a ModelProcessor similar to the previous one, using the same
# reserve actuator strength so we can compare muscle activity accurately.
# 修改后的模型,加载到ModelProcessor,添加储备执行器强度,比较是否器械情况下的肌肉情况
modelProcessor = osim.ModelProcessor(muscleDrivenModel)
modelProcessor.append(osim.ModOpAddReserves(2))
inverse.setModel(modelProcessor)# Part 5c:固定格式,求解! 获取结果并保存
inverseDeviceSolution = inverse.solve()
deviceSolution = inverseDeviceSolution.getMocoSolution()
deviceSolution.write('inverseDeviceSolution.sto')## Part 6: 比较无辅助和辅助情况下的逆问题结果
print('Cost without device: ', solution.getObjective())
print('Cost with device: ', deviceSolution.getObjective())# 使用此函数进行方便的结果对比画图
helpers.compareInverseSolutions(inverseSolution, inverseDeviceSolution)

4. 关节扭矩驱动与肌肉驱动的模型处理方法

模型的预处理封装在exampleSquatToStand_helpers.py中供直接使用,此处只截取模型处理部分进行注释说明。


def addCoordinateActuator(model, coordName, optForce):"""向给定的生物力学模型添加坐标致动器参数:- model:生物力学模型对象。- coordName:要添加致动器的坐标名称,要与.osim文件"Coordinate name=**"中一致- optForce:最大扭矩值。"""# 获取模型的关节坐标集coordSet = model.updCoordinateSet()# 创建一个坐标致动器actu = osim.CoordinateActuator()# 设置致动器的名称actu.setName('tau_' + coordName)# setCoordinate将致动器关联到特定的坐标actu.setCoordinate(coordSet.get(coordName))# setOptimalForce设置致动器的最大扭矩actu.setOptimalForce(optForce)# 输入的control的最小/小控制值,一般设置inf,.osim中有对应属性actu.setMinControl(-1)actu.setMaxControl(1)# 将致动器添加到模型中model.addComponent(actu)def getTorqueDrivenModel():# 加载基础模型model = osim.Model('squatToStand_3dof9musc.osim')# 移除模型中的肌肉model.updForceSet().clearAndDestroy()model.initSystem()# 向模型的关节自由度上添加坐标致动器addCoordinateActuator(model, 'hip_flexion_r', 150)addCoordinateActuator(model, 'knee_angle_r', 300)addCoordinateActuator(model, 'ankle_angle_r', 150)return modeldef getMuscleDrivenModel():# 加载基础模型model = osim.Model('squatToStand_3dof9musc.osim')# 进行重载,完成模型的连接model.finalizeConnections()# 使用DeGrooteFregly提出的肌肉替换原模型,# 它们的特性曲线针对Direct Collocation法进行了优化(即无间断点、二次可微等)osim.DeGrooteFregly2016Muscle().replaceMuscles(model)# 通过强化模型和加宽主动力-长度曲线,使问题更容易求解# 遍历模型中的所有肌肉,对于每个肌肉有如下操作for m in np.arange(model.getMuscles().getSize()):musc = model.updMuscles().get(int(m))# 设置最小控制值为 0musc.setMinControl(0.0)# 设置不忽略激活动力学,即使用肌肉激活动力学和肌腱顺应性musc.set_ignore_activation_dynamics(False)musc.set_ignore_tendon_compliance(False)# 将最大等长力设置为原来的两倍,例子中只考虑身体一半的右腿musc.set_max_isometric_force(2.0 * musc.get_max_isometric_force())# 肌肉转换为dgf = osim.DeGrooteFregly2016Muscle.safeDownCast(musc)# 肌肉主动力-长度曲线(Muscle Active Force-Length Curve)中# 设置肌肉主动力宽度为 1.5倍dgf.set_active_force_width_scale(1.5)# 肌腱的顺应性动力学模型设置为隐式形式dgf.set_tendon_compliance_dynamics_mode('implicit')# 忽略比目鱼肌“soleus_r”被动纤维力,被动纤维力对应具有刚性# 因为比目鱼肌肌腱很长,比目鱼肌肌腱不具有被动纤维力,即没有刚性,为纯柔性# 否则,因为纤维长度,会产生过多的被动纤维力# 设置后,soleus_r_passive_force列的值都为0if str(musc.getName()) == 'soleus_r':dgf.set_ignore_passive_fiber_force(True)return model

这篇关于使用Moco工具生成人体蹲起运动并分析辅助器械作用的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1122686

相关文章

C++使用栈实现括号匹配的代码详解

《C++使用栈实现括号匹配的代码详解》在编程中,括号匹配是一个常见问题,尤其是在处理数学表达式、编译器解析等任务时,栈是一种非常适合处理此类问题的数据结构,能够精确地管理括号的匹配问题,本文将通过C+... 目录引言问题描述代码讲解代码解析栈的状态表示测试总结引言在编程中,括号匹配是一个常见问题,尤其是在

Java中String字符串使用避坑指南

《Java中String字符串使用避坑指南》Java中的String字符串是我们日常编程中用得最多的类之一,看似简单的String使用,却隐藏着不少“坑”,如果不注意,可能会导致性能问题、意外的错误容... 目录8个避坑点如下:1. 字符串的不可变性:每次修改都创建新对象2. 使用 == 比较字符串,陷阱满

Python使用国内镜像加速pip安装的方法讲解

《Python使用国内镜像加速pip安装的方法讲解》在Python开发中,pip是一个非常重要的工具,用于安装和管理Python的第三方库,然而,在国内使用pip安装依赖时,往往会因为网络问题而导致速... 目录一、pip 工具简介1. 什么是 pip?2. 什么是 -i 参数?二、国内镜像源的选择三、如何

使用C++实现链表元素的反转

《使用C++实现链表元素的反转》反转链表是链表操作中一个经典的问题,也是面试中常见的考题,本文将从思路到实现一步步地讲解如何实现链表的反转,帮助初学者理解这一操作,我们将使用C++代码演示具体实现,同... 目录问题定义思路分析代码实现带头节点的链表代码讲解其他实现方式时间和空间复杂度分析总结问题定义给定

Linux使用nload监控网络流量的方法

《Linux使用nload监控网络流量的方法》Linux中的nload命令是一个用于实时监控网络流量的工具,它提供了传入和传出流量的可视化表示,帮助用户一目了然地了解网络活动,本文给大家介绍了Linu... 目录简介安装示例用法基础用法指定网络接口限制显示特定流量类型指定刷新率设置流量速率的显示单位监控多个

JavaScript中的reduce方法执行过程、使用场景及进阶用法

《JavaScript中的reduce方法执行过程、使用场景及进阶用法》:本文主要介绍JavaScript中的reduce方法执行过程、使用场景及进阶用法的相关资料,reduce是JavaScri... 目录1. 什么是reduce2. reduce语法2.1 语法2.2 参数说明3. reduce执行过程

如何使用Java实现请求deepseek

《如何使用Java实现请求deepseek》这篇文章主要为大家详细介绍了如何使用Java实现请求deepseek功能,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录1.deepseek的api创建2.Java实现请求deepseek2.1 pom文件2.2 json转化文件2.2

python使用fastapi实现多语言国际化的操作指南

《python使用fastapi实现多语言国际化的操作指南》本文介绍了使用Python和FastAPI实现多语言国际化的操作指南,包括多语言架构技术栈、翻译管理、前端本地化、语言切换机制以及常见陷阱和... 目录多语言国际化实现指南项目多语言架构技术栈目录结构翻译工作流1. 翻译数据存储2. 翻译生成脚本

C++ Primer 多维数组的使用

《C++Primer多维数组的使用》本文主要介绍了多维数组在C++语言中的定义、初始化、下标引用以及使用范围for语句处理多维数组的方法,具有一定的参考价值,感兴趣的可以了解一下... 目录多维数组多维数组的初始化多维数组的下标引用使用范围for语句处理多维数组指针和多维数组多维数组严格来说,C++语言没

Springboot中分析SQL性能的两种方式详解

《Springboot中分析SQL性能的两种方式详解》文章介绍了SQL性能分析的两种方式:MyBatis-Plus性能分析插件和p6spy框架,MyBatis-Plus插件配置简单,适用于开发和测试环... 目录SQL性能分析的两种方式:功能介绍实现方式:实现步骤:SQL性能分析的两种方式:功能介绍记录