Example #1
0
 def calcConsts(cls, fam, famOnly=False):
     consts = [ fam.pi ]
     if not famOnly:
         consts.append(6 * FXnum(0.5, fam).asin())
         consts.append(4 *  ( 4 * (1 / FXnum(5, fam)).atan()
                             - (1 / FXnum(239, fam)).atan() ))
     return consts
Example #2
0
    def testIntRange(self):
        """Check detection of overflow of integer part."""
        for top in [-3, -2, 0, 2, 4, 6]:
            fam = FXfamily(16, top)
            a = FXnum(1.0 / 16.01, fam)
            zero = FXnum(0, fam)
            limit = 1 << (top + 4 - 1)  # Unlikely to be valid FXnum(,fam)

            cnt, x, y = 0, zero, zero
            while cnt < (limit + 5):
                cnt += 1

                try:
                    x += a
                except FXoverflowError:
                    if cnt <= limit: self.fail()
                else:
                    if cnt > limit: self.fail()

                try:
                    y -= a
                except FXoverflowError:
                    if cnt <= limit: self.fail()
                else:
                    if cnt > limit: self.fail()
Example #3
0
 def testFamilyProtection(self):
     """Check that arithmetic operators do not transmute resolution families"""
     famlist = [FXfamily(res) for res in [8, 16, 40, 90]]
     for fam0 in famlist:
         for fam1 in famlist:
             x = FXnum(2, fam0)
             y = FXnum(3, fam1)
             try:
                 a = x + y
             except FXfamilyError:
                 self.assertFalse(fam0 is fam1)
             else:
                 self.assertTrue(fam0 is fam1)
             try:
                 a = x - y
             except FXfamilyError:
                 self.assertFalse(fam0 is fam1)
             else:
                 self.assertTrue(fam0 is fam1)
             try:
                 a = x * y
             except FXfamilyError:
                 self.assertFalse(fam0 is fam1)
             else:
                 self.assertTrue(fam0 is fam1)
             try:
                 a = x / y
             except FXfamilyError:
                 self.assertFalse(fam0 is fam1)
             else:
                 self.assertTrue(fam0 is fam1)
Example #4
0
    def testMultiplication(self):
        """Multiplication operators should promote & commute"""
        scale = 0.25
        scale2 = scale * scale
        for x in range(-16, 32):
            fpx = FXnum(x * scale)
            for y in range(-32, 16):
                fpy = FXnum(y * scale)
                fpa = FXnum((x * y) * scale2)

                # compute various forms of a = (x * y):

                self.assertEqual(fpa, fpx * fpy)
                self.assertEqual(fpa, fpy * fpx)
                self.assertEqual((x * y) * scale2, float(fpx * fpy))

                tmp = fpx
                tmp *= fpy
                self.assertEqual(fpa, tmp)

                tmp = float(x * scale) * fpy
                self.assertEqual(fpa, tmp)

                tmp = fpx * float(y * scale)
                self.assertEqual(fpa, tmp)
Example #5
0
    def testDivision(self):
        """Division operators should promote & inverse-commute"""
        fam62 = FXfamily(62)
        scale = 0.125
        scale2 = scale * scale
        for a in range(-32, 32):
            if a == 0: continue
            fpa = FXnum(a * scale, fam62)
            for y in range(-16, 16):
                if y == 0: continue
                fpy = FXnum(y * scale, fam62)
                fpx = FXnum((y * a) * scale2, fam62)

                # compute various forms of a = (x / y):

                self.assertAlmostEqual(fpa, fpx / fpy)
                self.assertAlmostEqual(1 / fpa, fpy / fpx)
                self.assertAlmostEqual((a * scale), float(fpx / fpy))

                tmp = fpx
                tmp /= fpy
                self.assertAlmostEqual(fpa, tmp)

                tmp = float(a * y * scale2) / fpy
                self.assertAlmostEqual(fpa, tmp)

                tmp = fpx / float(y * scale)
                self.assertAlmostEqual(fpa, tmp)
Example #6
0
 def testBoolConditions(self):
     """Values used in boolean expressions should behave as true/false"""
     if FXnum(0):
         self.fail()
     if FXnum(1):
         pass
     else:
         self.fail()
Example #7
0
 def testRawBuild(self):
     """Check equivalence of FXnum._rawbuild() and FXnum()."""
     fam = FXfamily(10, 5)
     x = FXnum(val=9.7531, family=fam)
     xraw = FXnum._rawbuild(fam, x.scaledval)
     self.assertEqual(x, xraw)
     self.assertIsInstance(x, FXnum)
     self.assertIsInstance(xraw, FXnum)
     self.assertIsNot(x, xraw)
Example #8
0
 def testRepresentation(self):
     """Check repr() functionality"""
     for i in range(1, 30):
         v = 1.7**i
         for x in [v, -v, 1.0 / v, -1.0 / v]:
             fp0 = FXnum(x)
             # ensure that value extracted via repr() is in same FXfamily:
             fpb = FXnum(eval(repr(fp0)), family=fp0.family)
             self.assertEqual(fp0, fpb)
Example #9
0
 def testPrinting(self):
     """Check conversion to string"""
     for i in range(1, 10):
         v = 2**i
         for x in [v, -v, 1.0 / v, -1.0 / v]:
             plainstr = "%.8g" % x
             fpx = FXnum(x)
             self.assertEqual('{:.8g}'.format(x), str(fpx))
             self.assertEqual(str(fpx), fpx.toDecimalString())
Example #10
0
 def testExpLog(self):
     """exp and log methods should be inverses & agree with math.*"""
     fam62 = FXfamily(62)
     scale = 0.27
     for i in range(-32, 32):
         x = i * scale
         exp = FXnum(x, fam62).exp()
         logexp = exp.log()
         self.assertAlmostEqual(x, float(logexp))
Example #11
0
 def testExpLog(self):
     """exp and log methods should be inverses & agree with math.*"""
     fam62 = FXfamily(62)
     scale = 0.27
     for i in range(-32, 32):
         x = i * scale
         exp = FXnum(x, fam62).exp()
         logexp = exp.log()
         self.assertAlmostEqual(x, float(logexp))
Example #12
0
 def testPrinting(self):
     """Check conversion to string"""
     for i in range(1, 10):
         v = 2 ** i
         for x in [v, -v, 1.0/v, -1.0/v]:
             plainstr = "%.8g" % x
             fpx = FXnum(x)
             self.assertEqual('{:.8g}'.format(x), str(fpx))
             self.assertEqual(str(fpx), fpx.toDecimalString())
Example #13
0
    def testArctan(self):
        """atan method agree with math.sin/cos"""
        fam62 = FXfamily(62)
        scale = 0.277

        self.assertEqual(FXnum(0, fam62), 0)

        for i in range(-32, 32):
            tan = i * scale
            ang_true = math.atan(tan)
            ang = FXnum(tan, fam62).atan()
            self.assertAlmostEqual(ang_true, ang)
            self.assertAlmostEqual(float(ang.tan()), tan)
Example #14
0
    def testArctan(self):
        """atan method agree with math.sin/cos"""
        fam62 = FXfamily(62)
        scale = 0.277

        self.assertEqual(FXnum(0, fam62), 0)

        for i in range(-32, 32):
            tan = i * scale
            ang_true = math.atan(tan)
            ang = FXnum(tan, fam62).atan()
            self.assertAlmostEqual(ang_true, ang)
            self.assertAlmostEqual(float(ang.tan()), tan)
Example #15
0
 def testNegating(self):
     """Check prefix operators"""
     fam17 = FXfamily(17)
     for i in range(-32, 32):
         x = i * 0.819
         fx = FXnum(x, fam17)
         zero = FXnum(0, fam17)
         try:
             self.assertEqual(zero, fx + (-fx))
             self.assertEqual(zero, -fx + fx)
             self.assertEqual((-1 * fx), -fx)
             self.assertEqual(zero, (-1 * fx) + (-fx) + 2 * (+fx))
         except FXexception:
             self.fail()
Example #16
0
    def next_sample(self, fcw: int) -> NCOType:
        lut_index = (self.phase_acc >> (self.N - self.M)) & int(
            '1' * self.M, 2)  # take MSB M bits of phase_acc
        samples = []
        for lut in [
                self.sine_lut_fixed, self.square_lut_fixed,
                self.triangle_lut_fixed, self.sawtooth_lut_fixed
        ]:
            if self.interpolate is False:
                samples.append(lut[lut_index])
            else:
                samp1 = lut[lut_index]
                samp2 = lut[(lut_index + 1) % self.lut_entries]
                residual = self.phase_acc & int(
                    '1' *
                    (self.N - self.M), 2)  # take LSB (N-M) bits of phase_acc
                residual = FXnum(
                    residual / (2**(self.N - self.M)),
                    family=self.output_type)  # Cast residual as fixed point
                diff = samp2 - samp1
                samples.append(samp1 + residual * diff)

        self.phase_acc = self.phase_acc + fcw
        self.phase_acc = self.phase_acc % 2**self.N  # overflow on N bits
        return samples
Example #17
0
    def testPow(self):
        """Check raising FXnums to powers."""
        fam62 = FXfamily(62)
        scale = 0.205
        scale2 = 0.382
        for i in range(1, 32):
            x = i * scale

            pwr = FXnum(0, fam62)**x
            self.assertEqual(FXnum(1, fam62), pwr)

            for j in range(-16, 16):
                y = j * scale2
                pwr_true = math.pow(x, y)
                pwr = FXnum(x, fam62)**y
                self.assertAlmostEqual(pwr_true, pwr)
Example #18
0
 def testArcSinCos(self):
     """asin/acos methods should be inverses of sin/cos"""
     fam62 = FXfamily(62)
     trig = FXnum(0, fam62)
     self.assertEqual(trig, trig.asin())
     self.assertEqual(trig, FXnum(1,fam62).acos())
     steps = 20
     for i in range(0, steps + 1):
         for s in [-1.0, 1.0]:
             trig = FXnum((i * s) / steps, fam62)
             isn = trig.asin()
             self.assertTrue(abs(isn) <= fam62.pi / 2)
             self.assertAlmostEqual(float(trig), float(isn.sin()))
             ics = trig.acos()
             self.assertTrue(0 <= ics and ics <= fam62.pi)
             self.assertAlmostEqual(float(trig), float(ics.cos()))
Example #19
0
 def testSqrt(self):
     """sqrt method should find square-roots"""
     fam62 = FXfamily(62)
     scale = 0.94
     for i in range(-40, 40):
         x = i * scale
         fx = FXnum(x, fam62)
         try:
             rt = fx.sqrt()
         except FXdomainError:
             self.assertFalse(x >= 0)
         else:
             rt2 = float(rt * rt)
             self.assertAlmostEqual(x, rt2)
             if i == 0:
                 self.assertEqual(FXnum(0, fam62), rt)
Example #20
0
 def next_sample(self) -> int:
     nco_out = self.nco.next_sample_f(self.note_freq)
     summer_out = self.summer.next_sample(nco_out)
     if self.playing_note:
         return summer_out
     else:
         return FXnum(0, output_type)
Example #21
0
 def testSqrt(self):
     """sqrt method should find square-roots"""
     fam62 = FXfamily(62)
     scale = 0.94
     for i in range(-40, 40):
         x = i * scale
         fx = FXnum(x, fam62)
         try:
             rt = fx.sqrt()
         except FXdomainError:
             self.assertFalse(x >= 0)
         else:
             rt2 = float(rt * rt)
             self.assertAlmostEqual(x, rt2)
             if i == 0:
                 self.assertEqual(FXnum(0, fam62), rt)
Example #22
0
    def testDecimalRound(self):
        third = FXnum(1, FXfamily(200)) / 3
        x23 = 2 * third

        self.assertEqual(third.toDecimalString(precision=5), '0.33333')
        self.assertEqual(third.toDecimalString(precision=8, round10=True),
                         '0.33333333')

        self.assertEqual(x23.toDecimalString(precision=4), '0.6666')
        self.assertEqual(x23.toDecimalString(precision=7, round10=True),
                         '0.6666667')

        self.assertEqual(x23.toDecimalString()[:42], '0.' + '6' * 40)
        self.assertEqual(x23.toDecimalString(precision=50), '0.' + '6' * 50)
        self.assertEqual(x23.toDecimalString(precision=50, round10=True),
                         '0.' + '6' * 49 + '7')
Example #23
0
    def testBinarySeries(self):
        """Check binary printing of enumerated signed integers."""
        for res in range(1, 5):
            fam = FXfamily(res)
            for scaled in range(1 << (res + 4)):
                pos = FXnum(family=fam, scaled_value=scaled)

                for sign in ((1, -1) if scaled > 0 else (1, )):
                    printed = (sign * pos).toBinaryString()

                    if sign > 0:
                        x = scaled
                    else:
                        if scaled < (1 << res):
                            shift = res + 1
                        else:
                            shift = math.ceil(math.log2(scaled)) + 1
                        x = (1 << shift) - scaled
                    binstr = bin(x)[2:]
                    pad = res + 1 - len(binstr)
                    if pad > 0: binstr = '0' * pad + binstr
                    binstr = binstr[:-res] + '.' + binstr[-res:]
                    self.assertEqual(binstr, printed,
                                     'Binary printing failed for {}, res={}' \
                                        .format(float(sign * pos), res))
Example #24
0
 def testPrinting(self):
     """Check conversion to string"""
     for i in range(1, 10):
         v = 2**i
         for x in [v, -v, 1.0 / v, -1.0 / v]:
             fpa = "%.8g" % x
             fpx = str(FXnum(x))
             self.assertEqual(fpa, fpx)
Example #25
0
 def testSinCos(self):
     """sin/cos methods agree with math.sin/cos"""
     fam62 = FXfamily(62)
     scale = 0.342
     fang = FXnum(0, fam62)
     self.assertEqual(fang, fang.sin())
     self.assertEqual(FXnum(1, fam62), fang.cos())
     for i in range(-32, 32):
         x = i * scale
         sin_true = math.sin(x)
         cos_true = math.cos(x)
         fang = FXnum(x, fam62)
         (sin, cos) = fang.sincos()
         self.assertAlmostEqual(sin_true, sin)
         self.assertAlmostEqual(cos_true, cos)
         self.assertEqual(sin, fang.sin())
         self.assertEqual(cos, fang.cos())
Example #26
0
    def testNegatives(self):
        fam = FXfamily(3)

        x2 = FXnum(-0.25, fam)
        self.assertEqual(x2.toBinaryString(), '1.110')
        self.assertEqual(x2.toBinaryString(twosComp=False), '-0.010')

        x3 = FXnum(-0.625, fam)
        self.assertEqual(x3.toBinaryString(logBase=3), '7.3')
        self.assertEqual(x3.toBinaryString(3, twosComp=False), '-0.5')

        x4 = FXnum(-0.875, fam)
        self.assertEqual(x4.toBinaryString(4), 'f.2')
        self.assertEqual(x4.toBinaryString(4, twosComp=False), '-0.e')
Example #27
0
    def testDecimalRound(self):
        third = FXnum(1, FXfamily(200)) / 3
        x23 = 2 * third

        self.assertEqual(third.toDecimalString(precision=5), '0.33333')
        self.assertEqual(third.toDecimalString(precision=8, round10=True),
                         '0.33333333')

        self.assertEqual(x23.toDecimalString(precision=4), '0.6666')
        self.assertEqual(x23.toDecimalString(precision=7, round10=True),
                         '0.6666667')

        self.assertEqual(x23.toDecimalString()[:42],
                         '0.' + '6'*40)
        self.assertEqual(x23.toDecimalString(precision=50),
                         '0.' + '6'*50)
        self.assertEqual(x23.toDecimalString(precision=50, round10=True),
                         '0.' + '6' * 49 + '7')
Example #28
0
 def testFamilyConversion(self):
     """Check that conversion between families preserves values"""
     famlist = [FXfamily(b) for b in [32, 40, 48, 80, 120]]
     for i in range(1, 10):
         xpos = (float)(1 << (2 * i)) + 1.0 / (1 << i)
         for x in [xpos, -xpos]:
             for fam0 in famlist:
                 fp0 = FXnum(x, fam0)
                 for fam1 in famlist:
                     fp1 = FXnum(fp0, fam1)
                     try:
                         f = (fp0 == fp1)
                     except FXfamilyError:
                         self.assertFalse(fam0 is fam1)
                     else:
                         self.assertTrue(fam0 is fam1)
                     self.assertAlmostEqual(x, float(fp0))
                     self.assertAlmostEqual(x, float(fp1))
Example #29
0
 def testRawBuild(self):
     """Check equivalence of FXnum._rawbuild() and FXnum()."""
     fam = FXfamily(10, 5)
     x = FXnum(val=9.7531, family=fam)
     xraw = FXnum._rawbuild(fam, x.scaledval)
     self.assertEqual(x, xraw)
     self.assertIsInstance(x, FXnum)
     self.assertIsInstance(xraw, FXnum)
     self.assertIsNot(x, xraw)
Example #30
0
 def testExp(self):
     """Exponent method should agree with math.exp"""
     fam62 = FXfamily(62)
     scale = 0.23
     for i in range(-32, 32):
         x = i * scale
         exp_true = math.exp(x)
         exp = FXnum(x, fam62).exp()
         self.assertAlmostEqual(exp_true, exp)
Example #31
0
    def testNumCreateRounding(self):
        """Check rounding behaviour on FXnum creation"""
        fam = FXfamily(3)
        self.assertEqual(FXnum(0.375, fam).scaledval, 3)
        self.assertEqual(FXnum(0.437, fam).scaledval, 3)
        self.assertEqual(FXnum(0.438, fam).scaledval, 4)
        self.assertEqual(FXnum(0.46, fam).scaledval, 4)

        fam = FXfamily(4)
        self.assertEqual(FXnum(-0.75, fam).scaledval, -12)
        self.assertEqual(FXnum(-0.78124, fam).scaledval, -12)
        self.assertEqual(FXnum(-0.78126, fam).scaledval, -13)
        self.assertEqual(FXnum(-0.8125, fam).scaledval, -13)
Example #32
0
 def testLog(self):
     """Logarithm method agree with math.log"""
     fam62 = FXfamily(62)
     base = 1.5
     for i in range(1, 32):
         for j in range(0, 2):
             if j == 0:
                 x = 1.0 / (base**i)
             else:
                 x = base**i
             log_true = math.log(x)
             log = FXnum(x, fam62).log()
             self.assertAlmostEqual(log_true, log)
Example #33
0
    def __init__(self, fsamp: float, interpolate: bool) -> None:
        self.fsamp = fsamp
        self.interpolate = interpolate
        self.output_type = output_type
        self.phase_acc = 0  # type: int
        self.N = 24
        self.M = 8
        self.lut_entries = 2**self.M

        self.sine_lut_float = [
            np.sin(i * 2 * np.pi / self.lut_entries)
            for i in range(self.lut_entries)
        ]
        self.sine_lut_fixed = [
            FXnum(x, family=self.output_type) for x in self.sine_lut_float
        ]

        self.square_lut_fixed = [FXnum(1, family=self.output_type) for x in range(int(self.lut_entries/2))] + \
            [FXnum(-1, family=self.output_type) for x in range(int(self.lut_entries/2))]

        self.triangle_lut_float = [
            np.max(1 - np.abs(x)) for x in np.linspace(-1, 1, self.lut_entries)
        ]
        self.triangle_lut_float = [x * 2 - 1 for x in self.triangle_lut_float
                                   ]  # scale to range from -1 to 1
        self.triangle_lut_fixed = [
            FXnum(x, family=self.output_type) for x in self.triangle_lut_float
        ]

        self.sawtooth_lut_float = [
            x - np.floor(x)
            for x in np.linspace(0, 1 - 1e-16, self.lut_entries)
        ]
        self.sawtooth_lut_float = [x * 2 - 1 for x in self.sawtooth_lut_float
                                   ]  # scaling again
        self.sawtooth_lut_fixed = [
            FXnum(x, family=self.output_type) for x in self.sawtooth_lut_float
        ]
Example #34
0
    def testAddition(self):
        """Addition operators should promote & commute"""
        scale = 0.125
        for x in range(-16, 16):
            fpx = FXnum(x * scale)
            for y in range(-32, 32):
                fpy = FXnum(y * scale)
                fpa = FXnum((x + y) * scale)

                # compute various forms of a = (x + y):

                self.assertEqual(fpa, fpx + fpy)
                self.assertEqual(fpa, fpy + fpx)
                self.assertEqual((x + y) * scale, float(fpx + fpy))

                tmp = fpx
                tmp += fpy
                self.assertEqual(fpa, tmp)

                tmp = float(x * scale) + fpy
                self.assertEqual(fpa, tmp)

                tmp = fpx + float(y * scale)
                self.assertEqual(fpa, tmp)
Example #35
0
    def testSubtraction(self):
        """Subtraction operators should promote & anti-commute"""
        scale = 0.0625
        for x in range(-32, 16):
            fpx = FXnum(x * scale)
            for y in range(-16, 32):
                fpy = FXnum(y * scale)
                fpa = FXnum((x - y) * scale)

                # compute various forms of a = (x - y):

                self.assertEqual(fpa, fpx - fpy)
                self.assertEqual(-fpa, fpy - fpx)
                self.assertEqual((x - y) * scale, float(fpx - fpy))

                tmp = fpx
                tmp -= fpy
                self.assertEqual(fpa, tmp)

                tmp = float(x * scale) - fpy
                self.assertEqual(fpa, tmp)

                tmp = fpx - float(y * scale)
                self.assertEqual(fpa, tmp)
Example #36
0
    def testBitShifts(self):
        """Check effects of left & right shift operators."""
        fam = FXfamily(32)

        self.assertEqual(FXnum(1, fam) << 2, 4)
        self.assertEqual(FXnum(3, fam) << 4, 48)
        self.assertEqual(FXnum(-7, fam) << 8, -7 * 256)

        self.assertEqual(FXnum(1, fam) >> 1, 0.5)
        self.assertEqual(FXnum(12, fam) >> 2, 3)
        self.assertEqual(FXnum(-71 * 1024, fam) >> 12, -17.75)
Example #37
0
 def testSinCos(self):
     """sin/cos methods agree with math.sin/cos"""
     fam62 = FXfamily(62)
     scale = 0.342
     fang = FXnum(0, fam62)
     self.assertEqual(fang, fang.sin())
     self.assertEqual(FXnum(1,fam62), fang.cos())
     for i in range(-32, 32):
         x = i * scale
         sin_true = math.sin(x)
         cos_true = math.cos(x)
         fang = FXnum(x, fam62)
         (sin, cos) = fang.sincos()
         self.assertAlmostEqual(sin_true, sin)
         self.assertAlmostEqual(cos_true, cos)
         self.assertEqual(sin, fang.sin())
         self.assertEqual(cos, fang.cos())
Example #38
0
    def testPowSpecials(self):
        """Check raising of special values to powers."""
        fam30 = FXfamily(30)

        for i in range(1, 30):
            # Check x^0 == 1
            self.assertEqual(FXnum(i * 0.2, fam30)**0, fam30.unity)

            # Check 0^n == 0
            self.assertEqual(fam30.zero**i, fam30.zero)

            # Check 0^x == 0
            self.assertEqual(fam30.zero**(i * 0.27), fam30.zero)

            # Check 0^-x
            with self.assertRaises(FXdomainError):
                fam30.zero**(1 - i)
            with self.assertRaises(FXdomainError):
                fam30.zero**-(i * 0.23)
Example #39
0
    def testArcSinCos(self):
        """asin/acos methods should be inverses of sin/cos"""
        fam62 = FXfamily(62)

        trig = FXnum(0, fam62)
        self.assertEqual(trig, trig.asin())
        self.assertEqual(trig, FXnum(1, fam62).acos())

        steps = 20
        for i in range(0, steps + 1):
            for s in [-1.0, 1.0]:
                trig = FXnum((i * s) / steps, fam62)

                isn = trig.asin()
                self.assertTrue(abs(isn) <= fam62.pi / 2)
                self.assertAlmostEqual(float(trig), float(isn.sin()))
                self.assertAlmostEqual(float(isn), math.asin(float(trig)))

                ics = trig.acos()
                self.assertTrue(0 <= ics and ics <= fam62.pi)
                self.assertAlmostEqual(float(trig), float(ics.cos()))
                self.assertAlmostEqual(float(ics), math.acos(float(trig)))