alpha小数与16进制数值映射表

本文提供了一种将设计师工具中0.0到1.0的不透明度(alpha)值转换为16进制的方法,方便在安卓和iOS开发中使用。通过简单的数学转换,可以将小数形式的alpha值转换为16进制,从而简化了颜色透明度的编程工作。同时,文中列出了一份详细的百分比不透明度到16进制的映射表,帮助开发者快速查找对应值。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在客户端开发时,有些设计师的设计工具提供的alpha是[0.0 , 1.0] 的小数, 而安卓 、iOS的编程语言使用的是16进制,这时通常是自己用 计算器 转换一下。 但每次都用计算器来算,真是太没水平、太浪费时间了,因此提供以下 映射表。

转换方法 如下:
例如 alpha = 0.5,则 0.5*255 = 127.5, 16进制里没有小数,四舍五入后为 128,注意是 10进制 里的128,转成 16进制就是 80;

注意 alpha 是表示 【不透明度】,可以直观理解为【色彩有效性的比重】,比重为0表示 无颜色、即完全透明;比重为1表示 完全填充、即完全不透明。

百分比进制下的 alpha(不透明度) 对应 16进制 alpha(不透明度),小数请自行转换为百分比

100% — FF
99% — FC
98% — FA
97% — F7
96% — F5
95% — F2
94% — F0
93% — ED
92% — EB
91% — E8
90% — E6
89% — E3
88% — E0
87% — DE
86% — DB
85% — D9
84% — D6
83% — D4
82% — D1
81% — CF
80% — CC
79% — C9
78% — C7
77% — C4
76% — C2
75% — BF
74% — BD
73% — BA
72% — B8
71% — B5
70% — B3
69% — B0
68% — AD
67% — AB
66% — A8
65% — A6
64% — A3
63% — A1
62% — 9E
61% — 9C
60% — 99
59% — 96
58% — 94
57% — 91
56% — 8F
55% — 8C
54% — 8A
53% — 87
52% — 85
51% — 82
50% — 80
49% — 7D
48% — 7A
47% — 78
46% — 75
45% — 73
44% — 70
43% — 6E
42% — 6B
41% — 69
40% — 66
39% — 63
38% — 61
37% — 5E
36% — 5C
35% — 59
34% — 57
33% — 54
32% — 52
31% — 4F
30% — 4D
29% — 4A
28% — 47
27% — 45
26% — 42
25% — 40
24% — 3D
23% — 3B
22% — 38
21% — 36
20% — 33
19% — 30
18% — 2E
17% — 2B
16% — 29
15% — 26
14% — 24
13% — 21
12% — 1F
11% — 1C
10% — 1A
9% — 17
8% — 14
7% — 12
6% — 0F
5% — 0D
4% — 0A
3% — 08
2% — 05
1% — 03
0% — 00

<think>我们面对的问题是在不支持浮点运算的处理器上,将电机坐标变换中的归一化值(如角度、电压等)映射到Q12定点数范围(0~4095)。Q12表示整数部分0位,小数部分12位,因此数值范围是0到4095对应0.0到(4095/4096)≈0.999,但通常我们也可以映射到0到4095表示0到2π(角度)或-1到1(电压电流等)的范围。不过,题目要求映射到0~4095,所以我们需要将归一化的值映射到这个整数区间。 步骤: 1. 确定归一化前的数值范围:例如,角度通常是0到2π,电压电流可能是-最大值到+最大值。 2. 将归一化前的数值线性变换到0~4095的整数。 但是,题目要求的是归一化值映射到Q12定点数0~4095。这里有两种情况: a) 对于角度归一化:我们通常将角度归一化到[0, 2π)或[0,1)(即除以2π)。但题目要求映射到0~4095,我们可以将[0,2π)映射到[0,4095]。 b) 对于其他量(如电压、电流),我们可能先归一化到[-1,1]或[0,1],然后再映射到0~4095。但注意,0~4095是无符号整数,所以对于有符号的量,我们需要先偏移到正数范围。 然而,题目要求映射到0~4095,所以对于有符号量,我们需要先将其变换到非负数范围。例如,将电压从[-Vmax, Vmax]映射到[0,4095]: 第一步:归一化到[-1,1]:v_norm = v / Vmax 第二步:将[-1,1]映射到[0,2]:v_norm2 = v_norm + 1 (这样范围变成0~2) 第三步:将[0,2]映射到[0,4095]:v_int = (int)(v_norm2 * 4095 / 2) 但是,由于处理器不支持浮点,我们需要用定点数运算。我们可以使用Q格式定点数。例如,使用Q1516位有符号整数,其中15小数)或Q12(16位整数,其中12位小数)等。 具体到电机坐标变换中的归一化,我们以角度归一化为例: 角度范围:0到2π(弧度) 目标范围:0到4095(整数) 变换公式: 整数输出 = (角度 * 4095) / (2π) [注意:这样映射后,2π会对应4095,但通常我们使用整数除法] 但是,由于处理器不支持浮点,我们需要将角度和2π都用定点数表示。假设角度值已经用定点数表示(比如从编码器读取的是整数脉冲数,我们可以将其转换为代表角度的整数)。 假设我们有一个角度值,其原始表示是0到N-1(N为编码器一圈的计数),那么我们可以直接映射到0~4095: 整数输出 = (当前计数值 * 4095) / (N-1) 但是,如果原始角度是用定点数表示的弧度(比如用Q格式表示),那么我们需要计算:角度/(2π) * 4095。 由于处理器不支持浮点,我们可以将2π的倒数用定点数表示。例如,使用Q12格式,我们可以将1/(2π)表示为: 1/(2π) ≈ 0.15915494309189535 在Q12中,0.15915494309189535 * 4096 = 652(取整) (注意:Q12中,1对应4096,但这里我们使用乘法因子为4096,因为Q12的小数部分有12位,所以乘以4096相当于左移12位) 所以,我们可以用652(即0x028C)来表示1/(2π)的Q12值。 那么,角度(弧度)乘以652再右移12位(即除以4096),就得到归一化到[0,1)的值,然后再乘以4095(即映射到0~4095)?但是这样会先归一化到0~1再乘以4095,实际上可以合并为一步: 目标整数 = (角度(弧度) * 4095) / (2π) 在定点数中,我们可以这样计算: 目标整数 = (角度(弧度) * (4095 * 4096) / (2π)) >> 12 [因为分母是2π,分子是4095,再乘以4096(即左移12位)] 但是,这样计算量较大,而且分子分母都是常数,我们可以预先计算一个比例因子K: K = (4095 * 4096) / (2π) [这是一个常数] 计算K的整数近似值: 4095 * 4096 = 16773120 2π ≈ 6.283185307179586 K = 16773120 / 6.283185307179586 ≈ 2669327.5 (取整数2669328) 那么,计算过程为: 目标整数 = (角度(弧度) * K) >> 12 [因为乘以K相当于乘以4095*4096/(2π),再右移12位相当于除以4096,所以最终是角度/(2π)*4095] 但是,这里角度(弧度)也是定点数,我们需要知道它的表示方式。假设角度也是Q12定点数(即用0~2π对应的整数范围是0到2π*4096,那么实际值范围0~25736(因为2π≈6.28,6.28*4096≈25736))。那么,我们直接用角度(Q12)乘以K(2669328)得到64位中间结果,然后右移24位(因为两个Q12相乘,结果需要右移24位才能得到整数部分,但这里我们还要考虑K的缩放)?这样计算比较复杂。 另一种更直接的方法:既然角度已经是Q12定点数,那么它的范围是0到大约25736(2π对应的Q12值)。我们想要映射到0~4095,可以直接: 目标整数 = (角度(Q12) * 4095) / (2π对应的Q12值) 其中,2π对应的Q12值 = 2π * 4096 ≈ 25736(取整数) 所以:目标整数 = (角度 * 4095) / 25736 这样,我们只需要整数乘法和除法。注意:角度是Q12,乘以4095(整数)后,得到的结果是Q12格式的整数,然后除以25736(整数)得到整数结果(0~4095)。 因此,在代码中我们可以这样实现: uint16_t map_angle_to_q12(uint32_t angle_q12) { // angle_q12: 用Q12表示的角度,范围0~ (2π*4096)的整数部分(约25736) // 计算: (angle_q12 * 4095) / (2π对应的Q12值) uint32_t temp = angle_q12 * 4095; // 除以25736(即2π的Q12近似值) uint16_t result = temp / 25736; // 整数除法,结果在0~4095 return result; } 但是,这种方法在乘法时可能会溢出。angle_q12最大为25736,乘以4095: 25736 * 4095 = 105, 000, 000 大约,而32位无符号整数最大为4,294,967,295,所以不会溢出。 因此,我们可以用这种方法。 对于有符号量(如电流、电压),我们可能需要先偏移到正数范围。例如,电流范围是[-I_max, I_max],我们想映射到0~4095。我们可以: 第一步:将电流归一化到[-1,1]:i_norm = i / I_max (这里i用定点数表示,比如Q12) 第二步:将[-1,1]映射到[0,4095]:offset = 1(即Q12的1对应4096),然后乘以4095/2(因为范围长度是2) 但是,由于我们使用定点数,并且要避免浮点,我们可以: 目标整数 = ( (i_q12 + (1<<12) ) * 4095 ) / (2<<12) [因为1在Q12中是4096,2在Q12中是8192?不对] 实际上,电流i_q12的范围是[-I_max, I_max]对应的Q12值。假设我们已将电流归一化到Q12表示,即I_max对应1.0,那么I_max在Q12中就是4096(因为1.0在Q12中表示为1<<12=4096)。所以电流i_q12的范围是-4096到4096(实际最大4095,因为Q12最大正数是0xFFF,即4095,但我们可以用有符号整数,范围-4096到4095)。 那么,将[-4096,4095]映射到[0,4095]: 首先,加上4096(即偏移到0~8191),然后乘以4095,再除以8191(因为范围长度是8191)。但是,我们通常希望对称,所以用最大值4095对应4095,最小值-4096对应0。 公式: target = ( (i_q12 + 4096) * 4095 ) / 8192 但是,8192=2<<12,所以除以8192相当于右移13位。但是乘法部分:(i_q12+4096)最大为8191,乘以4095=8191*4095≈33,550,000,在32位整数范围内。 代码: uint16_t map_current_to_q12(int16_t i_q12) { // i_q12: 电流的Q12表示,范围-4096到4095 int32_t temp = (int32_t)i_q12 + 4096; // 现在范围0~8191 temp = temp * 4095; // 最大8191*4095=33,550,000 temp = temp / 8192; // 整数除法,相当于右移13位 return (uint16_t)temp; // 结果在0~4095 } 注意:这里除以8192也可以用移位(右移13位)实现。 总结: 对于不同的物理量,我们需要根据其范围设计映射函数。核心思想是:将原值线性变换到0~4095的整数范围,使用整数运算(乘法和除法)实现。 在电机坐标变换中,我们可能需要对角度、电流等进行上述映射。在变换函数(如Clark、Park)中,我们使用定点数版本的变换公式,然后对结果进行映射。 下面给出定点数版本的Clark变换和Park变换(使用Q12格式)的示例代码: 注意:Clark变换输入是三相电流(Ia, Ib, Ic),输出是alpha, beta。在定点数中,我们假设三相电流用Q12表示(即实际电流乘以4096,用整数表示)。 Clark变换公式(定点数版本): alpha = (2/3) * (Ia - 0.5*Ib - 0.5*Ic) beta = (2/3) * ( (√3/2)*Ib - (√3/2)*Ic ) 为了避免浮点,我们将系数用Q12表示: 2/3 ≈ 0.6666667,在Q12中:0.6666667 * 4096 ≈ 2730(取整) √3/2 ≈ 0.8660254,在Q12中:0.8660254 * 4096 ≈ 3548(取整) 0.5在Q12中就是2048(因为0.5*4096=2048) 所以,Clark变换的定点数实现: void clarkTransform_fixed(int16_t Ia, int16_t Ib, int16_t Ic, int16_t *alpha, int16_t *beta) { // 输入Ia, Ib, Ic是Q12表示的电流 // 1. 计算 Ia - 0.5*Ib - 0.5*Ic int32_t temp_alpha = (int32_t)Ia - ((int32_t)Ib/2) - ((int32_t)Ic/2); // 除以2可以用移位,但注意有符号移位 // 或者:temp_alpha = Ia - ((Ib + Ic) >> 1); // 然后乘以2/3(Q12系数2730) temp_alpha = (temp_alpha * 2730) >> 12; // 乘以2730(Q12)再右移12位,得到Q12的结果 // 2. 计算 (√3/2)*(Ib - Ic) [注意公式是(√3/2)*Ib - (√3/2)*Ic = (√3/2)*(Ib-Ic)] int32_t temp_beta = (int32_t)(Ib - Ic) * 3548; // 乘以系数(Q12) temp_beta = temp_beta >> 12; // 右移12位得到Q12 *alpha = (int16_t)temp_alpha; *beta = (int16_t)temp_beta; } Park变换公式(定点数版本): d = alpha * cos(theta) + beta * sin(theta) q = -alpha * sin(theta) + beta * cos(theta) 这里theta是归一化后的角度(0~4095对应0~2π),我们需要用这个整数角度来查表(预先计算sin和cos的Q12值表,表大小为4096个元素,每个元素为int16_t,范围-4096~4095,表示-1.0~1.0)。 查表方法: 将0~4095的整数角度作为索引,查表得到对应的cos_value和sin_value(都是Q12格式)。 然后进行乘法累加(注意乘法后需要右移12位,因为两个Q12相乘得到Q24,右移12位得到Q12)。 代码示例: // 预先计算好的正弦和余弦表(Q12格式,大小为4096) const int16_t sin_table[4096] = {...}; // 0~4095对应0~2π const int16_t cos_table[4096] = {...}; void parkTransform_fixed(int16_t alpha, int16_t beta, uint16_t theta_index, int16_t *d, int16_t *q) { // theta_index: 归一化到0~4095的角度索引 int16_t cos_val = cos_table[theta_index]; int16_t sin_val = sin_table[theta_index]; // 计算d = alpha * cos(theta) + beta * sin(theta) int32_t d_temp = (int32_t)alpha * (int32_t)cos_val + (int32_t)beta * (int32_t)sin_val; d_temp = d_temp >> 12; // 从Q24转回Q12 // 计算q = -alpha * sin(theta) + beta * cos(theta) int32_t q_temp = - (int32_t)alpha * (int32_t)sin_val + (int32_t)beta * (int32_t)cos_val; q_temp = q_temp >> 12; *d = (int16_t)d_temp; *q = (int16_t)q_temp; } 注意:乘法运算可能会溢出,因此使用32位整数进行中间计算。 最后,归一化处理(映射到0~4095)可以在需要的时候调用前面设计的映射函数。例如,在得到d,q后,如果需要将它们映射到0~4095,则调用map_current_to_q12(注意d,q是有符号的,所以需要偏移)。 但是,在FOC控制中,d,q通常用于PID控制,而PID控制器可能要求输入是Q12格式的有符号数,所以不一定需要映射到0~4095。题目要求归一化数值范围扩展到Q12(0~4095),但这里的Q12实际上是指12位无符号整数(0~4095)。所以,如果后续处理需要无符号整数,则进行映射;如果需要保留符号,则不需要映射。 因此,根据题目要求,我们只需将归一化值(如角度、或需要无符号表示的物理量)映射到0~4095。 总结实现步骤: 1. 将原始物理量(角度、电流等)转换为定点数(Q12)。 2. 在坐标变换中使用定点数运算。 3. 根据需要,将变换后的值映射到0~4095(无符号整数)。 注意:在定点数运算中,要特别注意数值范围和精度,以及避免溢出。 以上是基于处理器不支持浮点运算的定点数实现方法。</think>### 电机坐标变换归一化值映射到Q12定点数的实现方法 当处理器不支持浮点运算时,需要将电机控制中的坐标变换归一化值映射到Q12定点数范围(0~4095)。以下是完整的实现方案: #### 1. **Q12定点数表示原理** Q12格式使用16位整数表示定点数,其中: - 高4位为整数部分(实际不使用) - 低12位为小数部分 - 数值范围:$0$ 到 $4095$ ($2^{12}-1$) - 实际表示范围:$0.0$ 到 $\frac{4095}{4096} \approx 0.999$ - 映射关系:$x_{Q12} = \lfloor x_{\text{norm}} \times 4096 \rfloor$ #### 2. **关键参数的定点数转换** 将浮点参数转换为Q12定点常数: | 参数 | 浮点值 | Q12值(十六进制) | 计算方式 | |------|--------|------------------|----------| | $2\pi$ | 6.283185 | 0x6487 | $\lfloor 6.283185 \times 4096 \rfloor = 25736$ | | $\frac{2}{3}$ | 0.666667 | 0x0AAB | $\lfloor 0.666667 \times 4096 \rfloor = 2730$ | | $\frac{\sqrt{3}}{2}$ | 0.866025 | 0x0DDD | $\lfloor 0.866025 \times 4096 \rfloor = 3548$ | ```c // Q12 定点常数定义 #define Q12_2PI 0x6487 // 2π 的Q12表示 #define Q12_2DIV3 0x0AAB // 2/3 的Q12表示 #define Q12_SQRT3_2 0x0DDD // √3/2 的Q12表示 #define Q12_SCALE 4096 // Q12缩放因子 ``` #### 3. **定点数坐标变换实现** ##### (1) Clark变换(三相转两相) 浮点公式: $$\begin{bmatrix} \alpha \\ \beta \end{bmatrix} = \frac{2}{3} \begin{bmatrix} 1 & -0.5 & -0.5 \\ 0 & \frac{\sqrt{3}}{2} & -\frac{\sqrt{3}}{2} \end{bmatrix} \begin{bmatrix} I_a \\ I_b \\ I_c \end{bmatrix}$$ Q12定点实现: ```c void clark_transform_q12(int16_t Ia, int16_t Ib, int16_t Ic, int16_t *alpha, int16_t *beta) { // 所有输入输出均为Q12格式 int32_t temp; // &alpha; = (2/3) * (Ia - 0.5*Ib - 0.5*Ic) temp = (int32_t)Ia * 2 - (int32_t)Ib - (int32_t)Ic; // 等效 ×2 temp = (temp * Q12_2DIV3) >> 12; // Q12乘法后右移12位 *alpha = (int16_t)temp; // β = (2/3) * (√3/2 * Ib - √3/2 * Ic) temp = (int32_t)(Ib - Ic) * Q12_SQRT3_2; temp = (temp * Q12_2DIV3) >> 12; *beta = (int16_t)temp; } ``` ##### (2) Park变换(静止转旋转) 浮点公式: $$\begin{bmatrix} d \\ q \end{bmatrix} = \begin{bmatrix} \cos\theta & \sin\theta \\ -\sin\theta & \cos\theta \end{bmatrix} \begin{bmatrix} \alpha \\ \beta \end{bmatrix}$$ Q12定点实现(使用查表法优化): ```c // 预先计算Q12格式的sin/cos表(4096点对应0~2π) const int16_t sin_table[4096] = {0, 201, 402, ...}; // 预计算值 const int16_t cos_table[4096] = {4096, 4095, ...}; // 预计算值 void park_transform_q12(int16_t alpha, int16_t beta, uint16_t theta_q12, int16_t *d, int16_t *q) { // theta_q12: 归一化角度(0~4095对应0~2π) int16_t sin_val = sin_table[theta_q12]; int16_t cos_val = cos_table[theta_q12]; // d = &alpha;*cosθ + β*sinθ int32_t d_temp = (int32_t)alpha * cos_val + (int32_t)beta * sin_val; // q = -&alpha;*sinθ + β*cosθ int32_t q_temp = -(int32_t)alpha * sin_val + (int32_t)beta * cos_val; *d = (int16_t)(d_temp >> 12); // Q24转Q12 *q = (int16_t)(q_temp >> 12); } ``` #### 4. **角度归一化到Q12范围** 将机械角度映射到0~4095范围: ```c uint16_t normalize_angle_q12(uint16_t raw_angle, uint16_t max_count) { // raw_angle: 编码器原始计数值 // max_count: 编码器单圈最大计数值(如AS5600=4096) uint32_t temp = (uint32_t)raw_angle * 4095; return temp / (max_count - 1); // 映射到0~4095 } ``` #### 5. **电压/电流的归一化处理** 将有符号量映射到Q12范围: ```c uint16_t normalize_current_q12(int16_t current, int16_t max_current) { // 将[-max, +max]映射到[0, 4095] int32_t shifted = (int32_t)current + max_current; // 转非负 uint32_t scaled = (shifted * 4095) / (2 * max_current); return (uint16_t)scaled; } ``` #### 6. **完整处理流程** ```c // 1. 读取编码器原始角度 uint16_t raw_angle = encoder_read(); // 2. 归一化到Q12范围 (0~4095) uint16_t norm_angle = normalize_angle_q12(raw_angle, 4096); // 3. 读取三相电流(12位ADC值) int16_t Ia = adc_read(0) - 2048; // 12位ADC转有符号Q12 int16_t Ib = adc_read(1) - 2048; int16_t Ic = adc_read(2) - 2048; // 4. Clark变换 int16_t alpha, beta; clark_transform_q12(Ia, Ib, Ic, &alpha, &beta); // 5. Park变换 int16_t d, q; park_transform_q12(alpha, beta, norm_angle, &d, &q); // 6. 将d/q映射到监测范围(可选) uint16_t d_monitor = normalize_current_q12(d, 2048); uint16_t q_monitor = normalize_current_q12(q, 2048); ``` #### 7. **关键优化技术** 1. **查表法优化三角运算** - 预先计算4096点的sin/cos表 - 使用Q12格式存储(-4096~+4095对应-1.0~+0.999) ```c // 生成正弦表代码示例 for (int i = 0; i < 4096; i++) { float angle = 2 * PI * i / 4096.0; sin_table[i] = (int16_t)(sin(angle) * 4096); } ``` 2. **移位代替乘除法** ```c // 传统乘法 result = (a * b) >> 12; // 优化为移位(当b为2的幂次时) result = a << 3; // 等效×8 ``` 3. **32位中间变量防溢出** ```c // 32位中间计算防止溢出 int32_t temp = (int32_t)a * b; result = (int16_t)(temp >> 12); ``` 4. **Q格式自动转换宏** ```c #define FLOAT_TO_Q12(x) ((int16_t)((x) * 4096)) #define Q12_TO_FLOAT(q) (((float)(q)) / 4096.0f) ``` #### 8. **验证测试方法** 1. **边界值测试** ```c // 测试0°和360°应得相同结果 park_transform_q12(alpha, beta, 0, &d1, &q1); park_transform_q12(alpha, beta, 4095, &d2, &q2); assert(d1 == d2 && q1 == q2); ``` 2. **精度评估** ```c float float_d = alpha_f * cos(theta_f) + beta_f * sin(theta_f); float fixed_d = Q12_TO_FLOAT(d_q12); float error = fabs(float_d - fixed_d); ``` 3. **性能分析** - 使用处理器周期计数器 - 对比浮点定点版本的指令周期数 > **注意**:Q12格式的4095对应实际值$4095/4096≈0.999$,不是1.0。若需精确表示1.0,需使用Q11格式[^3]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值