仅使用整数数学对 C 中的正弦信号进行形状修改
Shape modification of sine signal in C using only integer math
我想在 ARM Cortex M0 微控制器上生成一个正弦信号,该微控制器可以通过形状参数 n 对其形状进行自定义。以下面的图为例。在这里,我使用函数
对不同的曲线进行建模
$y(x) = (1/2*(1 + sin(x)))^n$
对于更高的 n,最大值是 "shorter",最小值是“wider
”。对于较小的 n,最大值是“wider
”,最小值是“shorter
”。
为了减少内存消耗和提高性能,我只使用整数数学来生成正弦信号。
下面是正弦计算的代码:
Input range [0R 2πR] mapped to [0 to 1024].
输出范围 [-1.0 1.0] 映射到 [-16,384 16,384].
int_fast16_t sin_bam(int angle_bam) {
angle_bam %= 1024;
if (angle_bam < 0)
angle_bam += 1024;
uint_fast16_t sub_angle = angle_bam % (1024u / 2);
int_fast16_t sn = unsigned_mult16x16_into_32(sub_angle, (1024/2 - sub_angle)) / 4;
if (angle_bam & 512) {
sn = -sn;
}
return sn;
}
有没有人知道如何只用整数数学来实现这样的形状修改?
这个怎么样:
/*
* Generate integers to drive an n-bit D/A to make a modified sine wave.
*
* y = (1/2 * (1 + sin(theta))) ^ q
*
* y and q are 16-bit fixed-point numbers:
*
* 1000.000000000000 -> -8.000000000000
* ...
* 1111.111111111110 -> -0.000488281250
* 1111.111111111111 -> -0.000244140625
* 0000.000000000000 -> 0.000000000000
* 0000.000000000001 -> 0.000244140625
* 0000.000000000010 -> 0.000488281250
* ...
* 0111.111111111111 -> 7.999755859375
*
* theta is an 8-bit integer where
* 0x00 -> 0
* 0xff -> pi
*/
#include <iostream>
#include <string>
using namespace std;
#include <sys/types.h>
#include <stdlib.h>
#include <math.h>
string
fp2str( uint16_t n )
{
char buf[64];
bool neg = ((n & 0x8000) != 0);
if (neg) {
n = ~n + 1;
buf[0] = '-';
}
sprintf( buf + 1, "%14.12f", double(n) / double(0x1000) );
return neg ? buf : buf + 1;
}
uint16_t fpsin( uint16_t theta ) { // 0 < theta < 1024 ==> 0 to 2pi
static uint16_t sintbl[256] = {
0x0000,0x0019,0x0032,0x004c,0x0065,0x007e,0x0097,0x00b1,0x00ca,0x00e3,0x00fc,0x0115,0x012e,0x0148,0x0161,0x017a,
0x0193,0x01ac,0x01c5,0x01de,0x01f7,0x0210,0x0229,0x0242,0x025b,0x0274,0x028d,0x02a6,0x02bf,0x02d8,0x02f1,0x0309,
0x0322,0x033b,0x0354,0x036c,0x0385,0x039d,0x03b6,0x03cf,0x03e7,0x0400,0x0418,0x0430,0x0449,0x0461,0x0479,0x0491,
0x04aa,0x04c2,0x04da,0x04f2,0x050a,0x0522,0x053a,0x0551,0x0569,0x0581,0x0598,0x05b0,0x05c8,0x05df,0x05f7,0x060e,
0x0625,0x063d,0x0654,0x066b,0x0682,0x0699,0x06b0,0x06c7,0x06de,0x06f4,0x070b,0x0722,0x0738,0x074f,0x0765,0x077c,
0x0792,0x07a8,0x07be,0x07d4,0x07ea,0x0800,0x0816,0x082c,0x0841,0x0857,0x086c,0x0882,0x0897,0x08ac,0x08c1,0x08d6,
0x08eb,0x0900,0x0915,0x092a,0x093f,0x0953,0x0968,0x097c,0x0990,0x09a4,0x09b8,0x09cc,0x09e0,0x09f4,0x0a08,0x0a1b,
0x0a2f,0x0a42,0x0a56,0x0a69,0x0a7c,0x0a8f,0x0aa2,0x0ab5,0x0ac7,0x0ada,0x0aed,0x0aff,0x0b11,0x0b23,0x0b35,0x0b47,
0x0b59,0x0b6b,0x0b7d,0x0b8e,0x0b9f,0x0bb1,0x0bc2,0x0bd3,0x0be4,0x0bf5,0x0c05,0x0c16,0x0c27,0x0c37,0x0c47,0x0c57,
0x0c67,0x0c77,0x0c87,0x0c97,0x0ca6,0x0cb5,0x0cc5,0x0cd4,0x0ce3,0x0cf2,0x0d01,0x0d0f,0x0d1e,0x0d2c,0x0d3a,0x0d48,
0x0d56,0x0d64,0x0d72,0x0d80,0x0d8d,0x0d9a,0x0da8,0x0db5,0x0dc2,0x0dcf,0x0ddb,0x0de8,0x0df4,0x0e00,0x0e0d,0x0e19,
0x0e24,0x0e30,0x0e3c,0x0e47,0x0e53,0x0e5e,0x0e69,0x0e74,0x0e7e,0x0e89,0x0e94,0x0e9e,0x0ea8,0x0eb2,0x0ebc,0x0ec6,
0x0ecf,0x0ed9,0x0ee2,0x0eeb,0x0ef4,0x0efd,0x0f06,0x0f0f,0x0f17,0x0f1f,0x0f28,0x0f30,0x0f38,0x0f3f,0x0f47,0x0f4e,
0x0f56,0x0f5d,0x0f64,0x0f6a,0x0f71,0x0f78,0x0f7e,0x0f84,0x0f8a,0x0f90,0x0f96,0x0f9c,0x0fa1,0x0fa6,0x0fac,0x0fb1,
0x0fb6,0x0fba,0x0fbf,0x0fc3,0x0fc7,0x0fcc,0x0fd0,0x0fd3,0x0fd7,0x0fda,0x0fde,0x0fe1,0x0fe4,0x0fe7,0x0fea,0x0fec,
0x0fef,0x0ff1,0x0ff3,0x0ff5,0x0ff7,0x0ff8,0x0ffa,0x0ffb,0x0ffc,0x0ffd,0x0ffe,0x0fff,0x0fff,0x1000,0x1000,0x1000
} ;
uint16_t val;
theta &= 0x3ff;
if (theta < 0x100)
val = sintbl[theta];
else
if (theta < 0x200)
val = sintbl [0x200 - theta - 1];
else
if (theta < 0x300)
val = (~sintbl[theta - 0x200] + 1); // negate
else
val = (~sintbl[0x400 - theta -1] + 1); // negate
return val;
}
/*
* Natural-log table. Smallest value is ln(2/4096) -> -7.624618986159398403
* (values smaller than 2/4096 have logs less than -8, which smaller than we
* can represent in our fixed-point format). Largest is 2.0776, which is ln(8)
*/
int16_t fplog( int16_t n )
{
static uint16_t lntbl[512] = {
/*0.00048828*/ 0x8602,0xbdf3,0xc8cc,0xcf34,0xd3c3,0xd74f,0xda36,0xdcaa,0xdecb,0xe0ab,0xe259,0xe3df,0xe542,0xe689,0xe7b8,0xe8d2,
/*0.25048828*/ 0xe9da,0xead2,0xebbb,0xec98,0xed6a,0xee32,0xeef0,0xefa6,0xf054,0xf0fb,0xf19b,0xf236,0xf2ca,0xf35a,0xf3e5,0xf46b,
/*0.50048828*/ 0xf4ed,0xf56b,0xf5e5,0xf65c,0xf6cf,0xf73f,0xf7ac,0xf816,0xf87e,0xf8e3,0xf946,0xf9a6,0xfa04,0xfa60,0xfaba,0xfb12,
/*0.75048828*/ 0xfb68,0xfbbd,0xfc0f,0xfc60,0xfcb0,0xfcfe,0xfd4a,0xfd96,0xfddf,0xfe28,0xfe6f,0xfeb5,0xfefa,0xff3d,0xff80,0xffc2,
/*1.00048828*/ 0x0002,0x0041,0x0080,0x00be,0x00fa,0x0136,0x0171,0x01ab,0x01e4,0x021d,0x0254,0x028b,0x02c2,0x02f7,0x032c,0x0360,
/*1.25048828*/ 0x0394,0x03c6,0x03f9,0x042a,0x045b,0x048c,0x04bc,0x04eb,0x051a,0x0548,0x0576,0x05a3,0x05d0,0x05fc,0x0628,0x0653,
/*1.50048828*/ 0x067e,0x06a9,0x06d3,0x06fc,0x0725,0x074e,0x0776,0x079e,0x07c6,0x07ed,0x0814,0x083a,0x0860,0x0886,0x08ac,0x08d1,
/*1.75048828*/ 0x08f5,0x091a,0x093e,0x0962,0x0985,0x09a8,0x09cb,0x09ee,0x0a10,0x0a32,0x0a54,0x0a75,0x0a96,0x0ab7,0x0ad8,0x0af8,
/*2.00048828*/ 0x0b18,0x0b38,0x0b58,0x0b77,0x0b96,0x0bb5,0x0bd4,0x0bf2,0x0c10,0x0c2e,0x0c4c,0x0c6a,0x0c87,0x0ca4,0x0cc1,0x0cde,
/*2.25048828*/ 0x0cfa,0x0d17,0x0d33,0x0d4f,0x0d6b,0x0d86,0x0da2,0x0dbd,0x0dd8,0x0df3,0x0e0d,0x0e28,0x0e42,0x0e5c,0x0e76,0x0e90,
/*2.50048828*/ 0x0eaa,0x0ec3,0x0edd,0x0ef6,0x0f0f,0x0f28,0x0f41,0x0f59,0x0f72,0x0f8a,0x0fa2,0x0fba,0x0fd2,0x0fea,0x1001,0x1019,
/*2.75048828*/ 0x1030,0x1047,0x105f,0x1075,0x108c,0x10a3,0x10ba,0x10d0,0x10e6,0x10fc,0x1113,0x1129,0x113e,0x1154,0x116a,0x117f,
/*3.00048828*/ 0x1195,0x11aa,0x11bf,0x11d4,0x11e9,0x11fe,0x1213,0x1227,0x123c,0x1250,0x1265,0x1279,0x128d,0x12a1,0x12b5,0x12c9,
/*3.25048828*/ 0x12dc,0x12f0,0x1304,0x1317,0x132a,0x133e,0x1351,0x1364,0x1377,0x138a,0x139d,0x13af,0x13c2,0x13d5,0x13e7,0x13fa,
/*3.50048828*/ 0x140c,0x141e,0x1430,0x1442,0x1454,0x1466,0x1478,0x148a,0x149c,0x14ad,0x14bf,0x14d0,0x14e2,0x14f3,0x1504,0x1515,
/*3.75048828*/ 0x1526,0x1537,0x1548,0x1559,0x156a,0x157b,0x158c,0x159c,0x15ad,0x15bd,0x15ce,0x15de,0x15ee,0x15fe,0x160f,0x161f,
/*4.00048828*/ 0x162f,0x163f,0x164f,0x165e,0x166e,0x167e,0x168e,0x169d,0x16ad,0x16bc,0x16cc,0x16db,0x16ea,0x16fa,0x1709,0x1718,
/*4.25048828*/ 0x1727,0x1736,0x1745,0x1754,0x1763,0x1772,0x1780,0x178f,0x179e,0x17ac,0x17bb,0x17c9,0x17d8,0x17e6,0x17f5,0x1803,
/*4.50048828*/ 0x1811,0x181f,0x182d,0x183c,0x184a,0x1858,0x1866,0x1873,0x1881,0x188f,0x189d,0x18ab,0x18b8,0x18c6,0x18d4,0x18e1,
/*4.75048828*/ 0x18ef,0x18fc,0x1909,0x1917,0x1924,0x1931,0x193f,0x194c,0x1959,0x1966,0x1973,0x1980,0x198d,0x199a,0x19a7,0x19b4,
/*5.00048828*/ 0x19c1,0x19cd,0x19da,0x19e7,0x19f4,0x1a00,0x1a0d,0x1a19,0x1a26,0x1a32,0x1a3f,0x1a4b,0x1a57,0x1a64,0x1a70,0x1a7c,
/*5.25048828*/ 0x1a88,0x1a95,0x1aa1,0x1aad,0x1ab9,0x1ac5,0x1ad1,0x1add,0x1ae9,0x1af5,0x1b01,0x1b0c,0x1b18,0x1b24,0x1b30,0x1b3b,
/*5.50048828*/ 0x1b47,0x1b53,0x1b5e,0x1b6a,0x1b75,0x1b81,0x1b8c,0x1b98,0x1ba3,0x1bae,0x1bba,0x1bc5,0x1bd0,0x1bdc,0x1be7,0x1bf2,
/*5.75048828*/ 0x1bfd,0x1c08,0x1c13,0x1c1e,0x1c29,0x1c34,0x1c3f,0x1c4a,0x1c55,0x1c60,0x1c6b,0x1c76,0x1c80,0x1c8b,0x1c96,0x1ca1,
/*6.00048828*/ 0x1cab,0x1cb6,0x1cc1,0x1ccb,0x1cd6,0x1ce0,0x1ceb,0x1cf5,0x1d00,0x1d0a,0x1d15,0x1d1f,0x1d29,0x1d34,0x1d3e,0x1d48,
/*6.25048828*/ 0x1d53,0x1d5d,0x1d67,0x1d71,0x1d7b,0x1d85,0x1d90,0x1d9a,0x1da4,0x1dae,0x1db8,0x1dc2,0x1dcc,0x1dd6,0x1ddf,0x1de9,
/*6.50048828*/ 0x1df3,0x1dfd,0x1e07,0x1e11,0x1e1a,0x1e24,0x1e2e,0x1e38,0x1e41,0x1e4b,0x1e54,0x1e5e,0x1e68,0x1e71,0x1e7b,0x1e84,
/*6.75048828*/ 0x1e8e,0x1e97,0x1ea1,0x1eaa,0x1eb4,0x1ebd,0x1ec6,0x1ed0,0x1ed9,0x1ee2,0x1eec,0x1ef5,0x1efe,0x1f07,0x1f10,0x1f1a,
/*7.00048828*/ 0x1f23,0x1f2c,0x1f35,0x1f3e,0x1f47,0x1f50,0x1f59,0x1f62,0x1f6b,0x1f74,0x1f7d,0x1f86,0x1f8f,0x1f98,0x1fa1,0x1faa,
/*7.25048828*/ 0x1fb2,0x1fbb,0x1fc4,0x1fcd,0x1fd6,0x1fde,0x1fe7,0x1ff0,0x1ff8,0x2001,0x200a,0x2012,0x201b,0x2024,0x202c,0x2035,
/*7.50048828*/ 0x203d,0x2046,0x204e,0x2057,0x205f,0x2068,0x2070,0x2079,0x2081,0x2089,0x2092,0x209a,0x20a2,0x20ab,0x20b3,0x20bb,
/*7.75048828*/ 0x20c4,0x20cc,0x20d4,0x20dc,0x20e5,0x20ed,0x20f5,0x20fd,0x2105,0x210d,0x2115,0x211d,0x2126,0x212e,0x2136,0x213e
} ;
return (n >= 0x0002) ? lntbl[ (n - 2) >> 6 ] : 0x8000;
}
/*
* Exponential table -- from -8.0 to 2.xxx. Layout is tricky.
*/
int16_t fpexp( int16_t n ) {
static int16_t pos_exp[] = {
/*0000*/ 0x1000,0x1041,0x1082,0x10c5,0x1108,0x114d,0x1193,0x11d9,0x1221,0x126a,0x12b5,0x1300,0x134d,0x139b,0x13ea,0x143a,
/*0400*/ 0x148b,0x14de,0x1532,0x1588,0x15df,0x1637,0x1690,0x16eb,0x1748,0x17a5,0x1805,0x1866,0x18c8,0x192c,0x1991,0x19f8,
/*0800*/ 0x1a61,0x1acc,0x1b38,0x1ba5,0x1c15,0x1c86,0x1cf9,0x1d6e,0x1de4,0x1e5d,0x1ed7,0x1f54,0x1fd2,0x2052,0x20d4,0x2159,
/*0c00*/ 0x21df,0x2268,0x22f2,0x237f,0x240e,0x24a0,0x2533,0x25c9,0x2662,0x26fd,0x279a,0x2839,0x28dc,0x2980,0x2a28,0x2ad1,
/*1000*/ 0x2b7e,0x2c2d,0x2ce0,0x2d94,0x2e4c,0x2f07,0x2fc4,0x3085,0x3149,0x320f,0x32d9,0x33a6,0x3476,0x354a,0x3621,0x36fb,
/*1400*/ 0x37d8,0x38ba,0x399e,0x3a87,0x3b72,0x3c62,0x3d56,0x3e4d,0x3f48,0x4047,0x414a,0x4251,0x435d,0x446c,0x4580,0x4698,
/*1800*/ 0x47b5,0x48d6,0x49fc,0x4b26,0x4c55,0x4d89,0x4ec1,0x4fff,0x5141,0x5289,0x53d6,0x5527,0x567f,0x57db,0x593e,0x5aa5,
/*1c00*/ 0x5c13,0x5d86,0x5eff,0x607e,0x6203,0x638e,0x6520,0x66b7,0x6855,0x69fa,0x6ba5,0x6d57,0x6f10,0x70d0,0x7296,0x7464
} ;
static int16_t neg_exp[] = {
/*8000*/ 0x0001,0x0001,0x0001,0x0001,0x0001,0x0001,0x0002,0x0002,0x0002,0x0002,0x0002,0x0002,0x0002,0x0002,0x0002,0x0002,
/*8400*/ 0x0002,0x0002,0x0002,0x0002,0x0002,0x0002,0x0002,0x0002,0x0002,0x0002,0x0002,0x0002,0x0002,0x0002,0x0002,0x0002,
/*8800*/ 0x0002,0x0002,0x0002,0x0002,0x0002,0x0002,0x0002,0x0003,0x0003,0x0003,0x0003,0x0003,0x0003,0x0003,0x0003,0x0003,
/*8c00*/ 0x0003,0x0003,0x0003,0x0003,0x0003,0x0003,0x0003,0x0003,0x0003,0x0003,0x0003,0x0003,0x0004,0x0004,0x0004,0x0004,
/*9000*/ 0x0004,0x0004,0x0004,0x0004,0x0004,0x0004,0x0004,0x0004,0x0004,0x0004,0x0004,0x0004,0x0005,0x0005,0x0005,0x0005,
/*9400*/ 0x0005,0x0005,0x0005,0x0005,0x0005,0x0005,0x0005,0x0005,0x0005,0x0006,0x0006,0x0006,0x0006,0x0006,0x0006,0x0006,
/*9800*/ 0x0006,0x0006,0x0006,0x0006,0x0007,0x0007,0x0007,0x0007,0x0007,0x0007,0x0007,0x0007,0x0007,0x0008,0x0008,0x0008,
/*9c00*/ 0x0008,0x0008,0x0008,0x0008,0x0008,0x0009,0x0009,0x0009,0x0009,0x0009,0x0009,0x0009,0x000a,0x000a,0x000a,0x000a,
/*a000*/ 0x000a,0x000a,0x000a,0x000b,0x000b,0x000b,0x000b,0x000b,0x000c,0x000c,0x000c,0x000c,0x000c,0x000c,0x000d,0x000d,
/*a400*/ 0x000d,0x000d,0x000d,0x000e,0x000e,0x000e,0x000e,0x000f,0x000f,0x000f,0x000f,0x000f,0x0010,0x0010,0x0010,0x0010,
/*a800*/ 0x0011,0x0011,0x0011,0x0012,0x0012,0x0012,0x0012,0x0013,0x0013,0x0013,0x0014,0x0014,0x0014,0x0015,0x0015,0x0015,
/*ac00*/ 0x0015,0x0016,0x0016,0x0017,0x0017,0x0017,0x0018,0x0018,0x0018,0x0019,0x0019,0x001a,0x001a,0x001a,0x001b,0x001b,
/*b000*/ 0x001c,0x001c,0x001c,0x001d,0x001d,0x001e,0x001e,0x001f,0x001f,0x0020,0x0020,0x0021,0x0021,0x0022,0x0022,0x0023,
/*b400*/ 0x0023,0x0024,0x0025,0x0025,0x0026,0x0026,0x0027,0x0028,0x0028,0x0029,0x0029,0x002a,0x002b,0x002b,0x002c,0x002d,
/*b800*/ 0x002e,0x002e,0x002f,0x0030,0x0030,0x0031,0x0032,0x0033,0x0034,0x0034,0x0035,0x0036,0x0037,0x0038,0x0039,0x003a,
/*bc00*/ 0x003a,0x003b,0x003c,0x003d,0x003e,0x003f,0x0040,0x0041,0x0042,0x0043,0x0044,0x0045,0x0046,0x0048,0x0049,0x004a,
/*c000*/ 0x004b,0x004c,0x004d,0x004f,0x0050,0x0051,0x0052,0x0054,0x0055,0x0056,0x0058,0x0059,0x005a,0x005c,0x005d,0x005f,
/*c400*/ 0x0060,0x0062,0x0063,0x0065,0x0067,0x0068,0x006a,0x006b,0x006d,0x006f,0x0071,0x0072,0x0074,0x0076,0x0078,0x007a,
/*c800*/ 0x007c,0x007e,0x0080,0x0082,0x0084,0x0086,0x0088,0x008a,0x008c,0x008e,0x0091,0x0093,0x0095,0x0098,0x009a,0x009c,
/*cc00*/ 0x009f,0x00a1,0x00a4,0x00a6,0x00a9,0x00ac,0x00ae,0x00b1,0x00b4,0x00b7,0x00ba,0x00bd,0x00c0,0x00c3,0x00c6,0x00c9,
/*d000*/ 0x00cc,0x00cf,0x00d2,0x00d6,0x00d9,0x00dc,0x00e0,0x00e3,0x00e7,0x00eb,0x00ee,0x00f2,0x00f6,0x00fa,0x00fe,0x0102,
/*d400*/ 0x0106,0x010a,0x010e,0x0112,0x0117,0x011b,0x0120,0x0124,0x0129,0x012d,0x0132,0x0137,0x013c,0x0141,0x0146,0x014b,
/*d800*/ 0x0150,0x0156,0x015b,0x0160,0x0166,0x016c,0x0171,0x0177,0x017d,0x0183,0x0189,0x018f,0x0196,0x019c,0x01a2,0x01a9,
/*dc00*/ 0x01b0,0x01b7,0x01bd,0x01c4,0x01cc,0x01d3,0x01da,0x01e2,0x01e9,0x01f1,0x01f9,0x0201,0x0209,0x0211,0x0219,0x0222,
/*e000*/ 0x022a,0x0233,0x023c,0x0245,0x024e,0x0257,0x0261,0x026a,0x0274,0x027e,0x0288,0x0292,0x029d,0x02a7,0x02b2,0x02bd,
/*e400*/ 0x02c8,0x02d3,0x02de,0x02ea,0x02f6,0x0302,0x030e,0x031a,0x0327,0x0333,0x0340,0x034d,0x035b,0x0368,0x0376,0x0384,
/*e800*/ 0x0392,0x03a0,0x03af,0x03be,0x03cd,0x03dc,0x03ec,0x03fc,0x040c,0x041c,0x042d,0x043d,0x044e,0x0460,0x0471,0x0483,
/*ec00*/ 0x0496,0x04a8,0x04bb,0x04ce,0x04e1,0x04f5,0x0509,0x051d,0x0532,0x0547,0x055c,0x0572,0x0588,0x059e,0x05b4,0x05cb,
/*f000*/ 0x05e3,0x05fb,0x0613,0x062b,0x0644,0x065d,0x0677,0x0691,0x06ab,0x06c6,0x06e2,0x06fd,0x071a,0x0736,0x0753,0x0771,
/*f400*/ 0x078f,0x07ad,0x07cc,0x07ec,0x080c,0x082c,0x084d,0x086e,0x0890,0x08b3,0x08d6,0x08fa,0x091e,0x0943,0x0968,0x098e,
/*f800*/ 0x09b4,0x09db,0x0a03,0x0a2c,0x0a55,0x0a7e,0x0aa9,0x0ad3,0x0aff,0x0b2b,0x0b58,0x0b86,0x0bb5,0x0be4,0x0c14,0x0c45,
/*fc00*/ 0x0c76,0x0ca8,0x0cdb,0x0d0f,0x0d44,0x0d79,0x0daf,0x0de7,0x0e1f,0x0e58,0x0e91,0x0ecc,0x0f08,0x0f44,0x0f82,0x0fc0
} ;
if (n >= 0 && n < 0x2000) return pos_exp[n >> 6];
if (n < 0) return neg_exp[ (uint16_t(n) - 0x8000u) >> 6 ];
cerr << "can't compute exp( 0x" << hex << n << " " << fp2str( n ) << ")" << endl;
exit( 0 );
}
int
main( int, char ** )
{
#ifdef TESTING
for (uint16_t a = 2; a < 0x7000; a += 0x0529) {
cout << "ln(" << fp2str(a) << " (0x" << hex << a << ")) = "
<< fp2str( fplog( a ) ) << " ... " << log( double(a) / double(0x1000) ) << endl;
}
for (uint16_t a = 0; a < 0x2000; a += 0x0727) {
cout << "exp(" << fp2str(a) << " (0x" << hex << a << ")) = "
<< fp2str( fpexp( a ) ) << " ... " << exp( double(a) / double(0x1000) ) << endl;
}
for (int16_t a = -1; a > -30000; a -= 0x0ab7) {
cout << "exp(" << fp2str(a) << " (0x" << hex << a << ")) = "
<< fp2str( fpexp( a ) ) << " ... " << exp( double(a) / double(0x1000) ) << endl;
}
for (uint16_t a = 10; a < 0x7fff; a += 0x0ab7) {
cout << "exp( log(" << fp2str(a) << " (0x" << hex << a << "))) = "
<< fp2str( fpexp( fplog( a ) ) ) << endl;
}
#else
// Implementation of y = (1/2 * (1 + sin( x ))) ^ n is left as an exercise for the reader.
// Note that fplog() doesn't work on numbers smaller than 2/4096, and fpexp() doesn't work
// on numbers larger than about (2 - 1/4096)
#endif
return 0;
}
我用这个 Perl 脚本生成了查找表:
#!/usr/bin/perl -w
use Math::Trig ':pi';
use POSIX;
#
# Fixed-point values have 12 fractional bits ... 2^12 => 4096
#
my $LSB = 1.0 / 4096.0;
#
# print sin table values
#
if (0) {
for ($i = 0; $i < 0x100; $i += 1) {
$s = sin( $i * pip2 / 255 );
printf( "0x%04x,", POSIX::floor( 0x1000 * $s + 0.5) );
print "\n" if (($i & 15) == 15);
}
}
#
# print log table values
#
if (0) {
$x = $LSB * 2.0;
for ($n = 0; $n < 32000; ++$n) {
printf( "/*%10.8f*/ ", $x ) if (($n & 15) == 0);
printf( "0x%04x,", POSIX::floor( 0x1000 * log($x) + 0.5) & 0xffff );
print "\n" if (($n & 15) == 15);
$x += $LSB * 64.0;
last if ($x >= 8.0);
}
}
#
# print exp table values -- this is tricky because we want all the negative
# numbers (0xffff ~ 0x8000) but only positive numbers between 0x0000 and 0x2000.
#
if (1) {
for ($n = 0; $n < 0x2000; $n += 64) {
printf( "/*%04x*/ ", $n & 0xffff ) if ((($n >> 6) & 15) == 0);
# printf( "%8.5f,", $n / 4096.0 );
printf( "0x%04x,", POSIX::floor( exp( $n / 4096.0 ) * 0x1000 + 0.5 ) );
print "\n" if ((($n >> 6) & 15) == 15);
}
print "\n\n";
for ($n = -32768; $n < 0; $n += 64) {
printf( "/*%04x*/ ", $n & 0xffff ) if ((($n >> 6) & 15) == 0);
# printf( "%8.5f,", $n / 4096.0 );
printf( "0x%04x,", POSIX::floor( exp( $n / 4096 ) * 0x1000 + 0.5 ) );
print "\n" if ((($n >> 6) & 15) == 15);
}
}
棘手的一点是将信号移动和缩放到 fplog()
和 fpexp()
工作得相当好的范围。你会做一个 16x16->32 的乘法来取幂,所以我想你会把高 16 位作为你的定点数,你将它提供给 fpexp()
以获得最终输出。
Does anyone have an idea how to realize such a shape modification only with integer math?
n
could also have a range of 1 to 10 for example
$y(x) = (1/2*(1 + sin(x)))^n$
OP 有一个正弦近似函数 sin_bam()
,然后用它来形成 1/2*(1 + sin(x))
,即 hacovercosin(θ)。剩下的就是比例幂函数。
#include <inttypes.h>
#define SCALE 16384
int pow_scale(int x, unsigned n) {
unsigned y = SCALE;
while (n>0) {
if (n%2) {
y = unsigned_mult16x16_into_32(x,y)/SCALE; // 16-bit x 16-bit --> 32-bit product.
}
n /= 2;
x = unsigned_mult16x16_into_32(x,x)/SCALE;
}
return x;
}
// x is the angle in 1024 BAM per period
// output is scaled to range [0....SCALE]
int shaped(int x, unsigned n) {
return pow_scale(SCALE/2 + sin_bam(x)/2), n);
}
我想在 ARM Cortex M0 微控制器上生成一个正弦信号,该微控制器可以通过形状参数 n 对其形状进行自定义。以下面的图为例。在这里,我使用函数
对不同的曲线进行建模$y(x) = (1/2*(1 + sin(x)))^n$
对于更高的 n,最大值是 "shorter",最小值是“wider
”。对于较小的 n,最大值是“wider
”,最小值是“shorter
”。
为了减少内存消耗和提高性能,我只使用整数数学来生成正弦信号。
下面是正弦计算的代码:
Input range [0R 2πR] mapped to [0 to 1024].
输出范围 [-1.0 1.0] 映射到 [-16,384 16,384].
int_fast16_t sin_bam(int angle_bam) {
angle_bam %= 1024;
if (angle_bam < 0)
angle_bam += 1024;
uint_fast16_t sub_angle = angle_bam % (1024u / 2);
int_fast16_t sn = unsigned_mult16x16_into_32(sub_angle, (1024/2 - sub_angle)) / 4;
if (angle_bam & 512) {
sn = -sn;
}
return sn;
}
有没有人知道如何只用整数数学来实现这样的形状修改?
这个怎么样:
/*
* Generate integers to drive an n-bit D/A to make a modified sine wave.
*
* y = (1/2 * (1 + sin(theta))) ^ q
*
* y and q are 16-bit fixed-point numbers:
*
* 1000.000000000000 -> -8.000000000000
* ...
* 1111.111111111110 -> -0.000488281250
* 1111.111111111111 -> -0.000244140625
* 0000.000000000000 -> 0.000000000000
* 0000.000000000001 -> 0.000244140625
* 0000.000000000010 -> 0.000488281250
* ...
* 0111.111111111111 -> 7.999755859375
*
* theta is an 8-bit integer where
* 0x00 -> 0
* 0xff -> pi
*/
#include <iostream>
#include <string>
using namespace std;
#include <sys/types.h>
#include <stdlib.h>
#include <math.h>
string
fp2str( uint16_t n )
{
char buf[64];
bool neg = ((n & 0x8000) != 0);
if (neg) {
n = ~n + 1;
buf[0] = '-';
}
sprintf( buf + 1, "%14.12f", double(n) / double(0x1000) );
return neg ? buf : buf + 1;
}
uint16_t fpsin( uint16_t theta ) { // 0 < theta < 1024 ==> 0 to 2pi
static uint16_t sintbl[256] = {
0x0000,0x0019,0x0032,0x004c,0x0065,0x007e,0x0097,0x00b1,0x00ca,0x00e3,0x00fc,0x0115,0x012e,0x0148,0x0161,0x017a,
0x0193,0x01ac,0x01c5,0x01de,0x01f7,0x0210,0x0229,0x0242,0x025b,0x0274,0x028d,0x02a6,0x02bf,0x02d8,0x02f1,0x0309,
0x0322,0x033b,0x0354,0x036c,0x0385,0x039d,0x03b6,0x03cf,0x03e7,0x0400,0x0418,0x0430,0x0449,0x0461,0x0479,0x0491,
0x04aa,0x04c2,0x04da,0x04f2,0x050a,0x0522,0x053a,0x0551,0x0569,0x0581,0x0598,0x05b0,0x05c8,0x05df,0x05f7,0x060e,
0x0625,0x063d,0x0654,0x066b,0x0682,0x0699,0x06b0,0x06c7,0x06de,0x06f4,0x070b,0x0722,0x0738,0x074f,0x0765,0x077c,
0x0792,0x07a8,0x07be,0x07d4,0x07ea,0x0800,0x0816,0x082c,0x0841,0x0857,0x086c,0x0882,0x0897,0x08ac,0x08c1,0x08d6,
0x08eb,0x0900,0x0915,0x092a,0x093f,0x0953,0x0968,0x097c,0x0990,0x09a4,0x09b8,0x09cc,0x09e0,0x09f4,0x0a08,0x0a1b,
0x0a2f,0x0a42,0x0a56,0x0a69,0x0a7c,0x0a8f,0x0aa2,0x0ab5,0x0ac7,0x0ada,0x0aed,0x0aff,0x0b11,0x0b23,0x0b35,0x0b47,
0x0b59,0x0b6b,0x0b7d,0x0b8e,0x0b9f,0x0bb1,0x0bc2,0x0bd3,0x0be4,0x0bf5,0x0c05,0x0c16,0x0c27,0x0c37,0x0c47,0x0c57,
0x0c67,0x0c77,0x0c87,0x0c97,0x0ca6,0x0cb5,0x0cc5,0x0cd4,0x0ce3,0x0cf2,0x0d01,0x0d0f,0x0d1e,0x0d2c,0x0d3a,0x0d48,
0x0d56,0x0d64,0x0d72,0x0d80,0x0d8d,0x0d9a,0x0da8,0x0db5,0x0dc2,0x0dcf,0x0ddb,0x0de8,0x0df4,0x0e00,0x0e0d,0x0e19,
0x0e24,0x0e30,0x0e3c,0x0e47,0x0e53,0x0e5e,0x0e69,0x0e74,0x0e7e,0x0e89,0x0e94,0x0e9e,0x0ea8,0x0eb2,0x0ebc,0x0ec6,
0x0ecf,0x0ed9,0x0ee2,0x0eeb,0x0ef4,0x0efd,0x0f06,0x0f0f,0x0f17,0x0f1f,0x0f28,0x0f30,0x0f38,0x0f3f,0x0f47,0x0f4e,
0x0f56,0x0f5d,0x0f64,0x0f6a,0x0f71,0x0f78,0x0f7e,0x0f84,0x0f8a,0x0f90,0x0f96,0x0f9c,0x0fa1,0x0fa6,0x0fac,0x0fb1,
0x0fb6,0x0fba,0x0fbf,0x0fc3,0x0fc7,0x0fcc,0x0fd0,0x0fd3,0x0fd7,0x0fda,0x0fde,0x0fe1,0x0fe4,0x0fe7,0x0fea,0x0fec,
0x0fef,0x0ff1,0x0ff3,0x0ff5,0x0ff7,0x0ff8,0x0ffa,0x0ffb,0x0ffc,0x0ffd,0x0ffe,0x0fff,0x0fff,0x1000,0x1000,0x1000
} ;
uint16_t val;
theta &= 0x3ff;
if (theta < 0x100)
val = sintbl[theta];
else
if (theta < 0x200)
val = sintbl [0x200 - theta - 1];
else
if (theta < 0x300)
val = (~sintbl[theta - 0x200] + 1); // negate
else
val = (~sintbl[0x400 - theta -1] + 1); // negate
return val;
}
/*
* Natural-log table. Smallest value is ln(2/4096) -> -7.624618986159398403
* (values smaller than 2/4096 have logs less than -8, which smaller than we
* can represent in our fixed-point format). Largest is 2.0776, which is ln(8)
*/
int16_t fplog( int16_t n )
{
static uint16_t lntbl[512] = {
/*0.00048828*/ 0x8602,0xbdf3,0xc8cc,0xcf34,0xd3c3,0xd74f,0xda36,0xdcaa,0xdecb,0xe0ab,0xe259,0xe3df,0xe542,0xe689,0xe7b8,0xe8d2,
/*0.25048828*/ 0xe9da,0xead2,0xebbb,0xec98,0xed6a,0xee32,0xeef0,0xefa6,0xf054,0xf0fb,0xf19b,0xf236,0xf2ca,0xf35a,0xf3e5,0xf46b,
/*0.50048828*/ 0xf4ed,0xf56b,0xf5e5,0xf65c,0xf6cf,0xf73f,0xf7ac,0xf816,0xf87e,0xf8e3,0xf946,0xf9a6,0xfa04,0xfa60,0xfaba,0xfb12,
/*0.75048828*/ 0xfb68,0xfbbd,0xfc0f,0xfc60,0xfcb0,0xfcfe,0xfd4a,0xfd96,0xfddf,0xfe28,0xfe6f,0xfeb5,0xfefa,0xff3d,0xff80,0xffc2,
/*1.00048828*/ 0x0002,0x0041,0x0080,0x00be,0x00fa,0x0136,0x0171,0x01ab,0x01e4,0x021d,0x0254,0x028b,0x02c2,0x02f7,0x032c,0x0360,
/*1.25048828*/ 0x0394,0x03c6,0x03f9,0x042a,0x045b,0x048c,0x04bc,0x04eb,0x051a,0x0548,0x0576,0x05a3,0x05d0,0x05fc,0x0628,0x0653,
/*1.50048828*/ 0x067e,0x06a9,0x06d3,0x06fc,0x0725,0x074e,0x0776,0x079e,0x07c6,0x07ed,0x0814,0x083a,0x0860,0x0886,0x08ac,0x08d1,
/*1.75048828*/ 0x08f5,0x091a,0x093e,0x0962,0x0985,0x09a8,0x09cb,0x09ee,0x0a10,0x0a32,0x0a54,0x0a75,0x0a96,0x0ab7,0x0ad8,0x0af8,
/*2.00048828*/ 0x0b18,0x0b38,0x0b58,0x0b77,0x0b96,0x0bb5,0x0bd4,0x0bf2,0x0c10,0x0c2e,0x0c4c,0x0c6a,0x0c87,0x0ca4,0x0cc1,0x0cde,
/*2.25048828*/ 0x0cfa,0x0d17,0x0d33,0x0d4f,0x0d6b,0x0d86,0x0da2,0x0dbd,0x0dd8,0x0df3,0x0e0d,0x0e28,0x0e42,0x0e5c,0x0e76,0x0e90,
/*2.50048828*/ 0x0eaa,0x0ec3,0x0edd,0x0ef6,0x0f0f,0x0f28,0x0f41,0x0f59,0x0f72,0x0f8a,0x0fa2,0x0fba,0x0fd2,0x0fea,0x1001,0x1019,
/*2.75048828*/ 0x1030,0x1047,0x105f,0x1075,0x108c,0x10a3,0x10ba,0x10d0,0x10e6,0x10fc,0x1113,0x1129,0x113e,0x1154,0x116a,0x117f,
/*3.00048828*/ 0x1195,0x11aa,0x11bf,0x11d4,0x11e9,0x11fe,0x1213,0x1227,0x123c,0x1250,0x1265,0x1279,0x128d,0x12a1,0x12b5,0x12c9,
/*3.25048828*/ 0x12dc,0x12f0,0x1304,0x1317,0x132a,0x133e,0x1351,0x1364,0x1377,0x138a,0x139d,0x13af,0x13c2,0x13d5,0x13e7,0x13fa,
/*3.50048828*/ 0x140c,0x141e,0x1430,0x1442,0x1454,0x1466,0x1478,0x148a,0x149c,0x14ad,0x14bf,0x14d0,0x14e2,0x14f3,0x1504,0x1515,
/*3.75048828*/ 0x1526,0x1537,0x1548,0x1559,0x156a,0x157b,0x158c,0x159c,0x15ad,0x15bd,0x15ce,0x15de,0x15ee,0x15fe,0x160f,0x161f,
/*4.00048828*/ 0x162f,0x163f,0x164f,0x165e,0x166e,0x167e,0x168e,0x169d,0x16ad,0x16bc,0x16cc,0x16db,0x16ea,0x16fa,0x1709,0x1718,
/*4.25048828*/ 0x1727,0x1736,0x1745,0x1754,0x1763,0x1772,0x1780,0x178f,0x179e,0x17ac,0x17bb,0x17c9,0x17d8,0x17e6,0x17f5,0x1803,
/*4.50048828*/ 0x1811,0x181f,0x182d,0x183c,0x184a,0x1858,0x1866,0x1873,0x1881,0x188f,0x189d,0x18ab,0x18b8,0x18c6,0x18d4,0x18e1,
/*4.75048828*/ 0x18ef,0x18fc,0x1909,0x1917,0x1924,0x1931,0x193f,0x194c,0x1959,0x1966,0x1973,0x1980,0x198d,0x199a,0x19a7,0x19b4,
/*5.00048828*/ 0x19c1,0x19cd,0x19da,0x19e7,0x19f4,0x1a00,0x1a0d,0x1a19,0x1a26,0x1a32,0x1a3f,0x1a4b,0x1a57,0x1a64,0x1a70,0x1a7c,
/*5.25048828*/ 0x1a88,0x1a95,0x1aa1,0x1aad,0x1ab9,0x1ac5,0x1ad1,0x1add,0x1ae9,0x1af5,0x1b01,0x1b0c,0x1b18,0x1b24,0x1b30,0x1b3b,
/*5.50048828*/ 0x1b47,0x1b53,0x1b5e,0x1b6a,0x1b75,0x1b81,0x1b8c,0x1b98,0x1ba3,0x1bae,0x1bba,0x1bc5,0x1bd0,0x1bdc,0x1be7,0x1bf2,
/*5.75048828*/ 0x1bfd,0x1c08,0x1c13,0x1c1e,0x1c29,0x1c34,0x1c3f,0x1c4a,0x1c55,0x1c60,0x1c6b,0x1c76,0x1c80,0x1c8b,0x1c96,0x1ca1,
/*6.00048828*/ 0x1cab,0x1cb6,0x1cc1,0x1ccb,0x1cd6,0x1ce0,0x1ceb,0x1cf5,0x1d00,0x1d0a,0x1d15,0x1d1f,0x1d29,0x1d34,0x1d3e,0x1d48,
/*6.25048828*/ 0x1d53,0x1d5d,0x1d67,0x1d71,0x1d7b,0x1d85,0x1d90,0x1d9a,0x1da4,0x1dae,0x1db8,0x1dc2,0x1dcc,0x1dd6,0x1ddf,0x1de9,
/*6.50048828*/ 0x1df3,0x1dfd,0x1e07,0x1e11,0x1e1a,0x1e24,0x1e2e,0x1e38,0x1e41,0x1e4b,0x1e54,0x1e5e,0x1e68,0x1e71,0x1e7b,0x1e84,
/*6.75048828*/ 0x1e8e,0x1e97,0x1ea1,0x1eaa,0x1eb4,0x1ebd,0x1ec6,0x1ed0,0x1ed9,0x1ee2,0x1eec,0x1ef5,0x1efe,0x1f07,0x1f10,0x1f1a,
/*7.00048828*/ 0x1f23,0x1f2c,0x1f35,0x1f3e,0x1f47,0x1f50,0x1f59,0x1f62,0x1f6b,0x1f74,0x1f7d,0x1f86,0x1f8f,0x1f98,0x1fa1,0x1faa,
/*7.25048828*/ 0x1fb2,0x1fbb,0x1fc4,0x1fcd,0x1fd6,0x1fde,0x1fe7,0x1ff0,0x1ff8,0x2001,0x200a,0x2012,0x201b,0x2024,0x202c,0x2035,
/*7.50048828*/ 0x203d,0x2046,0x204e,0x2057,0x205f,0x2068,0x2070,0x2079,0x2081,0x2089,0x2092,0x209a,0x20a2,0x20ab,0x20b3,0x20bb,
/*7.75048828*/ 0x20c4,0x20cc,0x20d4,0x20dc,0x20e5,0x20ed,0x20f5,0x20fd,0x2105,0x210d,0x2115,0x211d,0x2126,0x212e,0x2136,0x213e
} ;
return (n >= 0x0002) ? lntbl[ (n - 2) >> 6 ] : 0x8000;
}
/*
* Exponential table -- from -8.0 to 2.xxx. Layout is tricky.
*/
int16_t fpexp( int16_t n ) {
static int16_t pos_exp[] = {
/*0000*/ 0x1000,0x1041,0x1082,0x10c5,0x1108,0x114d,0x1193,0x11d9,0x1221,0x126a,0x12b5,0x1300,0x134d,0x139b,0x13ea,0x143a,
/*0400*/ 0x148b,0x14de,0x1532,0x1588,0x15df,0x1637,0x1690,0x16eb,0x1748,0x17a5,0x1805,0x1866,0x18c8,0x192c,0x1991,0x19f8,
/*0800*/ 0x1a61,0x1acc,0x1b38,0x1ba5,0x1c15,0x1c86,0x1cf9,0x1d6e,0x1de4,0x1e5d,0x1ed7,0x1f54,0x1fd2,0x2052,0x20d4,0x2159,
/*0c00*/ 0x21df,0x2268,0x22f2,0x237f,0x240e,0x24a0,0x2533,0x25c9,0x2662,0x26fd,0x279a,0x2839,0x28dc,0x2980,0x2a28,0x2ad1,
/*1000*/ 0x2b7e,0x2c2d,0x2ce0,0x2d94,0x2e4c,0x2f07,0x2fc4,0x3085,0x3149,0x320f,0x32d9,0x33a6,0x3476,0x354a,0x3621,0x36fb,
/*1400*/ 0x37d8,0x38ba,0x399e,0x3a87,0x3b72,0x3c62,0x3d56,0x3e4d,0x3f48,0x4047,0x414a,0x4251,0x435d,0x446c,0x4580,0x4698,
/*1800*/ 0x47b5,0x48d6,0x49fc,0x4b26,0x4c55,0x4d89,0x4ec1,0x4fff,0x5141,0x5289,0x53d6,0x5527,0x567f,0x57db,0x593e,0x5aa5,
/*1c00*/ 0x5c13,0x5d86,0x5eff,0x607e,0x6203,0x638e,0x6520,0x66b7,0x6855,0x69fa,0x6ba5,0x6d57,0x6f10,0x70d0,0x7296,0x7464
} ;
static int16_t neg_exp[] = {
/*8000*/ 0x0001,0x0001,0x0001,0x0001,0x0001,0x0001,0x0002,0x0002,0x0002,0x0002,0x0002,0x0002,0x0002,0x0002,0x0002,0x0002,
/*8400*/ 0x0002,0x0002,0x0002,0x0002,0x0002,0x0002,0x0002,0x0002,0x0002,0x0002,0x0002,0x0002,0x0002,0x0002,0x0002,0x0002,
/*8800*/ 0x0002,0x0002,0x0002,0x0002,0x0002,0x0002,0x0002,0x0003,0x0003,0x0003,0x0003,0x0003,0x0003,0x0003,0x0003,0x0003,
/*8c00*/ 0x0003,0x0003,0x0003,0x0003,0x0003,0x0003,0x0003,0x0003,0x0003,0x0003,0x0003,0x0003,0x0004,0x0004,0x0004,0x0004,
/*9000*/ 0x0004,0x0004,0x0004,0x0004,0x0004,0x0004,0x0004,0x0004,0x0004,0x0004,0x0004,0x0004,0x0005,0x0005,0x0005,0x0005,
/*9400*/ 0x0005,0x0005,0x0005,0x0005,0x0005,0x0005,0x0005,0x0005,0x0005,0x0006,0x0006,0x0006,0x0006,0x0006,0x0006,0x0006,
/*9800*/ 0x0006,0x0006,0x0006,0x0006,0x0007,0x0007,0x0007,0x0007,0x0007,0x0007,0x0007,0x0007,0x0007,0x0008,0x0008,0x0008,
/*9c00*/ 0x0008,0x0008,0x0008,0x0008,0x0008,0x0009,0x0009,0x0009,0x0009,0x0009,0x0009,0x0009,0x000a,0x000a,0x000a,0x000a,
/*a000*/ 0x000a,0x000a,0x000a,0x000b,0x000b,0x000b,0x000b,0x000b,0x000c,0x000c,0x000c,0x000c,0x000c,0x000c,0x000d,0x000d,
/*a400*/ 0x000d,0x000d,0x000d,0x000e,0x000e,0x000e,0x000e,0x000f,0x000f,0x000f,0x000f,0x000f,0x0010,0x0010,0x0010,0x0010,
/*a800*/ 0x0011,0x0011,0x0011,0x0012,0x0012,0x0012,0x0012,0x0013,0x0013,0x0013,0x0014,0x0014,0x0014,0x0015,0x0015,0x0015,
/*ac00*/ 0x0015,0x0016,0x0016,0x0017,0x0017,0x0017,0x0018,0x0018,0x0018,0x0019,0x0019,0x001a,0x001a,0x001a,0x001b,0x001b,
/*b000*/ 0x001c,0x001c,0x001c,0x001d,0x001d,0x001e,0x001e,0x001f,0x001f,0x0020,0x0020,0x0021,0x0021,0x0022,0x0022,0x0023,
/*b400*/ 0x0023,0x0024,0x0025,0x0025,0x0026,0x0026,0x0027,0x0028,0x0028,0x0029,0x0029,0x002a,0x002b,0x002b,0x002c,0x002d,
/*b800*/ 0x002e,0x002e,0x002f,0x0030,0x0030,0x0031,0x0032,0x0033,0x0034,0x0034,0x0035,0x0036,0x0037,0x0038,0x0039,0x003a,
/*bc00*/ 0x003a,0x003b,0x003c,0x003d,0x003e,0x003f,0x0040,0x0041,0x0042,0x0043,0x0044,0x0045,0x0046,0x0048,0x0049,0x004a,
/*c000*/ 0x004b,0x004c,0x004d,0x004f,0x0050,0x0051,0x0052,0x0054,0x0055,0x0056,0x0058,0x0059,0x005a,0x005c,0x005d,0x005f,
/*c400*/ 0x0060,0x0062,0x0063,0x0065,0x0067,0x0068,0x006a,0x006b,0x006d,0x006f,0x0071,0x0072,0x0074,0x0076,0x0078,0x007a,
/*c800*/ 0x007c,0x007e,0x0080,0x0082,0x0084,0x0086,0x0088,0x008a,0x008c,0x008e,0x0091,0x0093,0x0095,0x0098,0x009a,0x009c,
/*cc00*/ 0x009f,0x00a1,0x00a4,0x00a6,0x00a9,0x00ac,0x00ae,0x00b1,0x00b4,0x00b7,0x00ba,0x00bd,0x00c0,0x00c3,0x00c6,0x00c9,
/*d000*/ 0x00cc,0x00cf,0x00d2,0x00d6,0x00d9,0x00dc,0x00e0,0x00e3,0x00e7,0x00eb,0x00ee,0x00f2,0x00f6,0x00fa,0x00fe,0x0102,
/*d400*/ 0x0106,0x010a,0x010e,0x0112,0x0117,0x011b,0x0120,0x0124,0x0129,0x012d,0x0132,0x0137,0x013c,0x0141,0x0146,0x014b,
/*d800*/ 0x0150,0x0156,0x015b,0x0160,0x0166,0x016c,0x0171,0x0177,0x017d,0x0183,0x0189,0x018f,0x0196,0x019c,0x01a2,0x01a9,
/*dc00*/ 0x01b0,0x01b7,0x01bd,0x01c4,0x01cc,0x01d3,0x01da,0x01e2,0x01e9,0x01f1,0x01f9,0x0201,0x0209,0x0211,0x0219,0x0222,
/*e000*/ 0x022a,0x0233,0x023c,0x0245,0x024e,0x0257,0x0261,0x026a,0x0274,0x027e,0x0288,0x0292,0x029d,0x02a7,0x02b2,0x02bd,
/*e400*/ 0x02c8,0x02d3,0x02de,0x02ea,0x02f6,0x0302,0x030e,0x031a,0x0327,0x0333,0x0340,0x034d,0x035b,0x0368,0x0376,0x0384,
/*e800*/ 0x0392,0x03a0,0x03af,0x03be,0x03cd,0x03dc,0x03ec,0x03fc,0x040c,0x041c,0x042d,0x043d,0x044e,0x0460,0x0471,0x0483,
/*ec00*/ 0x0496,0x04a8,0x04bb,0x04ce,0x04e1,0x04f5,0x0509,0x051d,0x0532,0x0547,0x055c,0x0572,0x0588,0x059e,0x05b4,0x05cb,
/*f000*/ 0x05e3,0x05fb,0x0613,0x062b,0x0644,0x065d,0x0677,0x0691,0x06ab,0x06c6,0x06e2,0x06fd,0x071a,0x0736,0x0753,0x0771,
/*f400*/ 0x078f,0x07ad,0x07cc,0x07ec,0x080c,0x082c,0x084d,0x086e,0x0890,0x08b3,0x08d6,0x08fa,0x091e,0x0943,0x0968,0x098e,
/*f800*/ 0x09b4,0x09db,0x0a03,0x0a2c,0x0a55,0x0a7e,0x0aa9,0x0ad3,0x0aff,0x0b2b,0x0b58,0x0b86,0x0bb5,0x0be4,0x0c14,0x0c45,
/*fc00*/ 0x0c76,0x0ca8,0x0cdb,0x0d0f,0x0d44,0x0d79,0x0daf,0x0de7,0x0e1f,0x0e58,0x0e91,0x0ecc,0x0f08,0x0f44,0x0f82,0x0fc0
} ;
if (n >= 0 && n < 0x2000) return pos_exp[n >> 6];
if (n < 0) return neg_exp[ (uint16_t(n) - 0x8000u) >> 6 ];
cerr << "can't compute exp( 0x" << hex << n << " " << fp2str( n ) << ")" << endl;
exit( 0 );
}
int
main( int, char ** )
{
#ifdef TESTING
for (uint16_t a = 2; a < 0x7000; a += 0x0529) {
cout << "ln(" << fp2str(a) << " (0x" << hex << a << ")) = "
<< fp2str( fplog( a ) ) << " ... " << log( double(a) / double(0x1000) ) << endl;
}
for (uint16_t a = 0; a < 0x2000; a += 0x0727) {
cout << "exp(" << fp2str(a) << " (0x" << hex << a << ")) = "
<< fp2str( fpexp( a ) ) << " ... " << exp( double(a) / double(0x1000) ) << endl;
}
for (int16_t a = -1; a > -30000; a -= 0x0ab7) {
cout << "exp(" << fp2str(a) << " (0x" << hex << a << ")) = "
<< fp2str( fpexp( a ) ) << " ... " << exp( double(a) / double(0x1000) ) << endl;
}
for (uint16_t a = 10; a < 0x7fff; a += 0x0ab7) {
cout << "exp( log(" << fp2str(a) << " (0x" << hex << a << "))) = "
<< fp2str( fpexp( fplog( a ) ) ) << endl;
}
#else
// Implementation of y = (1/2 * (1 + sin( x ))) ^ n is left as an exercise for the reader.
// Note that fplog() doesn't work on numbers smaller than 2/4096, and fpexp() doesn't work
// on numbers larger than about (2 - 1/4096)
#endif
return 0;
}
我用这个 Perl 脚本生成了查找表:
#!/usr/bin/perl -w
use Math::Trig ':pi';
use POSIX;
#
# Fixed-point values have 12 fractional bits ... 2^12 => 4096
#
my $LSB = 1.0 / 4096.0;
#
# print sin table values
#
if (0) {
for ($i = 0; $i < 0x100; $i += 1) {
$s = sin( $i * pip2 / 255 );
printf( "0x%04x,", POSIX::floor( 0x1000 * $s + 0.5) );
print "\n" if (($i & 15) == 15);
}
}
#
# print log table values
#
if (0) {
$x = $LSB * 2.0;
for ($n = 0; $n < 32000; ++$n) {
printf( "/*%10.8f*/ ", $x ) if (($n & 15) == 0);
printf( "0x%04x,", POSIX::floor( 0x1000 * log($x) + 0.5) & 0xffff );
print "\n" if (($n & 15) == 15);
$x += $LSB * 64.0;
last if ($x >= 8.0);
}
}
#
# print exp table values -- this is tricky because we want all the negative
# numbers (0xffff ~ 0x8000) but only positive numbers between 0x0000 and 0x2000.
#
if (1) {
for ($n = 0; $n < 0x2000; $n += 64) {
printf( "/*%04x*/ ", $n & 0xffff ) if ((($n >> 6) & 15) == 0);
# printf( "%8.5f,", $n / 4096.0 );
printf( "0x%04x,", POSIX::floor( exp( $n / 4096.0 ) * 0x1000 + 0.5 ) );
print "\n" if ((($n >> 6) & 15) == 15);
}
print "\n\n";
for ($n = -32768; $n < 0; $n += 64) {
printf( "/*%04x*/ ", $n & 0xffff ) if ((($n >> 6) & 15) == 0);
# printf( "%8.5f,", $n / 4096.0 );
printf( "0x%04x,", POSIX::floor( exp( $n / 4096 ) * 0x1000 + 0.5 ) );
print "\n" if ((($n >> 6) & 15) == 15);
}
}
棘手的一点是将信号移动和缩放到 fplog()
和 fpexp()
工作得相当好的范围。你会做一个 16x16->32 的乘法来取幂,所以我想你会把高 16 位作为你的定点数,你将它提供给 fpexp()
以获得最终输出。
Does anyone have an idea how to realize such a shape modification only with integer math?
n
could also have a range of 1 to 10 for example$y(x) = (1/2*(1 + sin(x)))^n$
OP 有一个正弦近似函数 sin_bam()
,然后用它来形成 1/2*(1 + sin(x))
,即 hacovercosin(θ)。剩下的就是比例幂函数。
#include <inttypes.h>
#define SCALE 16384
int pow_scale(int x, unsigned n) {
unsigned y = SCALE;
while (n>0) {
if (n%2) {
y = unsigned_mult16x16_into_32(x,y)/SCALE; // 16-bit x 16-bit --> 32-bit product.
}
n /= 2;
x = unsigned_mult16x16_into_32(x,x)/SCALE;
}
return x;
}
// x is the angle in 1024 BAM per period
// output is scaled to range [0....SCALE]
int shaped(int x, unsigned n) {
return pow_scale(SCALE/2 + sin_bam(x)/2), n);
}