├── .gitignore ├── Decision Trees on Infinite Grid ├── .gitignore ├── README.md ├── results │ ├── L3_0-2-1-0.png │ ├── L5_0-2-2-1.png │ ├── L5_1-3-1-0.png │ ├── L7_0-2-3-2.png │ ├── L7_1-3-2-1.png │ └── L7_2-4-1-0.png └── trees.py ├── LICENSE ├── Octree ├── .gitignore ├── CMakeLists.txt ├── build ├── cmake │ └── Modules │ │ └── FindCppTest.cmake └── src │ ├── CMakeLists.txt │ ├── collisions.cpp │ ├── collisions.h │ ├── collisions_unit.h │ ├── octree.cpp │ ├── octree.h │ ├── octree_unit.h │ ├── types_3d.cpp │ ├── types_3d.h │ ├── types_3d_unit.h │ └── unit_tests.cpp ├── README.md ├── Sallen Key Solver ├── README.md ├── SallenKey_Design.py ├── anneal.py ├── misc.py └── results │ └── SA_results.png ├── Short Time Fourier Transform ├── .gitignore ├── BuildQtGui.py ├── ParseMathExp.py ├── README.md ├── Stft.py ├── archive │ ├── half_cosine.py │ └── stft.py ├── media │ ├── .gitignore │ ├── mike_annoying.wav │ └── mike_chirp.wav ├── mplcanvas.py ├── sfft_gui.py └── sfft_gui.ui └── Weinberg Circuit ├── .gitignore ├── README.md ├── v02-Ideal.asc ├── v03-NonIdeal.asc └── v04-SEPIC.asc /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | 3 | resources 4 | 5 | __pycache__/ 6 | *.py[cod] 7 | 8 | # C extensions 9 | *.so 10 | 11 | # Distribution / packaging 12 | .Python 13 | env/ 14 | build/ 15 | develop-eggs/ 16 | dist/ 17 | downloads/ 18 | eggs/ 19 | lib/ 20 | lib64/ 21 | parts/ 22 | sdist/ 23 | var/ 24 | *.egg-info/ 25 | .installed.cfg 26 | *.egg 27 | 28 | # PyInstaller 29 | # Usually these files are written by a python script from a template 30 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 31 | *.manifest 32 | *.spec 33 | 34 | # Installer logs 35 | pip-log.txt 36 | pip-delete-this-directory.txt 37 | 38 | # Unit test / coverage reports 39 | htmlcov/ 40 | .tox/ 41 | .coverage 42 | .cache 43 | nosetests.xml 44 | coverage.xml 45 | 46 | # Translations 47 | *.mo 48 | *.pot 49 | 50 | # Django stuff: 51 | *.log 52 | 53 | # Sphinx documentation 54 | docs/_build/ 55 | 56 | # PyBuilder 57 | target/ 58 | -------------------------------------------------------------------------------- /Decision Trees on Infinite Grid/.gitignore: -------------------------------------------------------------------------------- 1 | resources 2 | -------------------------------------------------------------------------------- /Decision Trees on Infinite Grid/README.md: -------------------------------------------------------------------------------- 1 | Decision Trees on Infinite Grid 2 | ============================= 3 | 4 | To run, execute the following command: 5 | 6 | >> python trees.py 7 | 8 | Required Packages 9 | -----------------s 10 | * GraphViz 11 | * PyDot 12 | 13 | -------------------------------------------------------------------------------- /Decision Trees on Infinite Grid/results/L3_0-2-1-0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KevinNJ/Projects/7b3268a808b76e85aab5981b35b22710ed7c4300/Decision Trees on Infinite Grid/results/L3_0-2-1-0.png -------------------------------------------------------------------------------- /Decision Trees on Infinite Grid/results/L5_0-2-2-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KevinNJ/Projects/7b3268a808b76e85aab5981b35b22710ed7c4300/Decision Trees on Infinite Grid/results/L5_0-2-2-1.png -------------------------------------------------------------------------------- /Decision Trees on Infinite Grid/results/L5_1-3-1-0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KevinNJ/Projects/7b3268a808b76e85aab5981b35b22710ed7c4300/Decision Trees on Infinite Grid/results/L5_1-3-1-0.png -------------------------------------------------------------------------------- /Decision Trees on Infinite Grid/results/L7_0-2-3-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KevinNJ/Projects/7b3268a808b76e85aab5981b35b22710ed7c4300/Decision Trees on Infinite Grid/results/L7_0-2-3-2.png -------------------------------------------------------------------------------- /Decision Trees on Infinite Grid/results/L7_1-3-2-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KevinNJ/Projects/7b3268a808b76e85aab5981b35b22710ed7c4300/Decision Trees on Infinite Grid/results/L7_1-3-2-1.png -------------------------------------------------------------------------------- /Decision Trees on Infinite Grid/results/L7_2-4-1-0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KevinNJ/Projects/7b3268a808b76e85aab5981b35b22710ed7c4300/Decision Trees on Infinite Grid/results/L7_2-4-1-0.png -------------------------------------------------------------------------------- /Decision Trees on Infinite Grid/trees.py: -------------------------------------------------------------------------------- 1 | __author__ = 'knelson' 2 | 3 | 4 | transitions = { 5 | 'L': ['U', 'D', 'L'], 6 | 'R': ['U', 'D', 'R'], 7 | 'U': ['L', 'R', 'U'], 8 | 'D': ['L', 'R', 'D'], 9 | None: ['L', 'R', 'U', 'D'] 10 | } 11 | 12 | 13 | class Node(object): 14 | def __init__(self): 15 | self.children = [] 16 | self.decision = None 17 | 18 | 19 | def make_tree(node, state): 20 | for d,v in state.iteritems(): 21 | if d in transitions[node.decision] and v > 0: 22 | child = Node() 23 | child.decision = d 24 | new_state = state.copy() 25 | new_state[d] -= 1 26 | make_tree(child, new_state) 27 | node.children.append(child) 28 | 29 | 30 | def list_paths(parent): 31 | if len(parent.children) == 0: 32 | return [[parent.decision]] 33 | else: 34 | paths = [] 35 | for child in parent.children: 36 | paths.extend(list_paths(child)) 37 | if parent.decision is not None: 38 | for path in paths: 39 | path.insert(0, parent.decision) 40 | return paths 41 | 42 | 43 | def run_tuple(l,r,u,d): 44 | root = Node() 45 | make_tree(root, {'L':l, 'R':r, 'U':u, 'D':d}) 46 | path_len = sum((l,r,u,d)) 47 | paths = filter(lambda x: len(x) == path_len, list_paths(root)) 48 | print 'Path Len, Number of paths (%s,%s)' % (path_len, len(paths)) 49 | #print '\n'.join([', '.join(x) for x in paths]) 50 | #print '' 51 | return root, paths 52 | 53 | 54 | def make_graph(graph, root, root_node): 55 | for child in root.children: 56 | child_node = pydot.Node(get_next_id(), label=child.decision) 57 | dot_edge = pydot.Edge(root_node, child_node) 58 | graph.add_node(child_node) 59 | graph.add_edge(dot_edge) 60 | make_graph(graph, child, child_node) 61 | 62 | 63 | def get_next_id(): 64 | nid = get_next_id.id 65 | get_next_id.id += 1 66 | return nid 67 | get_next_id.id = 1 68 | 69 | 70 | if __name__ == '__main__': 71 | 72 | pathDic = { 73 | 3: [(0,2,1,0)], 74 | 5: [(1,3,1,0),(0,2,2,1)], 75 | 7: [(2,4,1,0),(0,2,3,2),(1,3,2,1)] 76 | } 77 | 78 | import pydot 79 | 80 | for l,p in pathDic.iteritems(): 81 | for tup in p: 82 | graph = pydot.Dot(graph_type='graph', dpi=300) 83 | root, paths = run_tuple(*tup) 84 | root_node = pydot.Node('X') 85 | make_graph(graph, root, root_node) 86 | 87 | graph.write_png('L%s_' % l + '-'.join(map(str, tup)) + '.png') -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 KevinNJ 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /Octree/.gitignore: -------------------------------------------------------------------------------- 1 | debug -------------------------------------------------------------------------------- /Octree/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required (VERSION 2.6) 2 | project (unit_tests) 3 | 4 | set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake/Modules/") 5 | 6 | SET (CMAKE_C_FLAGS "-Wall -std=c99") 7 | SET (CMAKE_C_FLAGS_DEBUG "-g") 8 | SET (CMAKE_C_FLAGS_MINSIZEREL "-Os -DNDEBUG") 9 | SET (CMAKE_C_FLAGS_RELEASE "-O4 -DNDEBUG") 10 | SET (CMAKE_C_FLAGS_RELWITHDEBINFO "-O2 -g") 11 | 12 | SET (CMAKE_CXX_FLAGS "-Wextra -std=c++1y") 13 | SET (CMAKE_CXX_FLAGS_DEBUG "-g") 14 | SET (CMAKE_CXX_FLAGS_MINSIZEREL "-Os -DNDEBUG") 15 | SET (CMAKE_CXX_FLAGS_RELEASE "-O4 -DNDEBUG") 16 | SET (CMAKE_CXX_FLAGS_RELWITHDEBINFO "-O2 -g") 17 | 18 | # If compiler is clang, add option to use gcc stdlib 19 | if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang") 20 | SET (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -stdlib=libstdc++") # for clang only 21 | ENDIF () 22 | 23 | add_subdirectory(src) 24 | 25 | 26 | -------------------------------------------------------------------------------- /Octree/build: -------------------------------------------------------------------------------- 1 | set -e 2 | 3 | directory=`dirname $0` 4 | 5 | cd $directory/debug 6 | rm -r * 7 | #CC=/usr/bin/gcc CXX=/usr/bin/g++ cmake -DCMAKE_BUILD_TYPE=Debug .. 8 | CC=/usr/bin/clang CXX=/usr/bin/clang++ cmake -DCMAKE_BUILD_TYPE=Debug .. 9 | make 10 | ./src/unit_tests 11 | -------------------------------------------------------------------------------- /Octree/cmake/Modules/FindCppTest.cmake: -------------------------------------------------------------------------------- 1 | # Find CPPTest for use in unit level testing 2 | # 3 | # This tries to find the CPPTest library. Once completed it will set: 4 | # CPPTEST_INCLUDE_DIRS - include directories for compilation 5 | # CPPTEST_LIBRARIES - libraries needed to link against 6 | # CPPTEST_LIBRARY_DIRS - directories where to find the libraries 7 | # CPPTest_FOUND - boolean set to true if found 8 | # 9 | ################################################################################ 10 | # Copyright (c) 2013 David D. Marshall 11 | # 12 | # All rights reserved. This program and the accompanying materials 13 | # are made available under the terms of the Eclipse Public License v1.0 14 | # which accompanies this distribution, and is available at 15 | # http://www.eclipse.org/legal/epl-v10.html 16 | # 17 | # Contributors: 18 | # David D. Marshall - initial code and implementation 19 | ################################################################################ 20 | 21 | if(CPPTEST_LIBRARIES) 22 | set(CPPTEST_FOUND TRUE) 23 | else() 24 | find_path(CPPTEST_INCLUDE_DIRS cpptest.h 25 | PATHS 26 | /usr/include 27 | /usr/local/include 28 | /opt/local/include 29 | ${CMAKE_INSTALL_PREFIX}/include 30 | $ENV{CPPTESTDIR} 31 | ${INCLUDE_INSTALL_DIR}) 32 | find_library(CPPTEST_LIBRARIES cpptest 33 | PATHS 34 | $ENV{CPPTESTDIR} 35 | /usr/local/lib 36 | /opt/local/lib 37 | ${LIB_INSTALL_DIR}) 38 | get_filename_component(CPPTEST_LIBRARY_DIRS ${CPPTEST_LIBRARIES} PATH) 39 | 40 | mark_as_advanced(CPPTEST_INCLUDE_DIRS CPPTEST_LIBRARIES CPPTEST_LIBRARY_DIRS) 41 | 42 | include(FindPackageHandleStandardArgs) 43 | find_package_handle_standard_args(CPPTest DEFAULT_MSG CPPTEST_INCLUDE_DIRS CPPTEST_LIBRARIES CPPTEST_LIBRARY_DIRS) 44 | endif() -------------------------------------------------------------------------------- /Octree/src/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | file(GLOB SOURCES *.cpp) 2 | add_executable (unit_tests ${SOURCES}) 3 | 4 | find_package(CppTest REQUIRED) 5 | include_directories(${CPPTEST_INCLUDE_DIRS}) 6 | target_link_libraries(unit_tests ${CPPTEST_LIBRARIES}) -------------------------------------------------------------------------------- /Octree/src/collisions.cpp: -------------------------------------------------------------------------------- 1 | #include "collisions.h" 2 | 3 | bool Collisions::sphere3_ray3(const vector3_t& c, double r, const ray3_t& y) 4 | { 5 | // get vector from ray start to center of sphere 6 | auto v1 = c - y.point(); 7 | 8 | // test if ray is pointing towards sphere 9 | auto len = v1.dot(y.dir()); 10 | if (len < 0) {return false;} 11 | 12 | // get test point which is closest point on ray to center of sphere 13 | auto proj = y.dir(); 14 | proj.scale(len); 15 | auto tp = proj + y.point(); 16 | 17 | // collision test with this point and the sphere 18 | return sphere3_vector3(c, r, tp); 19 | } 20 | 21 | bool Collisions::poly3_vector3(const poly3_t& t, const vector3_t& v) 22 | { 23 | // NOTE: function assumes that the point is coplaner with the triangle 24 | 25 | // find the inverse of the area of the triangle (iat) 26 | auto ts1 = t.p1() - t.p2(); 27 | auto ts2 = t.p1() - t.p3(); 28 | auto iat = 1 / ts1.cross(ts2).length(); 29 | 30 | // find vectors from the corners of the triangle to the point 31 | // used in calculating the barycentric coordinates of the point 32 | auto ta = t.p1() - v; 33 | auto tb = t.p2() - v; 34 | auto tc = t.p3() - v; 35 | 36 | // calculate the barycentric coordinates for the point 37 | // a->alpha, b->beta, g->gamma 38 | auto a = tb.cross(tc).length() * iat; 39 | auto b = tc.cross(ta).length() * iat; 40 | auto g = 1 - a - b; 41 | 42 | // if the coordinates are all between 0 and 1, the point lies within the triangle 43 | return (0 <= a && a <= 1) && (0 <= b && b <= 1) && (0 <= g && g <= 1); 44 | } 45 | 46 | bool Collisions::sphere3_poly3(const vector3_t& c, double r, const poly3_t& t) 47 | { 48 | auto v1 = t.p1() - c; 49 | auto v2 = v1.project(t.n()); 50 | auto q = c + v2; 51 | 52 | // test if point is inside sphere and if point is inside triangle 53 | return sphere3_vector3(c, r, q) && poly3_vector3(t, q); 54 | } 55 | 56 | bool Collisions::poly3_ray3(const poly3_t& p, const ray3_t r) 57 | { 58 | // NOTE: not sure what this does if ray and triangle are parallel 59 | 60 | // d in the equation of a plane, where d is 61 | // (the normal of the plane) dot (a point on the plane) 62 | auto d = p.n().dot(p.p1()); 63 | 64 | // t is a scalar which represents the length between 65 | // (the point of the ray) and (the intersecting point on the plane) 66 | auto t = (r.point().dot(p.n()) + d) / r.dir().dot(p.n()); 67 | 68 | // s is the vector which goes between the point of the ray and the intersecting point 69 | // on the plane 70 | auto s = r.dir(); 71 | s.scale(t); 72 | 73 | // q is the intersecting point on the plane 74 | auto q = r.point() + s; 75 | 76 | // test if the intersecting point is within the triangle 77 | return poly3_vector3(p, q); 78 | } -------------------------------------------------------------------------------- /Octree/src/collisions.h: -------------------------------------------------------------------------------- 1 | #ifndef OCTREE_COLLISIONS_H 2 | #define OCTREE_COLLISIONS_H 3 | 4 | #include 5 | #include "types_3d.h" 6 | 7 | class Collisions 8 | { 9 | public: 10 | static inline bool sphere3_vector3(const vector3_t& c, double r, const vector3_t p) 11 | { 12 | // distance between point and sphere center is less than radius -> point in sphere 13 | auto v1 = c - p; 14 | return v1.length() <= r; 15 | } 16 | 17 | static inline bool sphere3_sphere3(const vector3_t& c1, double r1, const vector3_t& c2, double r2) 18 | { 19 | // distance between sphere center1 and sphere center2 <= radius1 + radius2 -> spheres collide 20 | auto v1 = c1 - c2; 21 | return v1.length() <= (r1 + r2); 22 | } 23 | 24 | static bool sphere3_ray3(const vector3_t& c, double r, const ray3_t& y); 25 | 26 | static bool sphere3_ray3_time(const vector3_t& c, double r, const ray3_t& y) 27 | { 28 | // Avoid 'unused variable' warnings 29 | (void)c; 30 | (void)r; 31 | (void)y; 32 | 33 | // TODO: Implement this function 34 | throw std::logic_error("Not implemented"); 35 | return false; 36 | } 37 | 38 | static bool poly3_vector3(const poly3_t& t, const vector3_t& v); 39 | static bool sphere3_poly3(const vector3_t& c, double r, const poly3_t& t); 40 | static bool poly3_ray3(const poly3_t& p, const ray3_t r); 41 | }; 42 | 43 | #endif //OCTREE_COLLISIONS_H -------------------------------------------------------------------------------- /Octree/src/collisions_unit.h: -------------------------------------------------------------------------------- 1 | #ifndef OCTREE_COLLISIONS_UNIT_H 2 | #define OCTREE_COLLISIONS_UNIT_H 3 | 4 | #include "collisions.h" 5 | 6 | class TestSuite_COLLISIONS : public Test::Suite 7 | { 8 | public: 9 | TestSuite_COLLISIONS() 10 | { 11 | TEST_ADD(TestSuite_COLLISIONS::collisions_sphere3_vector3) 12 | TEST_ADD(TestSuite_COLLISIONS::collisions_sphere3_sphere3) 13 | TEST_ADD(TestSuite_COLLISIONS::collisions_sphere3_ray3) 14 | TEST_ADD(TestSuite_COLLISIONS::collisions_sphere3_ray3_time) 15 | TEST_ADD(TestSuite_COLLISIONS::collisions_poly3_vector3) 16 | TEST_ADD(TestSuite_COLLISIONS::collisions_sphere3_poly3) 17 | TEST_ADD(TestSuite_COLLISIONS::collisions_poly3_ray3) 18 | } 19 | 20 | private: 21 | void collisions_sphere3_vector3(); 22 | void collisions_sphere3_sphere3(); 23 | void collisions_sphere3_ray3(); 24 | void collisions_sphere3_ray3_time(); 25 | void collisions_poly3_vector3(); 26 | void collisions_sphere3_poly3(); 27 | void collisions_poly3_ray3(); 28 | }; 29 | 30 | void TestSuite_COLLISIONS::collisions_sphere3_vector3() 31 | { 32 | vector3_t c1{1,1,1}; 33 | vector3_t c2{-1,-1,-1}; 34 | 35 | // add a small epsilon to the radius to be sure of double comparison on border case 36 | auto r = (c1-c2).length() + 1e-12; 37 | 38 | // border case 39 | TEST_ASSERT(Collisions::sphere3_vector3(c1, r, c2) == true) 40 | // radius is slightly too small 41 | TEST_ASSERT(Collisions::sphere3_vector3(c1, r-0.1, c2) == false) 42 | // radius is slightly larger than it needs to be 43 | TEST_ASSERT(Collisions::sphere3_vector3(c1, r+0.1, c2) == true) 44 | } 45 | 46 | void TestSuite_COLLISIONS::collisions_sphere3_sphere3() 47 | { 48 | vector3_t c1{1,1,1}; 49 | vector3_t c2{-1,-1,-1}; 50 | 51 | // add a small epsilon to the radius to be sure of double comparison on border case 52 | auto r = (c1-c2).length()/2.0 + 1e-12; 53 | 54 | // border case 55 | TEST_ASSERT(Collisions::sphere3_sphere3(c1, r, c2, r) == true) 56 | // radius is slightly too small 57 | TEST_ASSERT(Collisions::sphere3_sphere3(c1, r-0.1, c2, r) == false) 58 | TEST_ASSERT(Collisions::sphere3_sphere3(c1, r, c2, r-0.1) == false) 59 | //radius is slightly larger than needed 60 | TEST_ASSERT(Collisions::sphere3_sphere3(c1, r+0.1, c2, r) == true) 61 | TEST_ASSERT(Collisions::sphere3_sphere3(c1, r, c2, r+0.1) == true) 62 | } 63 | 64 | void TestSuite_COLLISIONS::collisions_sphere3_ray3() 65 | { 66 | vector3_t c; 67 | auto r = double{1}; 68 | 69 | // forwards and backwards through center of sphere 70 | ray3_t r1{vector3_t{-2,0,0}, vector3_t{1,0,0}}; 71 | ray3_t r2{vector3_t{2,0,0}, vector3_t{-1,0,0}}; 72 | TEST_ASSERT(Collisions::sphere3_ray3(c, r, r1) == true) 73 | TEST_ASSERT(Collisions::sphere3_ray3(c, r, r2) == true) 74 | 75 | //tangent to sphere 76 | ray3_t r3{vector3_t{-1,1,0}, vector3_t{1,0,0}}; 77 | TEST_ASSERT(Collisions::sphere3_ray3(c, r, r3) == true) 78 | 79 | // slightly miss sphere 80 | ray3_t r4{vector3_t{-1,1 + 1e-12,0}, vector3_t{1,0,0}}; 81 | TEST_ASSERT(Collisions::sphere3_ray3(c, r, r4) == false) 82 | 83 | // pointing away from sphere 84 | ray3_t r5{vector3_t{-2,0,0}, vector3_t{-1,0,0}}; 85 | TEST_ASSERT(Collisions::sphere3_ray3(c, r, r5) == false) 86 | 87 | // forwards and backwards through center of sphere, but tranlated in the z axis 88 | vector3_t c2; 89 | ray3_t r6{vector3_t{-2,0,1}, vector3_t{1,0,0}}; 90 | ray3_t r7{vector3_t{2,0,1}, vector3_t{-1,0,0}}; 91 | TEST_ASSERT(Collisions::sphere3_ray3(c2, r, r6) == true) 92 | TEST_ASSERT(Collisions::sphere3_ray3(c2, r, r7) == true) 93 | 94 | // slightly miss sphere translated in the z axis 95 | ray3_t r8{vector3_t{-1,1 + 1e-12, 1}, vector3_t{1,0,0}}; 96 | TEST_ASSERT(Collisions::sphere3_ray3(c2, r, r8) == false) 97 | } 98 | 99 | void TestSuite_COLLISIONS::collisions_sphere3_ray3_time() 100 | { 101 | TEST_ASSERT(false) 102 | } 103 | 104 | void TestSuite_COLLISIONS::collisions_poly3_vector3() 105 | { 106 | TEST_ASSERT(false) 107 | } 108 | 109 | void TestSuite_COLLISIONS::collisions_sphere3_poly3() 110 | { 111 | TEST_ASSERT(false) 112 | } 113 | 114 | void TestSuite_COLLISIONS::collisions_poly3_ray3() 115 | { 116 | TEST_ASSERT(false) 117 | } 118 | 119 | 120 | 121 | 122 | #endif // OCTREE_COLLISIONS_UNIT_H -------------------------------------------------------------------------------- /Octree/src/octree.cpp: -------------------------------------------------------------------------------- 1 | #include "octree.h" -------------------------------------------------------------------------------- /Octree/src/octree.h: -------------------------------------------------------------------------------- 1 | #ifndef OCTREE_OCTREE_H 2 | #define OCTREE_OCTREE_H 3 | 4 | 5 | 6 | #endif //OCTREE_OCTREE_H -------------------------------------------------------------------------------- /Octree/src/octree_unit.h: -------------------------------------------------------------------------------- 1 | #ifndef OCTREE_OCTREE_UNIT_H 2 | #define OCTREE_OCTREE_UNIT_H 3 | 4 | #include "octree.h" 5 | 6 | #endif //OCTREE_OCTREE_UNIT_H -------------------------------------------------------------------------------- /Octree/src/types_3d.cpp: -------------------------------------------------------------------------------- 1 | #include "types_3d.h" 2 | 3 | // vector3_t functions 4 | double vector3_t::dot(const vector3_t& v) const 5 | { 6 | // start a, end a, start b, initial sum 7 | auto d = std::inner_product(std::begin(coord),std::end(coord),std::begin(v.coord), 0.0); 8 | return d; 9 | } 10 | 11 | vector3_t vector3_t::cross(const vector3_t& v) const 12 | { 13 | double x, y, z; 14 | x = coord[1]*v.coord[2] - coord[2]*v.coord[1]; 15 | y = coord[2]*v.coord[0] - coord[0]*v.coord[2]; 16 | z = coord[0]*v.coord[1] - coord[1]*v.coord[0]; 17 | return vector3_t(x, y, z); 18 | } 19 | 20 | vector3_t vector3_t::project(vector3_t v) const 21 | { 22 | // copy v as new vector to work with (do not pass in by reference) 23 | auto d = dot(v); 24 | v.scale(d); 25 | return v; 26 | } 27 | 28 | double vector3_t::distance(const vector3_t& v) const 29 | { 30 | auto s = *this - v; 31 | auto d = s.dot(s); 32 | return sqrt(d); 33 | } 34 | 35 | double vector3_t::length() const 36 | { 37 | return sqrt(dot(*this)); 38 | } 39 | 40 | void vector3_t::scale(double s) 41 | { 42 | coord[0] *= s; 43 | coord[1] *= s; 44 | coord[2] *= s; 45 | } 46 | 47 | void vector3_t::normalize() 48 | { 49 | auto n = length(); 50 | coord[0] /= n; 51 | coord[1] /= n; 52 | coord[2] /= n; 53 | } 54 | 55 | vector3_t& operator+= (vector3_t& v1, const vector3_t& v2) 56 | { 57 | v1.coord[0] += v2.coord[0]; 58 | v1.coord[1] += v2.coord[1]; 59 | v1.coord[2] += v2.coord[2]; 60 | 61 | return v1; 62 | } 63 | 64 | vector3_t& operator-= (vector3_t& v1, const vector3_t& v2) 65 | { 66 | v1.coord[0] -= v2.coord[0]; 67 | v1.coord[1] -= v2.coord[1]; 68 | v1.coord[2] -= v2.coord[2]; 69 | 70 | return v1; 71 | } 72 | 73 | vector3_t operator+ (const vector3_t& v1, const vector3_t& v2) 74 | { 75 | auto xd = v1.coord[0] + v2.coord[0]; 76 | auto yd = v1.coord[1] + v2.coord[1]; 77 | auto zd = v1.coord[2] + v2.coord[2]; 78 | 79 | return vector3_t(xd, yd, zd); 80 | } 81 | 82 | vector3_t operator- (const vector3_t& v1, const vector3_t& v2) 83 | { 84 | auto xd = v1.coord[0] - v2.coord[0]; 85 | auto yd = v1.coord[1] - v2.coord[1]; 86 | auto zd = v1.coord[2] - v2.coord[2]; 87 | 88 | return vector3_t(xd, yd, zd); 89 | } 90 | 91 | /* 92 | bool operator== (const vector3_t& v1, const vector3_t& v2) 93 | { 94 | return std::equal(&v1.coord[0], &v1.coord[2], &v2.coord[0]); 95 | } 96 | 97 | bool operator!= (const vector3_t& v1, const vector3_t& v2) 98 | { 99 | return !(v1 == v2); 100 | } 101 | */ 102 | 103 | std::ostream& operator<<(std::ostream& os, const vector3_t& v) 104 | { 105 | os << "Vector(" << v.x() << ", " << v.y() << ", " << v.z() << ")"; 106 | return os; 107 | } 108 | 109 | 110 | // ray3_t functions 111 | ray3_t::ray3_t(const vector3_t& point_, const vector3_t& dir_) : components{point_, dir_} // TODO: does this move or copy? 112 | { 113 | dir().normalize(); 114 | } 115 | 116 | std::ostream& operator<<(std::ostream& os, const ray3_t& r) 117 | { 118 | os << "Ray(" << "Start:" << r.point() << ", Direction:" << r.dir() << ")"; 119 | return os; 120 | } 121 | 122 | 123 | // poly3_t functions 124 | void poly3_t::set_normal() 125 | { 126 | auto e1 = points[2] - points[1]; 127 | auto e2 = points[3] - points[1]; 128 | points[4] = e1.cross(e2); 129 | } 130 | 131 | std::ostream& operator<<(std::ostream& os, const poly3_t& t) 132 | { 133 | os << "Poly3(" << "p1:" << t.p1() << ", p2:" << t.p2() << ", p3:" << t.p3() << ", n:" << t.n() << ")"; 134 | return os; 135 | } -------------------------------------------------------------------------------- /Octree/src/types_3d.h: -------------------------------------------------------------------------------- 1 | #ifndef OCTREE_TYPES_3D_H 2 | #define OCTREE_TYPES_3D_H 3 | 4 | #include 5 | #include 6 | 7 | class vector3_t 8 | { 9 | public: 10 | double coord[3]; 11 | 12 | // constructors 13 | vector3_t():coord{0.0,0.0,0.0} {} 14 | vector3_t(double x, double y, double z) : coord{x,y,z} {} 15 | 16 | // getters 17 | double inline x() const {return coord[0];} 18 | double inline y() const {return coord[1];} 19 | double inline z() const {return coord[2];} 20 | 21 | // Vector operator functions (return new vector) 22 | double dot(const vector3_t& v) const; 23 | vector3_t cross(const vector3_t& v) const; 24 | vector3_t project(vector3_t v) const; 25 | 26 | // Vector metric functions 27 | double distance(const vector3_t& v) const; 28 | double length() const; 29 | 30 | // Transformation functions 31 | void scale(double s); 32 | void normalize(); 33 | 34 | // Vector arithmatic functions 35 | friend vector3_t& operator+= (vector3_t& v1, const vector3_t& v2); 36 | friend vector3_t& operator-= (vector3_t& v1, const vector3_t& v2); 37 | 38 | friend vector3_t operator+ (const vector3_t& v1, const vector3_t& v2); 39 | friend vector3_t operator- (const vector3_t& v1, const vector3_t& v2); 40 | 41 | // Vector comparison functions 42 | // TODO remove these because we shouldn't do double comparisons like this 43 | //friend bool operator== (const vector3_t& v1, const vector3_t& v2); 44 | //friend bool operator!= (const vector3_t& v1, const vector3_t& v2); 45 | 46 | // cout operator overload 47 | friend std::ostream& operator<<(std::ostream& os, const vector3_t& v); 48 | }; 49 | 50 | 51 | class ray3_t 52 | { 53 | public: 54 | vector3_t components[2]; 55 | 56 | // getters (used in constructor, so defined first) 57 | auto inline point() const {return components[0];} 58 | auto inline dir() const {return components[1];} 59 | 60 | // constructors 61 | ray3_t(const vector3_t& point_, const vector3_t& dir_); 62 | 63 | // cout operator overload 64 | friend std::ostream& operator<<(std::ostream& os, const ray3_t& r); 65 | }; 66 | 67 | 68 | class poly3_t 69 | { 70 | public: 71 | vector3_t points[4]; 72 | 73 | // constructors 74 | poly3_t(vector3_t p1, vector3_t p2, vector3_t p3) 75 | { 76 | // copy in points (do not pass in by reference) 77 | points[0] = p1; 78 | points[1] = p2; 79 | points[3] = p3; 80 | set_normal(); 81 | } 82 | 83 | // getters 84 | auto inline p1() const {return points[0];} 85 | auto inline p2() const {return points[1];} 86 | auto inline p3() const {return points[2];} 87 | auto inline n() const {return points[3];} 88 | 89 | // cout operator overload 90 | friend std::ostream& operator<<(std::ostream& os, const poly3_t& t); 91 | 92 | private: 93 | // helper functions 94 | void set_normal(); 95 | }; 96 | 97 | #endif //OCTREE_TYPES_3D_H -------------------------------------------------------------------------------- /Octree/src/types_3d_unit.h: -------------------------------------------------------------------------------- 1 | #ifndef OCTREE_TYPES_3D_UNIT_H 2 | #define OCTREE_TYPES_3D_UNIT_H 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #include "types_3d.h" 9 | 10 | class TestSuite_TYPES_3D : public Test::Suite 11 | { 12 | public: 13 | TestSuite_TYPES_3D() 14 | { 15 | // 31 - 16 (+1)= 16 tests 16 | TEST_ADD(TestSuite_TYPES_3D::vector3_members) 17 | TEST_ADD(TestSuite_TYPES_3D::vector3_default_constructor) 18 | TEST_ADD(TestSuite_TYPES_3D::vector3_constructor) 19 | TEST_ADD(TestSuite_TYPES_3D::vector3_getters) 20 | TEST_ADD(TestSuite_TYPES_3D::vector3_operators_dot) 21 | TEST_ADD(TestSuite_TYPES_3D::vector3_operators_cross) 22 | TEST_ADD(TestSuite_TYPES_3D::vector3_operators_project) 23 | TEST_ADD(TestSuite_TYPES_3D::vector3_metric_distance) 24 | TEST_ADD(TestSuite_TYPES_3D::vector3_metric_length) 25 | TEST_ADD(TestSuite_TYPES_3D::vector3_transform_scale) 26 | TEST_ADD(TestSuite_TYPES_3D::vector3_transform_normalize) 27 | TEST_ADD(TestSuite_TYPES_3D::vector3_operators_plusequals) 28 | TEST_ADD(TestSuite_TYPES_3D::vector3_operators_minusequals) 29 | TEST_ADD(TestSuite_TYPES_3D::vector3_operators_plus) 30 | TEST_ADD(TestSuite_TYPES_3D::vector3_operators_minus) 31 | TEST_ADD(TestSuite_TYPES_3D::vector3_overload_stream_insertion) 32 | 33 | TEST_ADD(TestSuite_TYPES_3D::ray3_members) 34 | TEST_ADD(TestSuite_TYPES_3D::ray3_getters) 35 | TEST_ADD(TestSuite_TYPES_3D::ray3_constructor) 36 | TEST_ADD(TestSuite_TYPES_3D::ray3_stream_insertion) 37 | 38 | TEST_ADD(TestSuite_TYPES_3D::poly3_members) 39 | TEST_ADD(TestSuite_TYPES_3D::poly3_constructor) 40 | TEST_ADD(TestSuite_TYPES_3D::poly3_getters) 41 | TEST_ADD(TestSuite_TYPES_3D::poly3_stream_insert) 42 | } 43 | 44 | private: 45 | // 51 - 36 (+1) = 16 tests 46 | void vector3_members(); 47 | void vector3_default_constructor(); 48 | void vector3_constructor(); 49 | void vector3_getters(); 50 | void vector3_operators_dot(); 51 | void vector3_operators_cross(); 52 | void vector3_operators_project(); 53 | void vector3_metric_distance(); 54 | void vector3_metric_length(); 55 | void vector3_transform_scale(); 56 | void vector3_transform_normalize(); 57 | void vector3_operators_plusequals(); 58 | void vector3_operators_minusequals(); 59 | void vector3_operators_plus(); 60 | void vector3_operators_minus(); 61 | void vector3_overload_stream_insertion(); 62 | 63 | void ray3_members(); 64 | void ray3_getters(); 65 | void ray3_constructor(); 66 | void ray3_stream_insertion(); 67 | 68 | void poly3_members(); 69 | void poly3_constructor(); 70 | void poly3_getters(); 71 | void poly3_stream_insert(); 72 | }; 73 | 74 | 75 | void TestSuite_TYPES_3D::vector3_members() 76 | { 77 | vector3_t t; 78 | TEST_ASSERT_MSG(sizeof(t.coord) == sizeof(double)*3, "coord not right size"); 79 | } 80 | 81 | void TestSuite_TYPES_3D::vector3_default_constructor() 82 | { 83 | auto absTol = double{1E-8}; 84 | 85 | vector3_t t; 86 | 87 | TEST_ASSERT_MSG(std::abs(t.coord[0] - 0) < absTol, "test 1") 88 | TEST_ASSERT_MSG(std::abs(t.coord[1] - 0) < absTol, "test 2") 89 | TEST_ASSERT_MSG(std::abs(t.coord[2] - 0) < absTol, "test 3") 90 | } 91 | 92 | void TestSuite_TYPES_3D::vector3_constructor() 93 | { 94 | auto absTol = double{1E-8}; 95 | 96 | auto x = double{1.0}; 97 | auto y = double{2.0}; 98 | auto z = double{3.0}; 99 | 100 | vector3_t t{x,y,z}; 101 | 102 | TEST_ASSERT_MSG(std::abs(t.coord[0] - x) < absTol, "test 1") 103 | TEST_ASSERT_MSG(std::abs(t.coord[1] - y) < absTol, "test 2") 104 | TEST_ASSERT_MSG(std::abs(t.coord[2] - z) < absTol, "test 3") 105 | } 106 | 107 | void TestSuite_TYPES_3D::vector3_getters() 108 | { 109 | auto absTol = double{1E-8}; 110 | 111 | auto x = double{1.0}; 112 | auto y = double{2.0}; 113 | auto z = double{3.0}; 114 | 115 | vector3_t t{x,y,z}; 116 | 117 | TEST_ASSERT_MSG(std::abs(t.x() - x) < absTol, "test 1") 118 | TEST_ASSERT_MSG(std::abs(t.y() - y) < absTol, "test 2") 119 | TEST_ASSERT_MSG(std::abs(t.z() - z) < absTol, "test 3") 120 | } 121 | 122 | void TestSuite_TYPES_3D::vector3_operators_dot() 123 | { 124 | auto absTol = double{1E-8}; 125 | 126 | auto x = double{1.0}; 127 | auto y = double{2.0}; 128 | auto z = double{3.0}; 129 | 130 | auto i = double{4.0}; 131 | auto j = double{5.0}; 132 | auto k = double{6.0}; 133 | 134 | vector3_t v1{x,y,z}; 135 | vector3_t v2{i,j,k}; 136 | 137 | double r = x*i + y*j + z*k; 138 | auto d = v1.dot(v2); 139 | 140 | TEST_ASSERT(std::abs(d-r) < absTol) 141 | } 142 | 143 | void TestSuite_TYPES_3D::vector3_operators_cross() 144 | { 145 | auto absTol = double{1E-8}; 146 | 147 | auto x = double{1.0}; 148 | auto y = double{2.0}; 149 | auto z = double{3.0}; 150 | 151 | auto i = double{4.0}; 152 | auto j = double{5.0}; 153 | auto k = double{6.0}; 154 | 155 | auto a = y*k - z*j; 156 | auto b = z*i - x*k; 157 | auto c = x*j - y*i; 158 | 159 | vector3_t v1{x,y,z}; 160 | vector3_t v2{i,j,k}; 161 | vector3_t v3{a,b,c}; 162 | 163 | auto p = v1.cross(v2); 164 | 165 | TEST_ASSERT( (std::abs(v3.x()-p.x()) < absTol) && 166 | (std::abs(v3.y()-p.y()) < absTol) && 167 | (std::abs(v3.z()-p.z()) < absTol) ) 168 | } 169 | 170 | void TestSuite_TYPES_3D::vector3_operators_project() 171 | { 172 | auto absTol = double{1E-8}; 173 | 174 | auto x = double{2.0}; 175 | auto y = double{3.0}; 176 | auto z = double{4.0}; 177 | 178 | auto i = double{1.0}; 179 | auto j = double{0.0}; 180 | auto k = double{0.0}; 181 | 182 | double r = x*i + y*j + z*k; 183 | 184 | auto a = r * i; 185 | auto b = r * j; 186 | auto c = r * k; 187 | 188 | vector3_t v1{x,y,z}; 189 | vector3_t v2{i,j,k}; 190 | vector3_t v3{a,b,c}; 191 | 192 | auto p = v1.project(v2); 193 | 194 | TEST_ASSERT( (std::abs(v3.x()-p.x()) < absTol) && 195 | (std::abs(v3.y()-p.y()) < absTol) && 196 | (std::abs(v3.z()-p.z()) < absTol) ) 197 | } 198 | 199 | void TestSuite_TYPES_3D::vector3_metric_distance() 200 | { 201 | auto absTol = double{1E-8}; 202 | 203 | auto x = double{1.0}; 204 | auto y = double{2.0}; 205 | auto z = double{3.0}; 206 | 207 | auto i = double{4.0}; 208 | auto j = double{5.0}; 209 | auto k = double{6.0}; 210 | 211 | auto d = sqrt((x-i)*(x-i) + (y-j)*(y-j) + (z-k)*(z-k)); 212 | 213 | vector3_t v1{x,y,z}; 214 | vector3_t v2{i,j,k}; 215 | 216 | auto p = v1.distance(v2); 217 | 218 | TEST_ASSERT(std::abs(d-p) < absTol) 219 | } 220 | 221 | void TestSuite_TYPES_3D::vector3_metric_length() 222 | { 223 | auto absTol = double{1E-8}; 224 | 225 | auto x = double{1.0}; 226 | auto y = double{2.0}; 227 | auto z = double{3.0}; 228 | 229 | auto r = sqrt(x*x + y*y + z*z); 230 | 231 | vector3_t v1{x,y,z}; 232 | auto p = v1.length(); 233 | 234 | TEST_ASSERT(std::abs(p-r) < absTol) 235 | } 236 | 237 | void TestSuite_TYPES_3D::vector3_transform_scale() 238 | { 239 | auto absTol = double{1E-8}; 240 | 241 | auto s = double{1.0}; 242 | 243 | auto x = double{1.0}; 244 | auto y = double{2.0}; 245 | auto z = double{3.0}; 246 | 247 | auto a = x*s; 248 | auto b = y*s; 249 | auto c = z*s; 250 | 251 | vector3_t v1{x,y,z}; 252 | v1.scale(s); 253 | 254 | TEST_ASSERT( (std::abs(v1.x()-a) < absTol) && 255 | (std::abs(v1.y()-b) < absTol) && 256 | (std::abs(v1.z()-c) < absTol) ) 257 | } 258 | 259 | void TestSuite_TYPES_3D::vector3_transform_normalize() 260 | { 261 | auto absTol = double{1E-8}; 262 | 263 | auto x = double{1.0}; 264 | auto y = double{2.0}; 265 | auto z = double{3.0}; 266 | 267 | vector3_t v1{x,y,z}; 268 | 269 | auto l = v1.length(); 270 | 271 | auto a = x/l; 272 | auto b = y/l; 273 | auto c = z/l; 274 | 275 | v1.normalize(); 276 | 277 | TEST_ASSERT( (std::abs(v1.x()-a) < absTol) && 278 | (std::abs(v1.y()-b) < absTol) && 279 | (std::abs(v1.z()-c) < absTol) ) 280 | } 281 | 282 | void TestSuite_TYPES_3D::vector3_operators_plusequals() 283 | { 284 | auto absTol = double{1E-8}; 285 | 286 | auto x = double{1.0}; 287 | auto y = double{2.0}; 288 | auto z = double{3.0}; 289 | 290 | auto i = double{4.0}; 291 | auto j = double{5.0}; 292 | auto k = double{6.0}; 293 | 294 | vector3_t v1{x,y,z}; 295 | vector3_t v2{i,j,k}; 296 | 297 | v1 += v2; 298 | 299 | TEST_ASSERT( (std::abs((x+i)-v1.x()) < absTol) && 300 | (std::abs((y+j)-v1.y()) < absTol) && 301 | (std::abs((z+k)-v1.z()) < absTol) ) 302 | } 303 | void TestSuite_TYPES_3D::vector3_operators_minusequals() 304 | { 305 | auto absTol = double{1E-8}; 306 | 307 | auto x = double{1.0}; 308 | auto y = double{2.0}; 309 | auto z = double{3.0}; 310 | 311 | auto i = double{4.0}; 312 | auto j = double{5.0}; 313 | auto k = double{6.0}; 314 | 315 | vector3_t v1{x,y,z}; 316 | vector3_t v2{i,j,k}; 317 | 318 | v1 -= v2; 319 | 320 | TEST_ASSERT( (std::abs((x-i)-v1.x()) < absTol) && 321 | (std::abs((y-j)-v1.y()) < absTol) && 322 | (std::abs((z-k)-v1.z()) < absTol) ) 323 | } 324 | 325 | void TestSuite_TYPES_3D::vector3_operators_plus() 326 | { 327 | auto absTol = double{1E-8}; 328 | 329 | auto x = double{1.0}; 330 | auto y = double{2.0}; 331 | auto z = double{3.0}; 332 | 333 | auto i = double{4.0}; 334 | auto j = double{5.0}; 335 | auto k = double{6.0}; 336 | 337 | vector3_t v1{x,y,z}; 338 | vector3_t v2{i,j,k}; 339 | 340 | auto v3 = v1 + v2; 341 | 342 | TEST_ASSERT( (std::abs((x+i)-v3.x()) < absTol) && 343 | (std::abs((y+j)-v3.y()) < absTol) && 344 | (std::abs((z+k)-v3.z()) < absTol) ) 345 | } 346 | 347 | void TestSuite_TYPES_3D::vector3_operators_minus() 348 | { 349 | auto absTol = double{1E-8}; 350 | 351 | auto x = double{1.0}; 352 | auto y = double{2.0}; 353 | auto z = double{3.0}; 354 | 355 | auto i = double{4.0}; 356 | auto j = double{5.0}; 357 | auto k = double{6.0}; 358 | 359 | vector3_t v1{x,y,z}; 360 | vector3_t v2{i,j,k}; 361 | 362 | auto v3 = v1 - v2; 363 | 364 | TEST_ASSERT( (std::abs((x-i)-v3.x()) < absTol) && 365 | (std::abs((y-j)-v3.y()) < absTol) && 366 | (std::abs((z-k)-v3.z()) < absTol) ) 367 | } 368 | 369 | void TestSuite_TYPES_3D::vector3_overload_stream_insertion() 370 | { 371 | auto x = double{1.0}; 372 | auto y = double{2.0}; 373 | auto z = double{3.0}; 374 | 375 | vector3_t v1{x,y,z}; 376 | std::stringstream si; 377 | si << v1; 378 | std::string correct = "Vector(1, 2, 3)"; 379 | 380 | TEST_ASSERT(correct.compare(si.str()) == 0) 381 | } 382 | 383 | //ray3 tests 384 | void TestSuite_TYPES_3D::ray3_members() 385 | { 386 | TEST_ASSERT(false) 387 | } 388 | 389 | void TestSuite_TYPES_3D::ray3_getters() 390 | { 391 | TEST_ASSERT(false) 392 | } 393 | 394 | void TestSuite_TYPES_3D::ray3_constructor() 395 | { 396 | TEST_ASSERT(false) 397 | } 398 | 399 | void TestSuite_TYPES_3D::ray3_stream_insertion() 400 | { 401 | TEST_ASSERT(false) 402 | } 403 | 404 | //poly3 tests 405 | void TestSuite_TYPES_3D::poly3_members() 406 | { 407 | TEST_ASSERT(false) 408 | } 409 | 410 | void TestSuite_TYPES_3D::poly3_constructor() 411 | { 412 | TEST_ASSERT(false) 413 | } 414 | 415 | void TestSuite_TYPES_3D::poly3_getters() 416 | { 417 | TEST_ASSERT(false) 418 | } 419 | 420 | void TestSuite_TYPES_3D::poly3_stream_insert() 421 | { 422 | TEST_ASSERT(false) 423 | } 424 | 425 | #endif //OCTREE_TYPES_3D_UNIT_H -------------------------------------------------------------------------------- /Octree/src/unit_tests.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include "types_3d_unit.h" 7 | #include "collisions_unit.h" 8 | 9 | int main() 10 | { 11 | Test::Suite ts; 12 | 13 | #pragma clang diagnostic ignored "-Wdeprecated-declarations" 14 | ts.add(std::auto_ptr(new TestSuite_TYPES_3D)); 15 | ts.add(std::auto_ptr(new TestSuite_COLLISIONS)); 16 | 17 | //Test::TextOutput output(Test::TextOutput::Verbose); 18 | Test::HtmlOutput output; 19 | 20 | // run the tests 21 | auto result = ts.run(output); 22 | 23 | std::ofstream f; 24 | f.open("results.html"); 25 | //output.generate(std::cout, true, "MyTest"); // can output directly to terminal 26 | output.generate(f, true, "Octree"); 27 | 28 | return result; 29 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Projects 2 | ======== 3 | 4 | Location for Miscellaneous Projects. 5 | 6 | For write-ups, see my blog at http://kevinsprojects.wordpress.com/ 7 | -------------------------------------------------------------------------------- /Sallen Key Solver/README.md: -------------------------------------------------------------------------------- 1 | Sallen-Key Filter Simulated Annealing Optimizer 2 | ============================= 3 | 4 | To run, execute the following command: 5 | 6 | >> python SallenKey_Design.py 7 | 8 | Required Packages 9 | ----------------- 10 | * Numpy 11 | * Scipy 12 | * Matplotlib 13 | 14 | -------------------------------------------------------------------------------- /Sallen Key Solver/SallenKey_Design.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | from __future__ import division 4 | 5 | import math 6 | import random 7 | 8 | import matplotlib.pyplot as plt 9 | import scipy.signal as sig 10 | 11 | from itertools import product 12 | from misc import common_part_values, metric_prefix 13 | from anneal import Annealer 14 | 15 | # Setup optimization targets 16 | target_q = 0.707 # 1/sqrt(2) - Which is the maximally flat response 17 | target_freq = 500 # Hz 18 | target_atten = -40 # dB 19 | 20 | rvalues, cvalues = common_part_values() 21 | 22 | 23 | def f0(system): 24 | """Return the natural frequency of the system.""" 25 | c1,c2,r1,r2 = system 26 | fn = 1 / (2 * math.pi * math.sqrt(r1 * c1 * r2 * c2)) 27 | return fn 28 | 29 | 30 | def q(system): 31 | """Return the Q Value of the system.""" 32 | c1,c2,r1,r2 = system 33 | q = math.sqrt(c1 * c2 * r1 * r2)/ (c2 * (r1 + r2)) 34 | return q 35 | 36 | 37 | def frf(system): 38 | """Return the Frequency Response Function of the system. 39 | 40 | Returns a function which takes a frequency as an argument. 41 | This function when evaluated at any frequency returns the complex 42 | frequency response at that frequency. 43 | 44 | Example: frf(system)(10) returns the complex FRF at 10 Hz 45 | """ 46 | def internal(f): 47 | c1,c2,r1,r2 = system 48 | w = 2 * math.pi * f 49 | num = 1 / (c1*c2*r1*r2) 50 | den = 1 / (c1*c2*r1*r2) + (r1+r2)/(c1*r1*r2) * 1j*w - w**2 51 | return num/den 52 | 53 | return internal 54 | 55 | 56 | def dB(x): 57 | """Returns the argument in decibels""" 58 | return 20 * math.log10(abs(x)) 59 | 60 | 61 | def stepResponse(system): 62 | """Computes the step response for a given system""" 63 | c1,c2,r1,r2 = system 64 | num = 1 / (c1*c2*r1*r2) 65 | den = (1, (r1+r2)/(c1*r1*r2), 1/(c1*c2*r1*r2)) 66 | return sig.step((num,den)) 67 | 68 | 69 | def energy(system): 70 | """Computes the energy of a given system. 71 | 72 | The energy is defined as decreasing towards zero as the system 73 | approaches an ideal system. 74 | """ 75 | 76 | frf_ = frf(system) 77 | f0_ = f0(system) 78 | q_ = q(system) 79 | c1,c2,r1,r2 = system 80 | 81 | e = 0 82 | e += abs(target_atten - dB(frf_(target_freq))) / abs(target_atten) # percent error off frequency @ attenuation 83 | e += abs(target_q - q_) / abs(target_q) # percent error off ideal Q value 84 | e += abs(c1-c2) / abs((c1+c2)/2) * 0.1 # percent difference in capacitor values 85 | e += abs(r1-r2) / abs((r1+r2)/2) * 0.1 # percent difference in resistor values 86 | 87 | return e 88 | 89 | 90 | def move(system): 91 | """ Changes the system randomly 92 | 93 | This function makes a random change to one of the component values 94 | in the system. 95 | """ 96 | component = random.randrange(0, 4) 97 | 98 | if component == 0: 99 | index = random.randrange(0, len(cvalues)) 100 | system[0] = cvalues[index] 101 | elif component == 1: 102 | index = random.randrange(0, len(cvalues)) 103 | system[1] = cvalues[index] 104 | elif component == 2: 105 | index = random.randrange(0, len(rvalues)) 106 | system[2] = rvalues[index] 107 | elif component == 3: 108 | index = random.randrange(0, len(rvalues)) 109 | system[3] = rvalues[index] 110 | 111 | 112 | if __name__ == '__main__': 113 | 114 | # set up simulated annealing algorithm 115 | units=('F', 'F', u'Ω', u'Ω') # units of the values in the system 116 | initial_system = [cvalues[0], cvalues[0], rvalues[0], rvalues[0]] 117 | annealer = Annealer(energy, move) 118 | schedule = annealer.auto(initial_system, minutes=0.1) 119 | 120 | # run simulated annealing algorithm and compute properties of the final system 121 | final_system, error = annealer.anneal(initial_system, schedule['tmax'], schedule['tmin'], schedule['steps'], updates=100) 122 | final_frf = frf(final_system) 123 | final_f0 = f0(final_system) 124 | final_q = q(final_system) 125 | final_vals = [metric_prefix(*s) for s in zip(final_system, units)] 126 | 127 | print 'Soln: (%s), Remaining Energy: %s' % (', '.join(final_vals), error) 128 | 129 | # calculate data for graphs 130 | freqs = range(1000000) # response from 0 Hz to 1 MHz 131 | response = [dB(final_frf(f)) for f in freqs] 132 | natural = final_f0, dB(final_frf(final_f0)) 133 | target = target_freq, dB(final_frf(target_freq)) 134 | step_freqs, step_response = stepResponse(final_system) 135 | 136 | 137 | plt.figure() 138 | 139 | # bode response plot 140 | ax = plt.subplot(2,1,1) 141 | plt.semilogx(freqs,response) 142 | plt.semilogx(natural[0], natural[1], 'r+', ms=10) 143 | plt.annotate('Natural Freq: (%.2f Hz, %.2f dB) ' % natural, xy=natural, xytext=(10,10), textcoords='offset points') 144 | plt.semilogx(target[0], target[1], 'r+', ms=10) 145 | plt.annotate('target attenuation: (%.2f Hz, %.2f dB)'%target, xy=target, xytext=(10,10), textcoords='offset points') 146 | plt.title('Bode Plot (F0: %.2f Hz, Q-Factor: %.2f)\n' % (final_f0, final_q) + 'Soln: (%s)' % ', '.join(final_vals)) 147 | plt.xlabel('Frequency [Hz]') 148 | plt.ylabel('Gain [dB]') 149 | 150 | lims=list(ax.get_ylim()) 151 | lims[1]=20 152 | plt.ylim(lims) 153 | 154 | # step response plot 155 | plt.subplot(2,1,2) 156 | plt.plot(step_freqs, step_response) 157 | plt.title('Step Response') 158 | plt.xlabel('Time (s)') 159 | plt.ylabel('Response (v)') 160 | 161 | plt.show() 162 | 163 | 164 | """ 165 | References: 166 | [1] http://en.wikipedia.org/wiki/Sallen%E2%80%93Key_topology 167 | [2] http://en.wikipedia.org/wiki/Q_factor 168 | [3] http://sim.okawa-denshi.jp/en/OPstool.php 169 | [4] http://www.falstad.com/circuit/ 170 | """ 171 | 172 | -------------------------------------------------------------------------------- /Sallen Key Solver/anneal.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # Python module for simulated annealing - anneal.py - v1.0 - 2 Sep 2009 3 | # 4 | # Copyright (c) 2009, Richard J. Wagner 5 | # 6 | # Permission to use, copy, modify, and/or distribute this software for any 7 | # purpose with or without fee is hereby granted, provided that the above 8 | # copyright notice and this permission notice appear in all copies. 9 | # 10 | # THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 | # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 | # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 | # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 | # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 | # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 | # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 | 18 | """ 19 | This module performs simulated annealing to find a state of a system that 20 | minimizes its energy. 21 | 22 | An example program demonstrates simulated annealing with a traveling 23 | salesman problem to find the shortest route to visit the twenty largest 24 | cities in the United States. 25 | 26 | Notes: 27 | Matt Perry 6/24/12 28 | Changed to slicing lists instead of deepcopy-ing them. 29 | e.g. state = prevState[:] instead of state = deepcopy(prevState) 30 | Huge performance enhancement (~5-10x faster) 31 | Should be identical behavior if the items in the state list are immutable. 32 | (immutable objects include integers and strings so should be safe) 33 | """ 34 | 35 | # How to optimize a system with simulated annealing: 36 | # 37 | # 1) Define a format for describing the state of the system. 38 | # 39 | # 2) Define a function to calculate the energy of a state. 40 | # 41 | # 3) Define a function to make a random change to a state. 42 | # 43 | # 4) Choose a maximum temperature, minimum temperature, and number of steps. 44 | # 45 | # 5) Set the annealer to work with your state and functions. 46 | # 47 | # 6) Study the variation in energy with temperature and duration to find a 48 | # productive annealing schedule. 49 | # 50 | # Or, 51 | # 52 | # 4) Run the automatic annealer which will attempt to choose reasonable values 53 | # for maximum and minimum temperatures and then anneal for the allotted time. 54 | 55 | import copy, math, sys, time 56 | try: 57 | from numpy import random 58 | except ImportError: 59 | import random 60 | 61 | def round_figures(x, n): 62 | """Returns x rounded to n significant figures.""" 63 | return round(x, int(n - math.ceil(math.log10(abs(x))))) 64 | 65 | def time_string(seconds): 66 | """Returns time in seconds as a string formatted HHHH:MM:SS.""" 67 | s = int(round(seconds)) # round to nearest second 68 | h, s = divmod(s, 3600) # get hours and remainder 69 | m, s = divmod(s, 60) # split remainder into minutes and seconds 70 | return '%4i:%02i:%02i' % (h, m, s) 71 | 72 | class Annealer: 73 | """Performs simulated annealing by calling functions to calculate 74 | energy and make moves on a state. The temperature schedule for 75 | annealing may be provided manually or estimated automatically. 76 | """ 77 | def __init__(self, energy, move): 78 | self.energy = energy # function to calculate energy of a state 79 | self.move = move # function to make a random change to a state 80 | 81 | def anneal(self, state, Tmax, Tmin, steps, updates=0): 82 | """Minimizes the energy of a system by simulated annealing. 83 | 84 | Keyword arguments: 85 | state -- an initial arrangement of the system 86 | Tmax -- maximum temperature (in units of energy) 87 | Tmin -- minimum temperature (must be greater than zero) 88 | steps -- the number of steps requested 89 | updates -- the number of updates to print during annealing 90 | 91 | Returns the best state and energy found.""" 92 | 93 | step = 0 94 | start = time.time() 95 | 96 | def update(T, E, acceptance, improvement): 97 | """Prints the current temperature, energy, acceptance rate, 98 | improvement rate, elapsed time, and remaining time. 99 | 100 | The acceptance rate indicates the percentage of moves since the last 101 | update that were accepted by the Metropolis algorithm. It includes 102 | moves that decreased the energy, moves that left the energy 103 | unchanged, and moves that increased the energy yet were reached by 104 | thermal excitation. 105 | 106 | The improvement rate indicates the percentage of moves since the 107 | last update that strictly decreased the energy. At high 108 | temperatures it will include both moves that improved the overall 109 | state and moves that simply undid previously accepted moves that 110 | increased the energy by thermal excititation. At low temperatures 111 | it will tend toward zero as the moves that can decrease the energy 112 | are exhausted and moves that would increase the energy are no longer 113 | thermally accessible.""" 114 | 115 | elapsed = time.time() - start 116 | if step == 0: 117 | print ' Temperature Energy Accept Improve Elapsed Remaining' 118 | print '%12.2f %12.2f %s ' % \ 119 | (T, E, time_string(elapsed) ) 120 | else: 121 | remain = ( steps - step ) * ( elapsed / step ) 122 | print '%12.2f %12.2f %7.2f%% %7.2f%% %s %s' % \ 123 | (T, E, 100.0*acceptance, 100.0*improvement, 124 | time_string(elapsed), time_string(remain)) 125 | 126 | # Precompute factor for exponential cooling from Tmax to Tmin 127 | if Tmin <= 0.0: 128 | print 'Exponential cooling requires a minimum temperature greater than zero.' 129 | sys.exit() 130 | Tfactor = -math.log( float(Tmax) / Tmin ) 131 | 132 | # Note initial state 133 | T = Tmax 134 | E = self.energy(state) 135 | #prevState = copy.deepcopy(state) 136 | prevState = state[:] 137 | prevEnergy = E 138 | #bestState = copy.deepcopy(state) 139 | bestState = state[:] 140 | bestEnergy = E 141 | trials, accepts, improves = 0, 0, 0 142 | if updates > 0: 143 | updateWavelength = float(steps) / updates 144 | update(T, E, None, None) 145 | 146 | # Attempt moves to new states 147 | while step < steps: 148 | step += 1 149 | T = Tmax * math.exp( Tfactor * step / steps ) 150 | self.move(state) 151 | E = self.energy(state) 152 | dE = E - prevEnergy 153 | trials += 1 154 | if dE > 0.0 and math.exp(-dE/T) < random.random(): 155 | # Restore previous state 156 | #state = copy.deepcopy(prevState) 157 | state = prevState[:] 158 | E = prevEnergy 159 | else: 160 | # Accept new state and compare to best state 161 | accepts += 1 162 | if dE < 0.0: 163 | improves += 1 164 | #prevState = copy.deepcopy(state) 165 | prevState = state[:] 166 | prevEnergy = E 167 | if E < bestEnergy: 168 | #bestState = copy.deepcopy(state) 169 | bestState = state[:] 170 | bestEnergy = E 171 | if updates > 1: 172 | if step // updateWavelength > (step-1) // updateWavelength: 173 | update(T, E, float(accepts)/trials, float(improves)/trials) 174 | trials, accepts, improves = 0, 0, 0 175 | 176 | # Return best state and energy 177 | return bestState, bestEnergy 178 | 179 | def auto(self, state, minutes, steps=2000): 180 | """Minimizes the energy of a system by simulated annealing with 181 | automatic selection of the temperature schedule. 182 | 183 | Keyword arguments: 184 | state -- an initial arrangement of the system 185 | minutes -- time to spend annealing (after exploring temperatures) 186 | steps -- number of steps to spend on each stage of exploration 187 | 188 | Returns the best state and energy found.""" 189 | 190 | def run(state, T, steps): 191 | """Anneals a system at constant temperature and returns the state, 192 | energy, rate of acceptance, and rate of improvement.""" 193 | E = self.energy(state) 194 | #prevState = copy.deepcopy(state) 195 | prevState = state[:] 196 | prevEnergy = E 197 | accepts, improves = 0, 0 198 | for step in range(steps): 199 | self.move(state) 200 | E = self.energy(state) 201 | dE = E - prevEnergy 202 | if dE > 0.0 and math.exp(-dE/T) < random.random(): 203 | #state = copy.deepcopy(prevState) 204 | state = prevState[:] 205 | E = prevEnergy 206 | else: 207 | accepts += 1 208 | if dE < 0.0: 209 | improves += 1 210 | #prevState = copy.deepcopy(state) 211 | prevState = state[:] 212 | prevEnergy = E 213 | return state, E, float(accepts)/steps, float(improves)/steps 214 | 215 | step = 0 216 | start = time.time() 217 | 218 | print 'Attempting automatic simulated anneal...' 219 | 220 | # Find an initial guess for temperature 221 | T = 0.0 222 | E = self.energy(state) 223 | while T == 0.0: 224 | step += 1 225 | self.move(state) 226 | T = abs( self.energy(state) - E ) 227 | 228 | print 'Exploring temperature landscape:' 229 | print ' Temperature Energy Accept Improve Elapsed' 230 | def update(T, E, acceptance, improvement): 231 | """Prints the current temperature, energy, acceptance rate, 232 | improvement rate, and elapsed time.""" 233 | elapsed = time.time() - start 234 | print '%12.2f %12.2f %7.2f%% %7.2f%% %s' % \ 235 | (T, E, 100.0*acceptance, 100.0*improvement, time_string(elapsed)) 236 | 237 | # Search for Tmax - a temperature that gives 98% acceptance 238 | state, E, acceptance, improvement = run(state, T, steps) 239 | step += steps 240 | while acceptance > 0.98: 241 | T = round_figures(T/1.5, 2) 242 | state, E, acceptance, improvement = run(state, T, steps) 243 | step += steps 244 | update(T, E, acceptance, improvement) 245 | while acceptance < 0.98: 246 | T = round_figures(T*1.5, 2) 247 | state, E, acceptance, improvement = run(state, T, steps) 248 | step += steps 249 | update(T, E, acceptance, improvement) 250 | Tmax = T 251 | 252 | # Search for Tmin - a temperature that gives 0% improvement 253 | while improvement > 0.0: 254 | T = round_figures(T/1.5, 2) 255 | state, E, acceptance, improvement = run(state, T, steps) 256 | step += steps 257 | update(T, E, acceptance, improvement) 258 | Tmin = T 259 | 260 | # Calculate anneal duration 261 | elapsed = time.time() - start 262 | duration = round_figures(int(60.0 * minutes * step / elapsed), 2) 263 | 264 | # MP: Don't perform anneal, just return params 265 | #return self.anneal(state, Tmax, Tmin, duration, 20) 266 | return {'tmax': Tmax, 'tmin': Tmin, 'steps': duration} 267 | 268 | if __name__ == '__main__': 269 | """Test annealer with a traveling salesman problem.""" 270 | 271 | # List latitude and longitude (degrees) for the twenty largest U.S. cities 272 | cities = { 'New York City': (40.72,74.00), 'Los Angeles': (34.05,118.25), 273 | 'Chicago': (41.88,87.63), 'Houston': (29.77,95.38), 274 | 'Phoenix': (33.45,112.07), 'Philadelphia': (39.95,75.17), 275 | 'San Antonio': (29.53,98.47), 'Dallas': (32.78,96.80), 276 | 'San Diego': (32.78,117.15), 'San Jose': (37.30,121.87), 277 | 'Detroit': (42.33,83.05), 'San Francisco': (37.78,122.42), 278 | 'Jacksonville': (30.32,81.70), 'Indianapolis': (39.78,86.15), 279 | 'Austin': (30.27,97.77), 'Columbus': (39.98,82.98), 280 | 'Fort Worth': (32.75,97.33), 'Charlotte': (35.23,80.85), 281 | 'Memphis': (35.12,89.97), 'Baltimore': (39.28,76.62) } 282 | 283 | def distance(a, b): 284 | """Calculates distance between two latitude-longitude coordinates.""" 285 | R = 3963 # radius of Earth (miles) 286 | lat1, lon1 = math.radians(a[0]), math.radians(a[1]) 287 | lat2, lon2 = math.radians(b[0]), math.radians(b[1]) 288 | return math.acos( math.sin(lat1)*math.sin(lat2) + 289 | math.cos(lat1)*math.cos(lat2)*math.cos(lon1-lon2) ) * R 290 | 291 | def route_move(state): 292 | """Swaps two cities in the route.""" 293 | a = random.randint( 0, len(state)-1 ) 294 | b = random.randint( 0, len(state)-1 ) 295 | state[a], state[b] = state[b], state[a] 296 | 297 | def route_energy(state): 298 | """Calculates the length of the route.""" 299 | e = 0 300 | for i in range(len(state)): 301 | e += distance( cities[state[i-1]], cities[state[i]] ) 302 | return e 303 | 304 | # Start with the cities listed in random order 305 | state = cities.keys() 306 | random.shuffle(state) 307 | 308 | # Minimize the distance to be traveled by simulated annealing with a 309 | # manually chosen temperature schedule 310 | annealer = Annealer(route_energy, route_move) 311 | state, e = annealer.anneal(state, 10000000, 0.01, 18000*len(state), 9) 312 | while state[0] != 'New York City': 313 | state = state[1:] + state[:1] # rotate NYC to start 314 | print "%i mile route:" % route_energy(state) 315 | for city in state: 316 | print "\t", city 317 | 318 | # Minimize the distance to be traveled by simulated annealing with an 319 | # automatically chosen temperature schedule 320 | state, e = annealer.auto(state, 4) 321 | while state[0] != 'New York City': 322 | state = state[1:] + state[:1] # rotate NYC to start 323 | print "%i mile route:" % route_energy(state) 324 | for city in state: 325 | print "\t", city 326 | 327 | sys.exit() 328 | -------------------------------------------------------------------------------- /Sallen Key Solver/misc.py: -------------------------------------------------------------------------------- 1 | from itertools import product 2 | 3 | def common_part_values(): 4 | """ Returns a list of common capacitor and resistor values. 5 | 6 | Resistor values are in ohms (1 ohm to 9.1 MOhm) 7 | Capacitor values are in farads (1e-11 F to 8.2e-7 F) = (10 pF to 820 nF) 8 | """ 9 | rexponent = [1, 10, 100, 1000, 10000, 100000] 10 | rmantissa = [1.0, 1.1, 1.2, 1.3, 1.5, 1.6, 1.8, 2.0, 2.2, 2.4, 2.7, 3.0, 3.3, 3.6, 3.9, 4.3, 4.7, 5.1, 5.6, 6.2, 6.8, 7.5, 8.2, 9.1] 11 | rvalues = [x[0]*x[1] for x in product(rexponent, rmantissa)] 12 | 13 | cexponent = [x * 1e-12 for x in [1, 10, 100, 1000, 1000, 10000]] 14 | cmantissa = [10, 12, 15, 18, 22, 27, 33, 39, 47, 56, 68, 82] 15 | cvalues = [x[0]*x[1] for x in product(cexponent, cmantissa)] 16 | 17 | return rvalues,cvalues 18 | 19 | def frexp_10(decimal): 20 | "Splits a float into it's base 10 mantissa and exponent" 21 | parts = ("%e" % decimal).split('e') 22 | return float(parts[0]), int(parts[1]) 23 | 24 | def metric_prefix(decimal, unit): 25 | """ Transforms a decimal value into a metric prefix 26 | 27 | E.G (1e-8 F) => (10 nF) 28 | """ 29 | mantissa, power = frexp_10(decimal) 30 | prefixes = {-12:'p', -9:'n', -6:'u', -3:'m', 0:'', 3:'k', 6:'M'} 31 | for p in prefixes.iteritems(): 32 | if p[0] <= power < p[0]+3: 33 | if p[0] == 0: 34 | # no prefix, between 0.1 and 10 35 | return '%s %s' % (mantissa * 10**(power-p[0]), unit) 36 | else: 37 | # has a prefix 38 | return '%s %s%s' % (mantissa * 10**(power-p[0]), p[1], unit) -------------------------------------------------------------------------------- /Sallen Key Solver/results/SA_results.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KevinNJ/Projects/7b3268a808b76e85aab5981b35b22710ed7c4300/Sallen Key Solver/results/SA_results.png -------------------------------------------------------------------------------- /Short Time Fourier Transform/.gitignore: -------------------------------------------------------------------------------- 1 | resources 2 | -------------------------------------------------------------------------------- /Short Time Fourier Transform/BuildQtGui.py: -------------------------------------------------------------------------------- 1 | __author__ = 'knelson' 2 | 3 | def make_gui(filename): 4 | """Makes a .py file from a .ui file. 5 | 6 | Assumes that the pyside-uic script is installed in the local Anaconda directory 7 | """ 8 | 9 | from subprocess import check_call 10 | import os 11 | 12 | cmd = os.path.normpath('C:\Anaconda\Scripts\pyside-uic') 13 | infile = filename + '.ui' 14 | outfile = filename + '.py' 15 | 16 | call_args = [cmd, infile, '-o', outfile] 17 | print call_args 18 | 19 | check_call(call_args) -------------------------------------------------------------------------------- /Short Time Fourier Transform/ParseMathExp.py: -------------------------------------------------------------------------------- 1 | __author__ = 'knelson' 2 | 3 | import ast 4 | import operator as op 5 | 6 | ''' 7 | Notes: 8 | Code taken from stack overflow answer located here: 9 | http://stackoverflow.com/a/9558001 10 | 11 | 12 | ''' 13 | 14 | operators = {ast.Add: op.add, ast.Sub: op.sub, ast.Mult: op.mul, 15 | ast.Div: op.truediv, ast.Pow: op.pow, ast.USub: op.neg} 16 | 17 | def eval_expr(expr): 18 | """Safely evaluate and return the result of a math expression 19 | 20 | Example: 21 | print eval_expr('2**2') 22 | >> 4 23 | """ 24 | return eval_node(ast.parse(expr, mode='eval').body) 25 | 26 | 27 | def eval_node(node): 28 | """Recursively parse math expression using AST""" 29 | 30 | if isinstance(node, ast.Num): # 31 | return node.n 32 | elif isinstance(node, ast.BinOp): # 33 | return operators[type(node.op)](eval_node(node.left), eval_node(node.right)) 34 | elif isinstance(node, ast.UnaryOp): # e.g., -1 35 | return operators[type(node.op)](eval_node(node.operand)) 36 | else: 37 | raise TypeError(node) -------------------------------------------------------------------------------- /Short Time Fourier Transform/README.md: -------------------------------------------------------------------------------- 1 | Short Time Fourier Transform 2 | ============================= 3 | 4 | To run, execute the following command: 5 | 6 | >> python Stft.py 7 | 8 | Required Packages 9 | ----------------- 10 | * Numpy 11 | * Scipy 12 | * Matplotlib 13 | * PySide 14 | -------------------------------------------------------------------------------- /Short Time Fourier Transform/Stft.py: -------------------------------------------------------------------------------- 1 | __author__ = 'kevin.nelson' 2 | 3 | import sys 4 | import numpy as np 5 | import scipy.signal as sig 6 | import scipy.io.wavfile as wav 7 | import matplotlib 8 | matplotlib.use('Qt4Agg') 9 | matplotlib.rcParams['backend.qt4']='PySide' 10 | 11 | from PySide.QtGui import QApplication, QMainWindow 12 | 13 | from ParseMathExp import eval_expr 14 | from BuildQtGui import make_gui 15 | 16 | class Stft(object): 17 | """Computes the short time fourier transform of a signal 18 | 19 | How to use: 20 | 1.) Pass the signal into the class, 21 | 2.) Call stft() to get the transformed data 22 | 3.) Call freq_axis() and time_axis() to get the freq and time values for each index in the array 23 | 24 | """ 25 | def __init__(self, data, fs, win_size, fft_size, overlap_fac=0.5): 26 | """Computes a bunch of information that will be used in all of the STFT functions""" 27 | self.data = np.array(data, dtype=np.float32) 28 | self.fs = np.int32(fs) 29 | self.win_size = np.int32(win_size) 30 | self.fft_size = np.int32(fft_size) 31 | self.overlap_fac = np.float32(1 - overlap_fac) 32 | 33 | self.hop_size = np.int32(np.floor(self.win_size * self.overlap_fac)) 34 | self.pad_end_size = self.fft_size 35 | self.total_segments = np.int32(np.ceil(len(self.data) / np.float32(self.hop_size))) 36 | self.t_max = len(self.data) / np.float32(self.fs) 37 | 38 | def stft(self, scale='log', ref=1, clip=None): 39 | """Perform the STFT and return the result""" 40 | 41 | # Todo: changing the overlap factor doens't seem to preserve energy, need to fix this 42 | window = np.hanning(self.win_size) * self.overlap_fac * 2 43 | inner_pad = np.zeros((self.fft_size * 2) - self.win_size) 44 | 45 | proc = np.concatenate((self.data, np.zeros(self.pad_end_size))) 46 | result = np.empty((self.total_segments, self.fft_size), dtype=np.float32) 47 | 48 | for i in xrange(self.total_segments): 49 | current_hop = self.hop_size * i 50 | segment = proc[current_hop:current_hop+self.win_size] 51 | windowed = segment * window 52 | padded = np.append(windowed, inner_pad) 53 | spectrum = np.fft.fft(padded) / self.fft_size 54 | autopower = np.abs(spectrum * np.conj(spectrum)) 55 | result[i, :] = autopower[:self.fft_size] 56 | 57 | if scale == 'log': 58 | result = self.dB(result, ref) 59 | 60 | if clip is not None: 61 | np.clip(result, clip[0], clip[1], out=result) 62 | 63 | return result 64 | 65 | def dB(self, data, ref): 66 | """Return the dB equivelant of the input data""" 67 | return 20*np.log10(data / ref) 68 | 69 | def freq_axis(self): 70 | """Returns a list of frequencies which correspond to the bins in the returned data from stft()""" 71 | return np.arange(self.fft_size) / np.float32(self.fft_size * 2) * self.fs 72 | 73 | def time_axis(self): 74 | """Returns a list of times which correspond to the bins in the returned data from stft()""" 75 | return np.arange(self.total_segments) / np.float32(self.total_segments) * self.t_max 76 | 77 | 78 | def create_ticks_optimum(axis, num_ticks, resolution, return_errors=False): 79 | """ Try to divide ticks evenly across the axis, keeping ticks to the nearest """ 80 | max_val = axis[-1] 81 | hop_size = max_val / np.float32(num_ticks) 82 | 83 | indicies = [] 84 | ideal_vals = [] 85 | errors = [] 86 | 87 | for i in range(num_ticks): 88 | current_hop = resolution * round(float(i*hop_size)/resolution) 89 | index = np.abs(axis-current_hop).argmin() 90 | 91 | indicies.append(index) 92 | ideal_vals.append(current_hop) 93 | errors.append(np.abs(current_hop - axis[index])) 94 | 95 | if return_errors: 96 | return indicies, ideal_vals, errors 97 | else: 98 | return indicies, ideal_vals 99 | 100 | 101 | class StftGui(QMainWindow): 102 | """The gui for the STFT application""" 103 | def __init__(self, filename, parent=None): 104 | super(StftGui, self).__init__(parent) 105 | self.ui = Ui_MainWindow() 106 | self.ui.setupUi(self) 107 | 108 | self.ui.render.clicked.connect(self.on_render) 109 | self.ui.mpl.onResize.connect(self.redraw) 110 | self.init(filename) 111 | 112 | def init(self, filename): 113 | self.fs, self.data = wav.read(filename) 114 | if len(self.data.shape) > 1: 115 | # if there are multiple channels, pick the first one. 116 | self.data = self.data[...,0] 117 | 118 | self.on_render() 119 | 120 | def redraw(self, *args, **kwargs): 121 | fig = self.ui.mpl.fig 122 | fig.tight_layout() 123 | self.ui.mpl.draw() 124 | 125 | def on_render(self): 126 | # get data from GUI 127 | downsample_fac = int(eval_expr(self.ui.downsample_fac.text())) 128 | win_size = int(eval_expr(self.ui.win_size.text())) 129 | fft_size = int(eval_expr(self.ui.fft_size.text())) 130 | overlap_fac = float(eval_expr(self.ui.overlap_fac.text())) 131 | clip_min, clip_max = float(eval_expr(self.ui.clip_min.text())), float(eval_expr(self.ui.clip_max.text())) 132 | x_tick_num, x_res = int(eval_expr(self.ui.x_num_ticks.text())), float(eval_expr(self.ui.x_resolution.text())) 133 | x_tick_rotation = int(eval_expr(self.ui.x_tick_rotation.text())) 134 | y_ticks_num, y_res = int(eval_expr(self.ui.y_num_ticks.text())), float(eval_expr(self.ui.y_resolution.text())) 135 | 136 | 137 | if downsample_fac > 1: 138 | downsampled_data = sig.decimate(self.data, downsample_fac, ftype='fir') 139 | downsampled_fs = self.fs / downsample_fac 140 | else: 141 | downsampled_data = self.data 142 | downsampled_fs = self.fs 143 | 144 | ft = Stft(downsampled_data, downsampled_fs, win_size=win_size, fft_size=fft_size, overlap_fac=overlap_fac) 145 | result = ft.stft(clip=(clip_min, clip_max)) 146 | 147 | x_ticks, x_tick_labels = create_ticks_optimum(ft.freq_axis(), num_ticks=x_tick_num, resolution=x_res) 148 | y_ticks, y_tick_labels = create_ticks_optimum(ft.time_axis(), num_ticks=y_ticks_num, resolution=y_res) 149 | 150 | fig = self.ui.mpl.fig 151 | fig.clear() 152 | ax = fig.add_subplot(111) 153 | 154 | img = ax.imshow(result, origin='lower', cmap='jet', interpolation='none', aspect='auto') 155 | 156 | ax.set_xticks(x_ticks) 157 | ax.set_xticklabels(x_tick_labels, rotation=x_tick_rotation) 158 | ax.set_yticks(y_ticks) 159 | ax.set_yticklabels(y_tick_labels) 160 | 161 | if self.ui.x_grid.isChecked(): 162 | ax.xaxis.grid(True, linestyle='-', linewidth=1) 163 | 164 | if self.ui.y_grid.isChecked(): 165 | ax.yaxis.grid(True, linestyle='-', linewidth=1) 166 | 167 | ax.set_xlabel('Frequency [Hz]') 168 | ax.set_ylabel('Time [s]') 169 | 170 | fig.colorbar(img) 171 | fig.tight_layout() 172 | 173 | self.ui.mpl.draw() 174 | 175 | self.ui.sampling_freq.setText('%d' % downsampled_fs) 176 | self.ui.data_length.setText('%.2f' % ft.t_max) 177 | self.ui.freq_res.setText('%s' % (downsampled_fs * 0.5 / np.float32(ft.fft_size))) 178 | 179 | 180 | if __name__ == '__main__': 181 | import os.path as path 182 | make_gui('sfft_gui') 183 | from sfft_gui import Ui_MainWindow 184 | 185 | 186 | filename = path.join('media','mike_chirp.wav') 187 | #filename = 'mike_annoying.wav' 188 | #filename = 'New Seal and New Spring_conv.wav' 189 | 190 | app = QApplication(sys.argv) 191 | win = StftGui(filename) 192 | win.show() 193 | app.exec_() -------------------------------------------------------------------------------- /Short Time Fourier Transform/archive/half_cosine.py: -------------------------------------------------------------------------------- 1 | __author__ = 'knelson' 2 | 3 | import numpy as np 4 | import matplotlib.pyplot as plt 5 | 6 | 7 | def half_cosine(window, total_segments, hop_size): 8 | win_length = window.shape 9 | total_length = win_length + hop_size*(total_segments-1) 10 | result = np.zeros(total_length) 11 | 12 | for i in xrange(total_segments): 13 | current_loc = i*hop_size 14 | result[current_loc:current_loc+win_length] += window 15 | 16 | plt.figure() 17 | plt.plot(result) 18 | plt.ylim([0, 1.2]) 19 | plt.show() 20 | 21 | 22 | if __name__ == '__main__': 23 | win_length = 500 24 | overlap = 1 - 0.5 25 | segments = 10 26 | total_length = np.int32(win_length + (win_length * overlap)*(segments-1)) 27 | hop_length = np.int32(win_length * overlap) 28 | 29 | print 'win length:', win_length 30 | print 'overlap_fac:', overlap 31 | print 'segments:', segments 32 | print 'total_length:', total_length 33 | print 'hop_length:', hop_length 34 | print '' 35 | 36 | win = np.hanning(win_length) * overlap * 2 37 | result = np.zeros(total_length) 38 | 39 | for i in xrange(segments): 40 | current_loc = i*hop_length 41 | print 'current location:', current_loc 42 | result[current_loc:current_loc+win_length] += win 43 | 44 | print ' '.join(map(lambda x: '%.4f'%x, result)) 45 | 46 | plt.plot(result) 47 | plt.ylim([0, 1.2]) 48 | plt.show() 49 | 50 | -------------------------------------------------------------------------------- /Short Time Fourier Transform/archive/stft.py: -------------------------------------------------------------------------------- 1 | __author__ = 'kevin.nelson' 2 | 3 | import numpy as np 4 | import scipy as sp 5 | import scipy.signal as sig 6 | from math import floor 7 | 8 | def stft(data, win_size, fft_size, overlap_fac): 9 | win = np.hanning(win_size) 10 | hop_size = int(floor(win_size * overlap_fac)) 11 | 12 | data = np.array(data) 13 | pad_start = np.zeros(win_size // 2, dtype=data.dtype) 14 | pad_end = np.zeros(win_size, dtype=data.dtype) 15 | 16 | proc = np.concatenate((pad_start, data, pad_end)) 17 | 18 | total_segments = (pad_start.shape[0]+data.shape[0]) / hop_size # int/int returns floor of result 19 | result = np.empty((total_segments, fft_size), dtype=np.float32) 20 | 21 | inner_pad = np.zeros(fft_size*2-win_size) 22 | 23 | for i in range(total_segments): 24 | current_loc = hop_size*i 25 | segment = proc[current_loc:current_loc+win_size] 26 | windowed = segment * win 27 | padded = np.append(windowed, inner_pad) 28 | freqs = np.fft.fft(padded) / fft_size 29 | result[i, :] = np.abs(freqs * np.conj(freqs))[:fft_size] 30 | 31 | return total_segments, result 32 | 33 | 34 | def stft_freqs(fft_size, fs): 35 | return np.arange(fft_size) / np.float32(fft_size*2) * fs 36 | 37 | 38 | def stft_time(frames, t): 39 | return np.arange(frames) / np.float32(frames) * t 40 | 41 | 42 | def create_ticks_optimum(axis, num_ticks, resolution): 43 | max_freq = axis[-1] 44 | hop_size = max_freq / np.float32(num_ticks) 45 | print 'hop size:', hop_size 46 | 47 | current_hop = 0 48 | 49 | indicies = [] 50 | ideal_vals = [] 51 | 52 | while current_hop < max_freq: 53 | next_index = np.abs(axis-current_hop).argmin() 54 | 55 | indicies.append(next_index) 56 | ideal_vals.append(current_hop) 57 | 58 | print 'error: ', np.abs(axis[next_index] - current_hop) 59 | 60 | current_hop += hop_size 61 | current_hop = resolution * round(float(current_hop)/resolution) 62 | 63 | 64 | 65 | return indicies, ideal_vals 66 | 67 | 68 | 69 | 70 | 71 | if __name__ == '__main__': 72 | from scipy.io.wavfile import read as wavread 73 | import matplotlib.pyplot as plt 74 | 75 | #''' 76 | fs, y = wavread('New Seal and New Spring_conv.wav') 77 | #fs, y = wavread('equation9sec.wav') 78 | y = y[...,0] 79 | t = y.shape[0] / np.float32(fs) 80 | 81 | #''' 82 | 83 | ''' 84 | f0 = 440 85 | fs = 48000 86 | t = 5 87 | n = np.arange(fs*t) 88 | y = 0.5*np.cos(2*np.pi*f0*n/float(fs)) 89 | ''' 90 | 91 | 92 | win_size = 2**11 93 | fft_size = win_size 94 | 95 | downsample = 3 96 | y = sig.decimate(y, downsample, ftype='fir') 97 | fs /= downsample 98 | 99 | print 'fs:', fs, 't:', t 100 | 101 | print 'y shape:', y.shape 102 | 103 | frames, result = stft(y, win_size=win_size, fft_size=fft_size, overlap_fac=0.1) 104 | result = 20*np.log10(result) 105 | result = np.clip(result, -60, 200) 106 | 107 | print 'result shape:', result.shape 108 | 109 | print 'frames:', frames 110 | 111 | img = plt.imshow(result, origin='lower', cmap='jet', interpolation='none', aspect='auto') 112 | cbar=plt.colorbar(img) 113 | tick_res_x = result.shape[1] / 10 114 | tick_res_y = result.shape[0] / 10 115 | 116 | freqs = stft_freqs(fft_size, fs) 117 | print 'num of freqs:', freqs.shape[0] 118 | print 'max freq:', freqs[-1] 119 | x_tick_locations, x_tick_vals = create_ticks_optimum(freqs, num_ticks=15, resolution=50) 120 | 121 | print 'tick_locations:', x_tick_locations 122 | print 'tick_values', x_tick_vals 123 | 124 | plt.xticks(x_tick_locations, x_tick_vals) 125 | 126 | time = stft_time(frames, t) 127 | print time.shape, time[-1] 128 | y_tick_locations, y_tick_vals = create_ticks_optimum(time, num_ticks=10, resolution=1) 129 | 130 | plt.yticks(y_tick_locations, y_tick_vals) 131 | 132 | plt.xlabel('Frequency [Hz]') 133 | plt.ylabel('Time [s]') 134 | plt.title('Autopower spectrum of "New Seal and New Spring"') 135 | 136 | plt.show() 137 | 138 | 139 | 140 | ''' 141 | next_pow_2 = np.power(2, np.int32(np.ceil(np.log2(y.shape[0])))) 142 | pad = np.zeros(next_pow_2 - y.shape[0]) 143 | y = np.append(y, pad) 144 | 145 | spectrum = np.fft.fft(y) 146 | autopower = np.empty(spectrum.shape[0]/2, dtype=np.float32) 147 | autopower[:] = np.abs(spectrum * np.conj(spectrum))[:autopower.shape[0]] 148 | 149 | plt.subplot(1,2,1) 150 | spectrum_freqs = np.arange(spectrum.shape[0]) / np.float32(next_pow_2) * fs 151 | plt.plot(spectrum_freqs, spectrum) 152 | 153 | plt.subplot(1,2,2) 154 | autopower_freqs = np.arange(autopower.shape[0]) / np.float32(next_pow_2) * fs 155 | plt.plot(autopower_freqs, autopower) 156 | print "Highest frequency is:", np.argmax(autopower) * fs / np.float32(next_pow_2), "Hz" 157 | 158 | plt.show() 159 | ''' 160 | 161 | 162 | -------------------------------------------------------------------------------- /Short Time Fourier Transform/media/.gitignore: -------------------------------------------------------------------------------- 1 | equation9sec.wav -------------------------------------------------------------------------------- /Short Time Fourier Transform/media/mike_annoying.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KevinNJ/Projects/7b3268a808b76e85aab5981b35b22710ed7c4300/Short Time Fourier Transform/media/mike_annoying.wav -------------------------------------------------------------------------------- /Short Time Fourier Transform/media/mike_chirp.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KevinNJ/Projects/7b3268a808b76e85aab5981b35b22710ed7c4300/Short Time Fourier Transform/media/mike_chirp.wav -------------------------------------------------------------------------------- /Short Time Fourier Transform/mplcanvas.py: -------------------------------------------------------------------------------- 1 | __author__ = 'kevin.nelson' 2 | 3 | 4 | from PySide import QtGui, QtCore 5 | from matplotlib.backends.backend_qt4agg import FigureCanvasQTAgg as FigureCanvas 6 | from matplotlib.figure import Figure 7 | 8 | 9 | class MplCanvas(FigureCanvas): 10 | onResize = QtCore.Signal(QtCore.QSize) 11 | def __init__(self, parent=None): 12 | self.fig = Figure() 13 | super(MplCanvas, self).__init__(self.fig) 14 | self.setParent(parent) 15 | 16 | def resizeEvent(self, event): 17 | super(MplCanvas, self).resizeEvent(event) 18 | self.onResize.emit(event.size()) 19 | 20 | -------------------------------------------------------------------------------- /Short Time Fourier Transform/sfft_gui.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # Form implementation generated from reading ui file 'sfft_gui.ui' 4 | # 5 | # Created: Sun Dec 14 21:56:17 2014 6 | # by: pyside-uic 0.2.15 running on PySide 1.2.2 7 | # 8 | # WARNING! All changes made in this file will be lost! 9 | 10 | from PySide import QtCore, QtGui 11 | 12 | class Ui_MainWindow(object): 13 | def setupUi(self, MainWindow): 14 | MainWindow.setObjectName("MainWindow") 15 | MainWindow.resize(921, 656) 16 | MainWindow.setMinimumSize(QtCore.QSize(0, 0)) 17 | self.centralwidget = QtGui.QWidget(MainWindow) 18 | self.centralwidget.setObjectName("centralwidget") 19 | self.horizontalLayout_5 = QtGui.QHBoxLayout(self.centralwidget) 20 | self.horizontalLayout_5.setObjectName("horizontalLayout_5") 21 | self.verticalLayout_3 = QtGui.QVBoxLayout() 22 | self.verticalLayout_3.setObjectName("verticalLayout_3") 23 | self.groupBox = QtGui.QGroupBox(self.centralwidget) 24 | sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Fixed, QtGui.QSizePolicy.MinimumExpanding) 25 | sizePolicy.setHorizontalStretch(0) 26 | sizePolicy.setVerticalStretch(0) 27 | sizePolicy.setHeightForWidth(self.groupBox.sizePolicy().hasHeightForWidth()) 28 | self.groupBox.setSizePolicy(sizePolicy) 29 | self.groupBox.setMinimumSize(QtCore.QSize(261, 202)) 30 | self.groupBox.setMaximumSize(QtCore.QSize(261, 301)) 31 | self.groupBox.setObjectName("groupBox") 32 | self.verticalLayout = QtGui.QVBoxLayout(self.groupBox) 33 | self.verticalLayout.setObjectName("verticalLayout") 34 | self.formLayout = QtGui.QFormLayout() 35 | self.formLayout.setFieldGrowthPolicy(QtGui.QFormLayout.AllNonFixedFieldsGrow) 36 | self.formLayout.setObjectName("formLayout") 37 | self.label_7 = QtGui.QLabel(self.groupBox) 38 | self.label_7.setObjectName("label_7") 39 | self.formLayout.setWidget(1, QtGui.QFormLayout.LabelRole, self.label_7) 40 | self.downsample_fac = QtGui.QLineEdit(self.groupBox) 41 | self.downsample_fac.setObjectName("downsample_fac") 42 | self.formLayout.setWidget(1, QtGui.QFormLayout.FieldRole, self.downsample_fac) 43 | self.fft_size = QtGui.QLineEdit(self.groupBox) 44 | self.fft_size.setMinimumSize(QtCore.QSize(0, 0)) 45 | self.fft_size.setObjectName("fft_size") 46 | self.formLayout.setWidget(3, QtGui.QFormLayout.FieldRole, self.fft_size) 47 | self.label_3 = QtGui.QLabel(self.groupBox) 48 | self.label_3.setObjectName("label_3") 49 | self.formLayout.setWidget(4, QtGui.QFormLayout.LabelRole, self.label_3) 50 | self.overlap_fac = QtGui.QLineEdit(self.groupBox) 51 | self.overlap_fac.setObjectName("overlap_fac") 52 | self.formLayout.setWidget(4, QtGui.QFormLayout.FieldRole, self.overlap_fac) 53 | self.label_2 = QtGui.QLabel(self.groupBox) 54 | self.label_2.setObjectName("label_2") 55 | self.formLayout.setWidget(5, QtGui.QFormLayout.LabelRole, self.label_2) 56 | self.horizontalLayout = QtGui.QHBoxLayout() 57 | self.horizontalLayout.setObjectName("horizontalLayout") 58 | self.clip_min = QtGui.QLineEdit(self.groupBox) 59 | sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Fixed) 60 | sizePolicy.setHorizontalStretch(0) 61 | sizePolicy.setVerticalStretch(0) 62 | sizePolicy.setHeightForWidth(self.clip_min.sizePolicy().hasHeightForWidth()) 63 | self.clip_min.setSizePolicy(sizePolicy) 64 | self.clip_min.setBaseSize(QtCore.QSize(0, 0)) 65 | self.clip_min.setObjectName("clip_min") 66 | self.horizontalLayout.addWidget(self.clip_min) 67 | self.clip_max = QtGui.QLineEdit(self.groupBox) 68 | self.clip_max.setObjectName("clip_max") 69 | self.horizontalLayout.addWidget(self.clip_max) 70 | self.formLayout.setLayout(5, QtGui.QFormLayout.FieldRole, self.horizontalLayout) 71 | self.label_5 = QtGui.QLabel(self.groupBox) 72 | self.label_5.setObjectName("label_5") 73 | self.formLayout.setWidget(6, QtGui.QFormLayout.LabelRole, self.label_5) 74 | self.horizontalLayout_3 = QtGui.QHBoxLayout() 75 | self.horizontalLayout_3.setObjectName("horizontalLayout_3") 76 | self.y_num_ticks = QtGui.QLineEdit(self.groupBox) 77 | self.y_num_ticks.setObjectName("y_num_ticks") 78 | self.horizontalLayout_3.addWidget(self.y_num_ticks) 79 | self.y_resolution = QtGui.QLineEdit(self.groupBox) 80 | self.y_resolution.setObjectName("y_resolution") 81 | self.horizontalLayout_3.addWidget(self.y_resolution) 82 | self.formLayout.setLayout(6, QtGui.QFormLayout.FieldRole, self.horizontalLayout_3) 83 | self.label_4 = QtGui.QLabel(self.groupBox) 84 | self.label_4.setObjectName("label_4") 85 | self.formLayout.setWidget(7, QtGui.QFormLayout.LabelRole, self.label_4) 86 | self.horizontalLayout_2 = QtGui.QHBoxLayout() 87 | self.horizontalLayout_2.setObjectName("horizontalLayout_2") 88 | self.x_num_ticks = QtGui.QLineEdit(self.groupBox) 89 | self.x_num_ticks.setObjectName("x_num_ticks") 90 | self.horizontalLayout_2.addWidget(self.x_num_ticks) 91 | self.x_resolution = QtGui.QLineEdit(self.groupBox) 92 | self.x_resolution.setObjectName("x_resolution") 93 | self.horizontalLayout_2.addWidget(self.x_resolution) 94 | self.formLayout.setLayout(7, QtGui.QFormLayout.FieldRole, self.horizontalLayout_2) 95 | self.label_8 = QtGui.QLabel(self.groupBox) 96 | self.label_8.setObjectName("label_8") 97 | self.formLayout.setWidget(8, QtGui.QFormLayout.LabelRole, self.label_8) 98 | self.x_tick_rotation = QtGui.QLineEdit(self.groupBox) 99 | self.x_tick_rotation.setObjectName("x_tick_rotation") 100 | self.formLayout.setWidget(8, QtGui.QFormLayout.FieldRole, self.x_tick_rotation) 101 | self.x_grid = QtGui.QCheckBox(self.groupBox) 102 | self.x_grid.setObjectName("x_grid") 103 | self.formLayout.setWidget(9, QtGui.QFormLayout.LabelRole, self.x_grid) 104 | self.y_grid = QtGui.QCheckBox(self.groupBox) 105 | self.y_grid.setObjectName("y_grid") 106 | self.formLayout.setWidget(10, QtGui.QFormLayout.LabelRole, self.y_grid) 107 | self.label = QtGui.QLabel(self.groupBox) 108 | self.label.setObjectName("label") 109 | self.formLayout.setWidget(3, QtGui.QFormLayout.LabelRole, self.label) 110 | self.label_12 = QtGui.QLabel(self.groupBox) 111 | self.label_12.setObjectName("label_12") 112 | self.formLayout.setWidget(2, QtGui.QFormLayout.LabelRole, self.label_12) 113 | self.win_size = QtGui.QLineEdit(self.groupBox) 114 | self.win_size.setObjectName("win_size") 115 | self.formLayout.setWidget(2, QtGui.QFormLayout.FieldRole, self.win_size) 116 | self.verticalLayout.addLayout(self.formLayout) 117 | self.render = QtGui.QPushButton(self.groupBox) 118 | self.render.setObjectName("render") 119 | self.verticalLayout.addWidget(self.render) 120 | self.verticalLayout_3.addWidget(self.groupBox) 121 | self.groupBox_3 = QtGui.QGroupBox(self.centralwidget) 122 | self.groupBox_3.setMinimumSize(QtCore.QSize(261, 87)) 123 | self.groupBox_3.setMaximumSize(QtCore.QSize(261, 101)) 124 | self.groupBox_3.setObjectName("groupBox_3") 125 | self.verticalLayout_2 = QtGui.QVBoxLayout(self.groupBox_3) 126 | self.verticalLayout_2.setObjectName("verticalLayout_2") 127 | self.formLayout_2 = QtGui.QFormLayout() 128 | self.formLayout_2.setObjectName("formLayout_2") 129 | self.label_10 = QtGui.QLabel(self.groupBox_3) 130 | self.label_10.setObjectName("label_10") 131 | self.formLayout_2.setWidget(3, QtGui.QFormLayout.LabelRole, self.label_10) 132 | self.freq_res = QtGui.QLineEdit(self.groupBox_3) 133 | sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Preferred, QtGui.QSizePolicy.Fixed) 134 | sizePolicy.setHorizontalStretch(0) 135 | sizePolicy.setVerticalStretch(0) 136 | sizePolicy.setHeightForWidth(self.freq_res.sizePolicy().hasHeightForWidth()) 137 | self.freq_res.setSizePolicy(sizePolicy) 138 | self.freq_res.setReadOnly(True) 139 | self.freq_res.setObjectName("freq_res") 140 | self.formLayout_2.setWidget(3, QtGui.QFormLayout.FieldRole, self.freq_res) 141 | self.label_9 = QtGui.QLabel(self.groupBox_3) 142 | self.label_9.setObjectName("label_9") 143 | self.formLayout_2.setWidget(1, QtGui.QFormLayout.LabelRole, self.label_9) 144 | self.sampling_freq = QtGui.QLineEdit(self.groupBox_3) 145 | sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Preferred, QtGui.QSizePolicy.Fixed) 146 | sizePolicy.setHorizontalStretch(0) 147 | sizePolicy.setVerticalStretch(0) 148 | sizePolicy.setHeightForWidth(self.sampling_freq.sizePolicy().hasHeightForWidth()) 149 | self.sampling_freq.setSizePolicy(sizePolicy) 150 | self.sampling_freq.setReadOnly(True) 151 | self.sampling_freq.setObjectName("sampling_freq") 152 | self.formLayout_2.setWidget(1, QtGui.QFormLayout.FieldRole, self.sampling_freq) 153 | self.label_11 = QtGui.QLabel(self.groupBox_3) 154 | self.label_11.setObjectName("label_11") 155 | self.formLayout_2.setWidget(2, QtGui.QFormLayout.LabelRole, self.label_11) 156 | self.data_length = QtGui.QLineEdit(self.groupBox_3) 157 | self.data_length.setObjectName("data_length") 158 | self.formLayout_2.setWidget(2, QtGui.QFormLayout.FieldRole, self.data_length) 159 | self.verticalLayout_2.addLayout(self.formLayout_2) 160 | self.verticalLayout_3.addWidget(self.groupBox_3) 161 | spacerItem = QtGui.QSpacerItem(20, 40, QtGui.QSizePolicy.Minimum, QtGui.QSizePolicy.Expanding) 162 | self.verticalLayout_3.addItem(spacerItem) 163 | self.horizontalLayout_5.addLayout(self.verticalLayout_3) 164 | self.groupBox_2 = QtGui.QGroupBox(self.centralwidget) 165 | sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Expanding) 166 | sizePolicy.setHorizontalStretch(0) 167 | sizePolicy.setVerticalStretch(0) 168 | sizePolicy.setHeightForWidth(self.groupBox_2.sizePolicy().hasHeightForWidth()) 169 | self.groupBox_2.setSizePolicy(sizePolicy) 170 | self.groupBox_2.setObjectName("groupBox_2") 171 | self.horizontalLayout_4 = QtGui.QHBoxLayout(self.groupBox_2) 172 | self.horizontalLayout_4.setObjectName("horizontalLayout_4") 173 | self.mpl = MplCanvas(self.groupBox_2) 174 | self.mpl.setObjectName("mpl") 175 | self.horizontalLayout_7 = QtGui.QHBoxLayout(self.mpl) 176 | self.horizontalLayout_7.setObjectName("horizontalLayout_7") 177 | self.horizontalLayout_4.addWidget(self.mpl) 178 | self.horizontalLayout_5.addWidget(self.groupBox_2) 179 | MainWindow.setCentralWidget(self.centralwidget) 180 | self.menubar = QtGui.QMenuBar(MainWindow) 181 | self.menubar.setGeometry(QtCore.QRect(0, 0, 921, 21)) 182 | self.menubar.setObjectName("menubar") 183 | MainWindow.setMenuBar(self.menubar) 184 | self.statusbar = QtGui.QStatusBar(MainWindow) 185 | self.statusbar.setObjectName("statusbar") 186 | MainWindow.setStatusBar(self.statusbar) 187 | 188 | self.retranslateUi(MainWindow) 189 | QtCore.QMetaObject.connectSlotsByName(MainWindow) 190 | MainWindow.setTabOrder(self.downsample_fac, self.fft_size) 191 | MainWindow.setTabOrder(self.fft_size, self.overlap_fac) 192 | MainWindow.setTabOrder(self.overlap_fac, self.clip_min) 193 | MainWindow.setTabOrder(self.clip_min, self.clip_max) 194 | MainWindow.setTabOrder(self.clip_max, self.y_num_ticks) 195 | MainWindow.setTabOrder(self.y_num_ticks, self.y_resolution) 196 | MainWindow.setTabOrder(self.y_resolution, self.x_num_ticks) 197 | MainWindow.setTabOrder(self.x_num_ticks, self.x_resolution) 198 | MainWindow.setTabOrder(self.x_resolution, self.x_tick_rotation) 199 | MainWindow.setTabOrder(self.x_tick_rotation, self.x_grid) 200 | MainWindow.setTabOrder(self.x_grid, self.y_grid) 201 | MainWindow.setTabOrder(self.y_grid, self.render) 202 | 203 | def retranslateUi(self, MainWindow): 204 | MainWindow.setWindowTitle(QtGui.QApplication.translate("MainWindow", "MainWindow", None, QtGui.QApplication.UnicodeUTF8)) 205 | self.groupBox.setTitle(QtGui.QApplication.translate("MainWindow", "SFFT Controls", None, QtGui.QApplication.UnicodeUTF8)) 206 | self.label_7.setText(QtGui.QApplication.translate("MainWindow", "Downsample Factor:", None, QtGui.QApplication.UnicodeUTF8)) 207 | self.downsample_fac.setText(QtGui.QApplication.translate("MainWindow", "1", None, QtGui.QApplication.UnicodeUTF8)) 208 | self.fft_size.setText(QtGui.QApplication.translate("MainWindow", "2**11", None, QtGui.QApplication.UnicodeUTF8)) 209 | self.label_3.setText(QtGui.QApplication.translate("MainWindow", "Overlap Factor:", None, QtGui.QApplication.UnicodeUTF8)) 210 | self.overlap_fac.setText(QtGui.QApplication.translate("MainWindow", "0.9", None, QtGui.QApplication.UnicodeUTF8)) 211 | self.label_2.setText(QtGui.QApplication.translate("MainWindow", "Clip:", None, QtGui.QApplication.UnicodeUTF8)) 212 | self.clip_min.setText(QtGui.QApplication.translate("MainWindow", "-60", None, QtGui.QApplication.UnicodeUTF8)) 213 | self.clip_max.setText(QtGui.QApplication.translate("MainWindow", "200", None, QtGui.QApplication.UnicodeUTF8)) 214 | self.label_5.setText(QtGui.QApplication.translate("MainWindow", "Y Axis (Ticks, Resolution):", None, QtGui.QApplication.UnicodeUTF8)) 215 | self.y_num_ticks.setText(QtGui.QApplication.translate("MainWindow", "10", None, QtGui.QApplication.UnicodeUTF8)) 216 | self.y_resolution.setText(QtGui.QApplication.translate("MainWindow", "1", None, QtGui.QApplication.UnicodeUTF8)) 217 | self.label_4.setText(QtGui.QApplication.translate("MainWindow", "X Axis (Ticks, Resolution):", None, QtGui.QApplication.UnicodeUTF8)) 218 | self.x_num_ticks.setText(QtGui.QApplication.translate("MainWindow", "15", None, QtGui.QApplication.UnicodeUTF8)) 219 | self.x_resolution.setText(QtGui.QApplication.translate("MainWindow", "50", None, QtGui.QApplication.UnicodeUTF8)) 220 | self.label_8.setText(QtGui.QApplication.translate("MainWindow", "X Tick Rotation", None, QtGui.QApplication.UnicodeUTF8)) 221 | self.x_tick_rotation.setText(QtGui.QApplication.translate("MainWindow", "90", None, QtGui.QApplication.UnicodeUTF8)) 222 | self.x_grid.setText(QtGui.QApplication.translate("MainWindow", "X Grid", None, QtGui.QApplication.UnicodeUTF8)) 223 | self.y_grid.setText(QtGui.QApplication.translate("MainWindow", "Y Grid", None, QtGui.QApplication.UnicodeUTF8)) 224 | self.label.setText(QtGui.QApplication.translate("MainWindow", "FFT Size:", None, QtGui.QApplication.UnicodeUTF8)) 225 | self.label_12.setText(QtGui.QApplication.translate("MainWindow", "Win Size:", None, QtGui.QApplication.UnicodeUTF8)) 226 | self.win_size.setText(QtGui.QApplication.translate("MainWindow", "500", None, QtGui.QApplication.UnicodeUTF8)) 227 | self.render.setText(QtGui.QApplication.translate("MainWindow", "Render", None, QtGui.QApplication.UnicodeUTF8)) 228 | self.groupBox_3.setTitle(QtGui.QApplication.translate("MainWindow", "Resolution", None, QtGui.QApplication.UnicodeUTF8)) 229 | self.label_10.setText(QtGui.QApplication.translate("MainWindow", "Frequency Resolution [Hz]:", None, QtGui.QApplication.UnicodeUTF8)) 230 | self.label_9.setText(QtGui.QApplication.translate("MainWindow", "Sampling Frequency [Hz]:", None, QtGui.QApplication.UnicodeUTF8)) 231 | self.label_11.setText(QtGui.QApplication.translate("MainWindow", "Duration of input [s]:", None, QtGui.QApplication.UnicodeUTF8)) 232 | self.groupBox_2.setTitle(QtGui.QApplication.translate("MainWindow", "Waterfall", None, QtGui.QApplication.UnicodeUTF8)) 233 | 234 | from mplcanvas import MplCanvas 235 | -------------------------------------------------------------------------------- /Short Time Fourier Transform/sfft_gui.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | MainWindow 4 | 5 | 6 | 7 | 0 8 | 0 9 | 921 10 | 656 11 | 12 | 13 | 14 | 15 | 0 16 | 0 17 | 18 | 19 | 20 | MainWindow 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 0 31 | 0 32 | 33 | 34 | 35 | 36 | 261 37 | 202 38 | 39 | 40 | 41 | 42 | 261 43 | 301 44 | 45 | 46 | 47 | SFFT Controls 48 | 49 | 50 | 51 | 52 | 53 | QFormLayout::AllNonFixedFieldsGrow 54 | 55 | 56 | 57 | 58 | Downsample Factor: 59 | 60 | 61 | 62 | 63 | 64 | 65 | 1 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 0 74 | 0 75 | 76 | 77 | 78 | 2**12 79 | 80 | 81 | 82 | 83 | 84 | 85 | Overlap Factor: 86 | 87 | 88 | 89 | 90 | 91 | 92 | 0.9 93 | 94 | 95 | 96 | 97 | 98 | 99 | Clip: 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 0 110 | 0 111 | 112 | 113 | 114 | 115 | 0 116 | 0 117 | 118 | 119 | 120 | -60 121 | 122 | 123 | 124 | 125 | 126 | 127 | 200 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | Y Axis (Ticks, Resolution): 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 10 146 | 147 | 148 | 149 | 150 | 151 | 152 | 0.025 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | X Axis (Ticks, Resolution): 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 30 171 | 172 | 173 | 174 | 175 | 176 | 177 | 25 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | X Tick Rotation 187 | 188 | 189 | 190 | 191 | 192 | 193 | 90 194 | 195 | 196 | 197 | 198 | 199 | 200 | X Grid 201 | 202 | 203 | 204 | 205 | 206 | 207 | Y Grid 208 | 209 | 210 | 211 | 212 | 213 | 214 | FFT Size: 215 | 216 | 217 | 218 | 219 | 220 | 221 | Win Size: 222 | 223 | 224 | 225 | 226 | 227 | 228 | 800 229 | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | Render 238 | 239 | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 261 249 | 87 250 | 251 | 252 | 253 | 254 | 261 255 | 101 256 | 257 | 258 | 259 | Resolution 260 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | Frequency Resolution [Hz]: 268 | 269 | 270 | 271 | 272 | 273 | 274 | 275 | 0 276 | 0 277 | 278 | 279 | 280 | true 281 | 282 | 283 | 284 | 285 | 286 | 287 | Sampling Frequency [Hz]: 288 | 289 | 290 | 291 | 292 | 293 | 294 | 295 | 0 296 | 0 297 | 298 | 299 | 300 | true 301 | 302 | 303 | 304 | 305 | 306 | 307 | Duration of input [s]: 308 | 309 | 310 | 311 | 312 | 313 | 314 | 315 | 316 | 317 | 318 | 319 | 320 | 321 | 322 | Qt::Vertical 323 | 324 | 325 | 326 | 20 327 | 40 328 | 329 | 330 | 331 | 332 | 333 | 334 | 335 | 336 | 337 | 338 | 0 339 | 0 340 | 341 | 342 | 343 | Waterfall 344 | 345 | 346 | 347 | 348 | 349 | 350 | 351 | 352 | 353 | 354 | 355 | 356 | 357 | 358 | 359 | 0 360 | 0 361 | 921 362 | 21 363 | 364 | 365 | 366 | 367 | 368 | 369 | 370 | MplCanvas 371 | QWidget 372 |
mplcanvas.h
373 | 1 374 |
375 |
376 | 377 | downsample_fac 378 | fft_size 379 | overlap_fac 380 | clip_min 381 | clip_max 382 | y_num_ticks 383 | y_resolution 384 | x_num_ticks 385 | x_resolution 386 | x_tick_rotation 387 | x_grid 388 | y_grid 389 | render 390 | 391 | 392 | 393 |
394 | -------------------------------------------------------------------------------- /Weinberg Circuit/.gitignore: -------------------------------------------------------------------------------- 1 | resources 2 | -------------------------------------------------------------------------------- /Weinberg Circuit/README.md: -------------------------------------------------------------------------------- 1 | Weinberg DC-DC Converter 2 | ======================== 3 | 4 | LTSPICE files for Weinberg DC-DC converter. 5 | 6 | * v02-Ideal => ideal version of the circuit 7 | * v03-NonIdeal => reduced coupling coefficient on inductors to check effect on circuit 8 | * v04-SEPIC => added coupling capacitors to transformers to reduce coupling coefficient effects -------------------------------------------------------------------------------- /Weinberg Circuit/v02-Ideal.asc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KevinNJ/Projects/7b3268a808b76e85aab5981b35b22710ed7c4300/Weinberg Circuit/v02-Ideal.asc -------------------------------------------------------------------------------- /Weinberg Circuit/v03-NonIdeal.asc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KevinNJ/Projects/7b3268a808b76e85aab5981b35b22710ed7c4300/Weinberg Circuit/v03-NonIdeal.asc -------------------------------------------------------------------------------- /Weinberg Circuit/v04-SEPIC.asc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KevinNJ/Projects/7b3268a808b76e85aab5981b35b22710ed7c4300/Weinberg Circuit/v04-SEPIC.asc --------------------------------------------------------------------------------