Skip to content

Commit

Permalink
Merge pull request #87 from jaidevd/jd-post-py3-cleanup
Browse files Browse the repository at this point in the history
Minor cleanup after running py2to3
  • Loading branch information
jaidevd committed Jan 15, 2016
2 parents edde4c9 + 603e5e1 commit 3f209d1
Show file tree
Hide file tree
Showing 11 changed files with 30 additions and 121 deletions.
5 changes: 2 additions & 3 deletions tftb/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import tftb.tests
import tftb.processing
import tftb.generators
from tftb import generators, processing, utils

__all__ = ["generators", "processing", "utils"]
12 changes: 6 additions & 6 deletions tftb/generators/__init__.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
from .amplitude_modulated import amexpos, amgauss, amrect, amtriang
from .frequency_modulated import (fmconst, fmhyp, fmlin, fmodany, fmpar,
from amplitude_modulated import amexpos, amgauss, amrect, amtriang
from frequency_modulated import (fmconst, fmhyp, fmlin, fmodany, fmpar,
fmpower, fmsin)
from .utils import sigmerge, scale
from .noise import dopnoise, noisecg, noisecu
from .analytic_signals import (anaask, anabpsk, anafsk, anapulse, anaqpsk,
from utils import sigmerge, scale
from noise import dopnoise, noisecg, noisecu
from analytic_signals import (anaask, anabpsk, anafsk, anapulse, anaqpsk,
anasing, anastep)
from tftb.generators.misc import doppler, gdpower, klauder, mexhat, altes, atoms
from misc import doppler, gdpower, klauder, mexhat, altes, atoms

__all__ = ['amexpos', 'amgauss', 'amrect', 'amtriang', 'fmconst', 'fmhyp',
'fmlin', 'fmodany', 'fmpar', 'fmpower', 'fmsin', 'sigmerge',
Expand Down
11 changes: 2 additions & 9 deletions tftb/generators/analytic_signals.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,9 @@
import numpy as np
from numpy import pi
from scipy.signal import hilbert
#
# package structure may need to be re-evaluated via the init.py file(s), so it is available as:
# tftb.generators.fmconst
# fmconst is imported in __init__.py; what's the right way to import this for this module in the package?
#from .frequency_modulated import fmconst
from tftb.generators import fmconst


def anaask(n_points, n_comp=None, f0=0.25):
"""Generate an amplitude shift (ASK) keying signal.
Expand All @@ -30,8 +26,7 @@ def anaask(n_points, n_comp=None, f0=0.25):
n_comp = np.round(n_points / 2)
if (f0 < 0) or (f0 > 0.5):
raise TypeError("f0 must be between 0 and 0.5")
#m = np.ceil(n_points / n_comp)
m = int(np.ceil(n_points / n_comp)) # getting an int deprication warning...
m = int(np.ceil(n_points / n_comp))
jumps = np.random.rand(m)
am = np.kron(jumps, np.ones((n_comp,)))[:n_points]
fm, iflaw = fmconst(n_points, f0, 1)
Expand Down Expand Up @@ -61,7 +56,6 @@ def anabpsk(n_points, n_comp=None, f0=0.25):
n_comp = np.round(n_points / 5)
if (f0 < 0) or (f0 > 0.5):
raise TypeError("f0 must be between 0 and 0.5")
#m = np.ceil(n_points / n_comp)
m = int(np.ceil(n_points / n_comp))
jumps = 2.0 * np.round(np.random.rand(m)) - 1
am = np.kron(jumps, np.ones((n_comp,)))[:n_points]
Expand Down Expand Up @@ -143,7 +137,6 @@ def anaqpsk(n_points, n_comp=None, f0=0.25):
n_comp = np.round(n_points / 5)
if (f0 < 0) or (f0 > 0.5):
raise TypeError("f0 must be between 0 and 0.5")
#m = np.ceil(n_points / n_comp)
m = int(np.ceil(n_points / n_comp))
jumps = np.floor(4 * np.random.rand(m))
jumps[jumps == 4] = 3
Expand Down
38 changes: 8 additions & 30 deletions tftb/generators/misc.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,16 +54,8 @@ def atoms(n_points, coordinates):
.. plot:: docstring_plots/generators/misc/atoms.py
"""
# FIXME: This function produces incorrect output when coordinates are
# one-dimensional.
# yoder: would the fix be something like: if not isinstance(coordinates[0], list): coordinates = [coordinates]
# ???
# at first glance, it looks ok. let's just add some data typ handlers. they may be imperfect, but the basic idea is to catch
# some common errors, like passing a list, not an array.
# an un-contained 1-d coordinates array:
if not hasattr(coordinates[0], '__len__'): coordinates = [coordinates]
if not hasattr(coordinates, 'shape'): coordinates = numpy.array(coordinates)
#
if coordinates.ndim == 1:
coordinates = coordinates.reshape((coordinates.shape[0], 1))
signal = np.zeros((n_points,), dtype=complex)
n_atoms = coordinates.shape[0]
for k in range(n_atoms):
Expand Down Expand Up @@ -147,9 +139,6 @@ def klauder(n_points, attenuation=10.0, f0=0.2):

assert n_points > 0
assert ((f0 < 0.5) and (f0 > 0))
#
# debug:
#print('debug: klauder:: n_points=', n_points)

f = np.linspace(0., 0.5, int(n_points / 2 + 1))
mod = np.exp(-2. * np.pi * attenuation * f) * f ** (2. * np.pi * attenuation * f0 - 0.5)
Expand Down Expand Up @@ -198,17 +187,13 @@ def gdpower(n_points, degree=0.0, rate=1.0):
frequency bins.
:rtype: tuple
"""
# quickly, handle types:
n_points = int(n_points)
degree = float(degree)
rate = float(rate)
#print("diagnostic: running gdpower")
degree = float(degree)
rate = float(rate)
t0 = 0
#lnu = int(np.round(n_points / 2))
lnu = int(np.ceil(n_points / 2)) # ??
lnu = int(np.ceil(n_points / 2))
nu = np.linspace(0, 0.5, lnu + 1)
nu = nu[1:]
#am = nu ** ((degree - 2) / 6)
am = nu ** ((degree - 2.0) / 6.0)

if rate == 0.:
Expand All @@ -217,39 +202,32 @@ def gdpower(n_points, degree=0.0, rate=1.0):
tfx = np.zeros((n_points,), dtype=complex)

if (degree < 1.) and (degree != 0):
#d = n_points ** (degree * rate)
d = float(n_points) ** (degree * rate)
t0 = n_points / 10.0
#tfx[:lnu] = np.exp(-1j * 2 * pi * (t0 * nu + d * nu ** degree / degree)) * am
tfx[:lnu] = np.exp(-1.0j * 2. * pi * ((t0 * nu + d * nu ** degree) / degree)) * am
tfx[:lnu] = np.exp(-1.0j * 2. * pi * (t0 * nu + d * nu ** degree / degree)) * am
x = np.fft.ifft(tfx)
elif degree == 0:
d = rate
t0 = n_points / 10.0
tfx[:lnu] = np.exp(-1j * 2 * np.pi * (t0 * nu + d * np.log(nu))) * am
x = np.fft.ifft(tfx)
elif degree == 1.:
from .analytic_signals import anapulse
from analytic_signals import anapulse
t0 = n_points
x = anapulse(n_points, t0)
elif degree > 1.:
#d = n_points * 2 ** (degree - 1) * rate
d = n_points * 2. ** (degree - 1.) * rate
#tfx[:lnu] = np.exp(-1j * 2 * pi * (t0 * nu + d * nu ** degree / degree)) * am
tfx[:lnu] = np.exp(-1.0j * 2.0 * pi * ((t0 * nu + d * nu ** degree) / degree)) * am
tfx[:lnu] = np.exp(-1.0j * 2.0 * pi * (t0 * nu + d * nu ** degree / degree)) * am
x = np.fft.ifft(tfx)
else:
t0 = n_points / 10
#d = n_points * 2 ** (degree - 1) * rate
d = n_points * 2.0 ** (degree - 1.0) * rate
tfx[:lnu] = np.exp(-1j * 2 * pi * (t0 * nu + d * np.log(nu))) * am
x = np.fft.ifft(tfx)

if degree != 1.0:
#gpd = t0 + np.abs(np.sign(rate) - 1) / 2 * (n_points + 1) + d * nu ** (degree - 1)
gpd = t0 + np.abs(np.sign(rate) - 1.0) / 2.0 * (n_points + 1.0) + d * nu ** (degree - 1.0)
else:
#gpd = t0 * np.ones((n_points / 2,))
gpd = t0 * np.ones((n_points / 2.0,))

x = x - x.mean()
Expand Down
5 changes: 1 addition & 4 deletions tftb/generators/noise.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,7 @@ def noisecu(n_points):
if n_points <= 2:
noise = (np.random.rand(n_points, 1) - 0.5 + 1j * (np.random.rand(n_points, 1) - 0.5)) * np.sqrt(6)
else:
# getting a non-integer warning, promising an error in time to come, here...
noise = np.random.rand(2 ** int(nextpow2(n_points)),) - 0.5
#noise = np.random.rand(2 ** nextpow2(n_points),) - 0.5
noise = hilbert(noise) / noise.std() / np.sqrt(2)
inds = noise.shape[0] - np.arange(n_points - 1, -1, step=-1) - 1
noise = noise[inds]
Expand Down Expand Up @@ -62,8 +60,7 @@ def noisecg(n_points, a1=None, a2=None):
if n_points <= 2:
noise = (np.random.randn(n_points, 1.) + 1j * np.random.randn(n_points, 1.)) / np.sqrt(2.)
else:
#noise = np.random.normal(size=(2 ** nextpow2(n_points),))
noise = np.random.normal(size=int(2. ** nextpow2(float(n_points)),)) # handle floats/ints a bit more carefully.
noise = np.random.normal(size=int(2. ** nextpow2(float(n_points)),))
noise = hilbert(noise) / noise.std() / np.sqrt(2.)
noise = noise[len(noise) - np.arange(n_points - 1, -1, -1) - 1]
return noise
Expand Down
5 changes: 0 additions & 5 deletions tftb/tests/__init__.py
Original file line number Diff line number Diff line change
@@ -1,5 +0,0 @@
from . import *
import glob # file listing utility.
import os
#
__all__ = [os.path.splitext(fl)[0] for fl in glob.glob('*.py')]
30 changes: 10 additions & 20 deletions tftb/tests/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,34 +8,24 @@

"""Base class for tests."""

import sys
import unittest
import numpy as np
from scipy import angle
from tftb.utils import is_linear

# yoder:
# let's add at least some backwards python2.x compatibility for now.
import sys
#py_ver = sys.version_info.major
# and assume only backwards revisions (for now):
ispy2 = (sys.version_info.major<3) # maybe we should work this into TestBase?
ispy2 = sys.version_info.major < 3


class TestBase(unittest.TestCase):

# yoder: add __init__()
def __init__(self, *args, **kwargs):
# handle various bits, including some python2-3 compatibility, then execute base __init__ as super()
if not ispy2:
# re-map some function calls:
self.assertItemsEqual = self.assertCountEqual #(inherited from unittest.TestCase)
# ... and others...
#
# and let's go backwards as well, just to be sure (now, we can correct all the downstream code and remove this hack at a later time...).
if ispy2:
self.assertCountEqual = self.assertItemsEqual
#
super(TestBase,self).__init__(*args, **kwargs)

@classmethod
def setUpClass(cls):
if ispy2:
cls.assertCountEqual = cls.assertItemsEqual
else:
cls.assertItemsEqual = cls.assertCountEqual

def assert_is_linear(self, signal, decimals=5):
"""Assert that the signal is linear."""
self.assertTrue(is_linear(signal, decimals=decimals))
Expand Down
3 changes: 0 additions & 3 deletions tftb/tests/test_amplitude_modulations.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,6 @@
import numpy as np
from numpy import pi
from scipy.signal import argrelmax
# diagnostics:
import base # this would be the 'local' import, so it will depend on the local directory structure. nominally, if we properly configure setup.py
# and install, we should be able to use the line below. are tests meant to be part of the package, or run separately?
from tftb.tests.base import TestBase
import tftb.generators.amplitude_modulated as am

Expand Down
10 changes: 0 additions & 10 deletions tftb/tests/test_analytic_signals.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,6 @@
import numpy as np
from tftb.tests.base import TestBase
from tftb.generators import analytic_signals as ana
#
# let's add at least some backwards python2.x compatibility for now.
# (moving this to the unit test class definition (see tests/base.py)
#import sys
#py_ver = sys.version_info.major
# and assume only backwards revisions (for now):
#ispy2 = (sys.version_info.major<3)


class TestAnalyticSignals(TestBase):
Expand All @@ -33,10 +26,7 @@ def test_anaask(self):
def test_anabpsk(self):
"""Test analytic BPSK signal."""
signal, amlaw = ana.anabpsk(300, 30, 0.1)
#
#self.assertItemsEqual(np.unique(amlaw), [-1, 1]) # python2.x syntax (py2/3 cases should be handled in TestBase class definition).
self.assertCountEqual(np.unique(amlaw), [-1, 1])
#
self.assert_is_analytic(signal)

def test_anafsk(self):
Expand Down
25 changes: 0 additions & 25 deletions tftb/tests/test_misc.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,6 @@
import numpy as np
from scipy.signal import argrelmax, argrelmin, hanning

#import pylab as plt

# yoder:
# let's add at least some backwards python2.x compatibility for now.
import sys
#py_ver = sys.version_info.major
# and assume only backwards revisions (for now):
#ispy2 = (sys.version_info.major<3) # moved version compatibility into base class: TestBase()?

class TestMisc(TestBase):

Expand Down Expand Up @@ -58,38 +50,21 @@ def test_mexhat(self):
self.assertEqual(maxima[0].shape[0], 1)
self.assertEqual(maxima[0][0], 3)
minima = argrelmin(actual)
#
# handling 2/3 compatibility in the class definition (see base.py)
#self.assertEqual(minima[0].shape[0], 2)
#if ispy2:
# self.assertItemsEqual(minima[0], (2, 4))
#else:
self.assertCountEqual(minima[0], (2, 4))

def test_gdpower(self):
ideal_sig = np.array([0.08540661 + 0.05077147j, 0.16735776 + 0.11542816j,
-0.08825763 + 0.17010894j, 0.04412953 - 0.01981114j,
-0.04981628 + 0.34985966j, -0.56798889 - 0.07983783j,
0.05266730 - 0.57074006j, 0.35650159 - 0.01577918j])
#
ideal_f = np.array([0.125, 0.25, 0.375, 0.5])
ideal_gpd = np.array([8.8, 6.45685425, 5.41880215, 4.8])
ideals = (ideal_sig, ideal_gpd, ideal_f)
#
# let's be a bit smarter about this:
#actuals = misc.gdpower(8, 0.5)
actuals = misc.gdpower(len(ideal_sig), 0.5)
#
for i, ideal in enumerate(ideals):
actual = actuals[i]
#
np.testing.assert_allclose(ideal, actual, atol=1e-7, rtol=1e-7)




if __name__ == '__main__':
unittest.main()
else:
#plt.ion()
pass
7 changes: 1 addition & 6 deletions tftb/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -74,12 +74,7 @@ def izak(x):

def nextpow2(n):
"""
#Compute the exponent of the next higher power of 2.
# returns the next *integer* exponent (as a float) and is lower-inclusive.
# ie,:
# > nextpow2(2) = 1.0
# > nextpow2(2.0) = 1.0
# > nextpow2(2.1) = 2.0
Compute the integer exponent of the next higher power of 2.
:param n: Number whose next higest power of 2 needs to be computed.
:type n: int, np.ndarray
Expand Down

0 comments on commit 3f209d1

Please sign in to comment.