Initial commit
8
.gitignore
vendored
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
.DS_Store
|
||||||
|
/.build
|
||||||
|
xcuserdata/
|
||||||
|
DerivedData/
|
||||||
|
.swiftpm/configuration/registries.json
|
||||||
|
.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata
|
||||||
|
.netrc
|
||||||
|
*.class
|
||||||
42
Package.resolved
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
{
|
||||||
|
"originHash" : "8b424c89cf909d23f0294225dd14ece13680ef4d122b099e92d093e9817a9b21",
|
||||||
|
"pins" : [
|
||||||
|
{
|
||||||
|
"identity" : "swift-algorithms",
|
||||||
|
"kind" : "remoteSourceControl",
|
||||||
|
"location" : "https://github.com/apple/swift-algorithms",
|
||||||
|
"state" : {
|
||||||
|
"revision" : "f6919dfc309e7f1b56224378b11e28bab5bccc42",
|
||||||
|
"version" : "1.2.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"identity" : "swift-numerics",
|
||||||
|
"kind" : "remoteSourceControl",
|
||||||
|
"location" : "https://github.com/apple/swift-numerics.git",
|
||||||
|
"state" : {
|
||||||
|
"revision" : "0a5bc04095a675662cf24757cc0640aa2204253b",
|
||||||
|
"version" : "1.0.2"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"identity" : "swift-odeint",
|
||||||
|
"kind" : "remoteSourceControl",
|
||||||
|
"location" : "https://github.com/jkl1337/swift-odeint",
|
||||||
|
"state" : {
|
||||||
|
"branch" : "master",
|
||||||
|
"revision" : "6e195efd2276dec7cedd2745be8ed61e0cbaa370"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"identity" : "swiftpffft",
|
||||||
|
"kind" : "remoteSourceControl",
|
||||||
|
"location" : "https://github.com/jkl1337/SwiftPFFFT",
|
||||||
|
"state" : {
|
||||||
|
"branch" : "master",
|
||||||
|
"revision" : "437f984b112fecbd4303d21f7c934f2085b6d9af"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"version" : 3
|
||||||
|
}
|
||||||
34
Package.swift
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
// swift-tools-version: 6.0
|
||||||
|
// The swift-tools-version declares the minimum version of Swift required to build this package.
|
||||||
|
|
||||||
|
import PackageDescription
|
||||||
|
|
||||||
|
let package = Package(
|
||||||
|
name: "ECGSynKit",
|
||||||
|
products: [
|
||||||
|
// Products define the executables and libraries a package produces, making them visible to other packages.
|
||||||
|
.library(
|
||||||
|
name: "ECGSynKit",
|
||||||
|
targets: ["ECGSynKit"]
|
||||||
|
),
|
||||||
|
],
|
||||||
|
dependencies: [
|
||||||
|
.package(url: "https://github.com/apple/swift-algorithms", from: "1.2.0"),
|
||||||
|
.package(url: "https://github.com/jkl1337/SwiftPFFFT", branch: "master"),
|
||||||
|
.package(url: "https://github.com/jkl1337/swift-odeint", branch: "master"),
|
||||||
|
],
|
||||||
|
targets: [
|
||||||
|
.target(
|
||||||
|
name: "ECGSynKit",
|
||||||
|
dependencies: [
|
||||||
|
.product(name: "PFFFT", package: "SwiftPFFFT"),
|
||||||
|
.product(name: "Algorithms", package: "swift-algorithms"),
|
||||||
|
.product(name: "OdeInt", package: "swift-odeint"),
|
||||||
|
]
|
||||||
|
),
|
||||||
|
.testTarget(
|
||||||
|
name: "ECGSynKitTests",
|
||||||
|
dependencies: ["ECGSynKit"]
|
||||||
|
),
|
||||||
|
]
|
||||||
|
)
|
||||||
7
Packages/KissFFT/.gitignore
vendored
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
.DS_Store
|
||||||
|
/.build
|
||||||
|
/Packages
|
||||||
|
/*.xcodeproj
|
||||||
|
xcuserdata/
|
||||||
|
DerivedData/
|
||||||
|
.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata
|
||||||
11
Packages/KissFFT/COPYING
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
Copyright (c) 2003-2010 Mark Borgerding
|
||||||
|
|
||||||
|
All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
|
||||||
|
|
||||||
|
* Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
|
||||||
|
* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
|
||||||
|
* Neither the author nor the names of any contributors may be used to endorse or promote products derived from this software without specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
10
Packages/KissFFT/Package.swift
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
// swift-tools-version:5.3
|
||||||
|
// The swift-tools-version declares the minimum version of Swift required to build this package.
|
||||||
|
|
||||||
|
import PackageDescription
|
||||||
|
|
||||||
|
let package = Package(
|
||||||
|
name: "KissFFT",
|
||||||
|
products: [ .library(name: "KissFFT", targets: ["KissFFT"])],
|
||||||
|
targets: [.target(name: "KissFFT", publicHeadersPath: "include")]
|
||||||
|
)
|
||||||
145
Packages/KissFFT/README.md
Normal file
@@ -0,0 +1,145 @@
|
|||||||
|
# Kiss FFT
|
||||||
|
|
||||||
|
Swift Package implementation of Kiss FFT, described below.
|
||||||
|
|
||||||
|
## A mixed-radix Fast Fourier Transform based up on the principle, "Keep It Simple, Stupid."
|
||||||
|
|
||||||
|
There are many great fft libraries already around. Kiss FFT is not trying
|
||||||
|
to be better than any of them. It only attempts to be a reasonably efficient,
|
||||||
|
moderately useful FFT that can use fixed or floating data types and can be
|
||||||
|
incorporated into someone's C program in a few minutes with trivial licensing.
|
||||||
|
|
||||||
|
## USAGE:
|
||||||
|
|
||||||
|
The basic usage for 1-d complex FFT is:
|
||||||
|
|
||||||
|
#include "kiss_fft.h"
|
||||||
|
|
||||||
|
kiss_fft_cfg cfg = kiss_fft_alloc( nfft ,is_inverse_fft ,0,0 );
|
||||||
|
|
||||||
|
while ...
|
||||||
|
|
||||||
|
... // put kth sample in cx_in[k].r and cx_in[k].i
|
||||||
|
|
||||||
|
kiss_fft( cfg , cx_in , cx_out );
|
||||||
|
|
||||||
|
... // transformed. DC is in cx_out[0].r and cx_out[0].i
|
||||||
|
|
||||||
|
free(cfg);
|
||||||
|
|
||||||
|
Note: frequency-domain data is stored from dc up to 2pi.
|
||||||
|
so cx_out[0] is the dc bin of the FFT
|
||||||
|
and cx_out[nfft/2] is the Nyquist bin (if exists)
|
||||||
|
|
||||||
|
Declarations are in "kiss_fft.h", along with a brief description of the
|
||||||
|
functions you'll need to use.
|
||||||
|
|
||||||
|
Code definitions for 1d complex FFTs are in kiss_fft.c.
|
||||||
|
|
||||||
|
You can do other cool stuff with the extras you'll find in tools/
|
||||||
|
|
||||||
|
* multi-dimensional FFTs
|
||||||
|
* real-optimized FFTs (returns the positive half-spectrum: (nfft/2+1) complex frequency bins)
|
||||||
|
* fast convolution FIR filtering (not available for fixed point)
|
||||||
|
* spectrum image creation
|
||||||
|
|
||||||
|
The core fft and most tools/ code can be compiled to use float, double
|
||||||
|
or Q15 short samples. The default is float.
|
||||||
|
|
||||||
|
|
||||||
|
## BACKGROUND:
|
||||||
|
|
||||||
|
I started coding this because I couldn't find a fixed point FFT that didn't
|
||||||
|
use assembly code. I started with floating point numbers so I could get the
|
||||||
|
theory straight before working on fixed point issues. In the end, I had a
|
||||||
|
little bit of code that could be recompiled easily to do ffts with short, float
|
||||||
|
or double (other types should be easy too).
|
||||||
|
|
||||||
|
Once I got my FFT working, I was curious about the speed compared to
|
||||||
|
a well respected and highly optimized fft library. I don't want to criticize
|
||||||
|
this great library, so let's call it FFT_BRANDX.
|
||||||
|
During this process, I learned:
|
||||||
|
|
||||||
|
1. FFT_BRANDX has more than 100K lines of code. The core of kiss_fft is about 500 lines (cpx 1-d).
|
||||||
|
2. It took me an embarrassingly long time to get FFT_BRANDX working.
|
||||||
|
3. A simple program using FFT_BRANDX is 522KB. A similar program using kiss_fft is 18KB (without optimizing for size).
|
||||||
|
4. FFT_BRANDX is roughly twice as fast as KISS FFT in default mode.
|
||||||
|
|
||||||
|
It is wonderful that free, highly optimized libraries like FFT_BRANDX exist.
|
||||||
|
But such libraries carry a huge burden of complexity necessary to extract every
|
||||||
|
last bit of performance.
|
||||||
|
|
||||||
|
Sometimes simpler is better, even if it's not better.
|
||||||
|
|
||||||
|
## FREQUENTLY ASKED QUESTIONS:
|
||||||
|
|
||||||
|
Q: Can I use kissfft in a project with a ___ license?
|
||||||
|
|
||||||
|
A: Yes. See LICENSE below.
|
||||||
|
|
||||||
|
Q: Why don't I get the output I expect?
|
||||||
|
|
||||||
|
A: The two most common causes of this are
|
||||||
|
|
||||||
|
1) scaling : is there a constant multiplier between what you got and what you want?
|
||||||
|
2) mixed build environment -- all code must be compiled with same preprocessor
|
||||||
|
definitions for FIXED_POINT and kiss_fft_scalar
|
||||||
|
|
||||||
|
Q: Will you write/debug my code for me?
|
||||||
|
|
||||||
|
A: Probably not unless you pay me. I am happy to answer pointed and topical questions, but
|
||||||
|
I may refer you to a book, a forum, or some other resource.
|
||||||
|
|
||||||
|
|
||||||
|
## PERFORMANCE: (on Athlon XP 2100+, with gcc 2.96, float data type)
|
||||||
|
|
||||||
|
Kiss performed 10000 1024-pt cpx ffts in .63 s of cpu time.
|
||||||
|
For comparison, it took md5sum twice as long to process the same amount of data.
|
||||||
|
|
||||||
|
Transforming 5 minutes of CD quality audio takes less than a second (nfft=1024).
|
||||||
|
|
||||||
|
DO NOT:
|
||||||
|
|
||||||
|
... use Kiss if you need the Fastest Fourier Transform in the World
|
||||||
|
|
||||||
|
... ask me to add features that will bloat the code
|
||||||
|
|
||||||
|
## UNDER THE HOOD:
|
||||||
|
|
||||||
|
Kiss FFT uses a time decimation, mixed-radix, out-of-place FFT. If you give it an input buffer
|
||||||
|
and output buffer that are the same, a temporary buffer will be created to hold the data.
|
||||||
|
|
||||||
|
No static data is used. The core routines of kiss_fft are thread-safe (but not all of the tools directory).
|
||||||
|
|
||||||
|
No scaling is done for the floating point version (for speed).
|
||||||
|
Scaling is done both ways for the fixed-point version (for overflow prevention).
|
||||||
|
|
||||||
|
Optimized butterflies are used for factors 2,3,4, and 5.
|
||||||
|
|
||||||
|
The real (i.e. not complex) optimization code only works for even length ffts. It does two half-length
|
||||||
|
FFTs in parallel (packed into real&imag), and then combines them via twiddling. The result is
|
||||||
|
nfft/2+1 complex frequency bins from DC to Nyquist. If you don't know what this means, search the web.
|
||||||
|
|
||||||
|
The fast convolution filtering uses the overlap-scrap method, slightly
|
||||||
|
modified to put the scrap at the tail.
|
||||||
|
|
||||||
|
## LICENSE:
|
||||||
|
|
||||||
|
Revised BSD License, see COPYING for verbiage.
|
||||||
|
Basically, "free to use&change, give credit where due, no guarantees"
|
||||||
|
Note this license is compatible with GPL at one end of the spectrum and closed, commercial software at
|
||||||
|
the other end. See http://www.fsf.org/licensing/licenses
|
||||||
|
|
||||||
|
A commercial license is available which removes the requirement for attribution. Contact me for details.
|
||||||
|
|
||||||
|
## FUTURE:
|
||||||
|
* Add real optimization for odd length FFTs
|
||||||
|
* Document/revisit the input/output fft scaling
|
||||||
|
* Make doc describing the overlap (tail) scrap fast convolution filtering in kiss_fastfir.c
|
||||||
|
* Test all the ./tools/ code with fixed point (kiss_fastfir.c doesn't work, maybe others)
|
||||||
|
|
||||||
|
## AUTHOR
|
||||||
|
|
||||||
|
Mark Borgerding
|
||||||
|
Mark@Borgerding.net
|
||||||
|
|
||||||
168
Packages/KissFFT/Sources/KissFFT/include/_kiss_fft_guts.h
Normal file
@@ -0,0 +1,168 @@
|
|||||||
|
/*
|
||||||
|
Copyright (c) 2003-2010, Mark Borgerding
|
||||||
|
|
||||||
|
All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
|
||||||
|
|
||||||
|
* Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
|
||||||
|
* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
|
||||||
|
* Neither the author nor the names of any contributors may be used to endorse or promote products derived from this software without specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* kiss_fft.h
|
||||||
|
defines kiss_fft_scalar as either short or a float type
|
||||||
|
and defines
|
||||||
|
typedef struct { kiss_fft_scalar r; kiss_fft_scalar i; }kiss_fft_cpx; */
|
||||||
|
#include "kiss_fft.h"
|
||||||
|
#include <limits.h>
|
||||||
|
|
||||||
|
#define MAXFACTORS 32
|
||||||
|
/* e.g. an fft of length 128 has 4 factors
|
||||||
|
as far as kissfft is concerned
|
||||||
|
4*4*4*2
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef SOUNDPIPE_H
|
||||||
|
|
||||||
|
struct kiss_fft_state{
|
||||||
|
int nfft;
|
||||||
|
int inverse;
|
||||||
|
int factors[2*MAXFACTORS];
|
||||||
|
kiss_fft_cpx twiddles[1];
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
Explanation of macros dealing with complex math:
|
||||||
|
|
||||||
|
C_MUL(m,a,b) : m = a*b
|
||||||
|
C_FIXDIV( c , div ) : if a fixed point impl., c /= div. noop otherwise
|
||||||
|
C_SUB( res, a,b) : res = a - b
|
||||||
|
C_SUBFROM( res , a) : res -= a
|
||||||
|
C_ADDTO( res , a) : res += a
|
||||||
|
* */
|
||||||
|
#ifdef FIXED_POINT
|
||||||
|
#if (FIXED_POINT==32)
|
||||||
|
# define FRACBITS 31
|
||||||
|
# define SAMPPROD int64_t
|
||||||
|
#define SAMP_MAX 2147483647
|
||||||
|
#else
|
||||||
|
# define FRACBITS 15
|
||||||
|
# define SAMPPROD int32_t
|
||||||
|
#define SAMP_MAX 32767
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define SAMP_MIN -SAMP_MAX
|
||||||
|
|
||||||
|
#if defined(CHECK_OVERFLOW)
|
||||||
|
# define CHECK_OVERFLOW_OP(a,op,b) \
|
||||||
|
if ( (SAMPPROD)(a) op (SAMPPROD)(b) > SAMP_MAX || (SAMPPROD)(a) op (SAMPPROD)(b) < SAMP_MIN ) { \
|
||||||
|
fprintf(stderr,"WARNING:overflow @ " __FILE__ "(%d): (%d " #op" %d) = %ld\n",__LINE__,(a),(b),(SAMPPROD)(a) op (SAMPPROD)(b) ); }
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
# define smul(a,b) ( (SAMPPROD)(a)*(b) )
|
||||||
|
# define sround( x ) (kiss_fft_scalar)( ( (x) + (1<<(FRACBITS-1)) ) >> FRACBITS )
|
||||||
|
|
||||||
|
# define S_MUL(a,b) sround( smul(a,b) )
|
||||||
|
|
||||||
|
# define C_MUL(m,a,b) \
|
||||||
|
do{ (m).r = sround( smul((a).r,(b).r) - smul((a).i,(b).i) ); \
|
||||||
|
(m).i = sround( smul((a).r,(b).i) + smul((a).i,(b).r) ); }while(0)
|
||||||
|
|
||||||
|
# define DIVSCALAR(x,k) \
|
||||||
|
(x) = sround( smul( x, SAMP_MAX/k ) )
|
||||||
|
|
||||||
|
# define C_FIXDIV(c,div) \
|
||||||
|
do { DIVSCALAR( (c).r , div); \
|
||||||
|
DIVSCALAR( (c).i , div); }while (0)
|
||||||
|
|
||||||
|
# define C_MULBYSCALAR( c, s ) \
|
||||||
|
do{ (c).r = sround( smul( (c).r , s ) ) ;\
|
||||||
|
(c).i = sround( smul( (c).i , s ) ) ; }while(0)
|
||||||
|
|
||||||
|
#else /* not FIXED_POINT*/
|
||||||
|
|
||||||
|
# define S_MUL(a,b) ( (a)*(b) )
|
||||||
|
#define C_MUL(m,a,b) \
|
||||||
|
do{ (m).r = (a).r*(b).r - (a).i*(b).i;\
|
||||||
|
(m).i = (a).r*(b).i + (a).i*(b).r; }while(0)
|
||||||
|
# define C_FIXDIV(c,div) /* NOOP */
|
||||||
|
# define C_MULBYSCALAR( c, s ) \
|
||||||
|
do{ (c).r *= (s);\
|
||||||
|
(c).i *= (s); }while(0)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef CHECK_OVERFLOW_OP
|
||||||
|
# define CHECK_OVERFLOW_OP(a,op,b) /* noop */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define C_ADD( res, a,b)\
|
||||||
|
do { \
|
||||||
|
CHECK_OVERFLOW_OP((a).r,+,(b).r)\
|
||||||
|
CHECK_OVERFLOW_OP((a).i,+,(b).i)\
|
||||||
|
(res).r=(a).r+(b).r; (res).i=(a).i+(b).i; \
|
||||||
|
}while(0)
|
||||||
|
#define C_SUB( res, a,b)\
|
||||||
|
do { \
|
||||||
|
CHECK_OVERFLOW_OP((a).r,-,(b).r)\
|
||||||
|
CHECK_OVERFLOW_OP((a).i,-,(b).i)\
|
||||||
|
(res).r=(a).r-(b).r; (res).i=(a).i-(b).i; \
|
||||||
|
}while(0)
|
||||||
|
#define C_ADDTO( res , a)\
|
||||||
|
do { \
|
||||||
|
CHECK_OVERFLOW_OP((res).r,+,(a).r)\
|
||||||
|
CHECK_OVERFLOW_OP((res).i,+,(a).i)\
|
||||||
|
(res).r += (a).r; (res).i += (a).i;\
|
||||||
|
}while(0)
|
||||||
|
|
||||||
|
#define C_SUBFROM( res , a)\
|
||||||
|
do {\
|
||||||
|
CHECK_OVERFLOW_OP((res).r,-,(a).r)\
|
||||||
|
CHECK_OVERFLOW_OP((res).i,-,(a).i)\
|
||||||
|
(res).r -= (a).r; (res).i -= (a).i; \
|
||||||
|
}while(0)
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef FIXED_POINT
|
||||||
|
# define KISS_FFT_COS(phase) floor(.5+SAMP_MAX * cos (phase))
|
||||||
|
# define KISS_FFT_SIN(phase) floor(.5+SAMP_MAX * sin (phase))
|
||||||
|
# define HALF_OF(x) ((x)>>1)
|
||||||
|
#elif defined(USE_SIMD)
|
||||||
|
# define KISS_FFT_COS(phase) _mm_set1_ps( cos(phase) )
|
||||||
|
# define KISS_FFT_SIN(phase) _mm_set1_ps( sin(phase) )
|
||||||
|
# define HALF_OF(x) ((x)*_mm_set1_ps(.5))
|
||||||
|
#else
|
||||||
|
# define KISS_FFT_COS(phase) (kiss_fft_scalar) cos(phase)
|
||||||
|
# define KISS_FFT_SIN(phase) (kiss_fft_scalar) sin(phase)
|
||||||
|
# define HALF_OF(x) ((x)*.5)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define kf_cexp(x,phase) \
|
||||||
|
do{ \
|
||||||
|
(x)->r = KISS_FFT_COS(phase);\
|
||||||
|
(x)->i = KISS_FFT_SIN(phase);\
|
||||||
|
}while(0)
|
||||||
|
|
||||||
|
|
||||||
|
/* a debugging function */
|
||||||
|
#define pcpx(c)\
|
||||||
|
fprintf(stderr,"%g + %gi\n",(double)((c)->r),(double)((c)->i) )
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef KISS_FFT_USE_ALLOCA
|
||||||
|
// define this to allow use of alloca instead of malloc for temporary buffers
|
||||||
|
// Temporary buffers are used in two case:
|
||||||
|
// 1. FFT sizes that have "bad" factors. i.e. not 2,3 and 5
|
||||||
|
// 2. "in-place" FFTs. Notice the quotes, since kissfft does not really do an in-place transform.
|
||||||
|
#include <alloca.h>
|
||||||
|
#define KISS_FFT_TMP_ALLOC(nbytes) alloca(nbytes)
|
||||||
|
#define KISS_FFT_TMP_FREE(ptr)
|
||||||
|
#else
|
||||||
|
#define KISS_FFT_TMP_ALLOC(nbytes) KISS_FFT_MALLOC(nbytes)
|
||||||
|
#define KISS_FFT_TMP_FREE(ptr) KISS_FFT_FREE(ptr)
|
||||||
|
#endif
|
||||||
128
Packages/KissFFT/Sources/KissFFT/include/kiss_fft.h
Normal file
@@ -0,0 +1,128 @@
|
|||||||
|
#ifndef KISS_FFT_H
|
||||||
|
#define KISS_FFT_H
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <math.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
ATTENTION!
|
||||||
|
If you would like a :
|
||||||
|
-- a utility that will handle the caching of fft objects
|
||||||
|
-- real-only (no imaginary time component ) FFT
|
||||||
|
-- a multi-dimensional FFT
|
||||||
|
-- a command-line utility to perform ffts
|
||||||
|
-- a command-line utility to perform fast-convolution filtering
|
||||||
|
|
||||||
|
Then see kfc.h kiss_fftr.h kiss_fftnd.h fftutil.c kiss_fastfir.c
|
||||||
|
in the tools/ directory.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifdef USE_SIMD
|
||||||
|
# include <xmmintrin.h>
|
||||||
|
# define kiss_fft_scalar __m128
|
||||||
|
#define KISS_FFT_MALLOC(nbytes) _mm_malloc(nbytes,16)
|
||||||
|
#define KISS_FFT_FREE _mm_free
|
||||||
|
#else
|
||||||
|
#define KISS_FFT_MALLOC malloc
|
||||||
|
#define KISS_FFT_FREE free
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef FIXED_POINT
|
||||||
|
#include <sys/types.h>
|
||||||
|
# if (FIXED_POINT == 32)
|
||||||
|
# define kiss_fft_scalar int32_t
|
||||||
|
# else
|
||||||
|
# define kiss_fft_scalar int16_t
|
||||||
|
# endif
|
||||||
|
#else
|
||||||
|
# ifndef kiss_fft_scalar
|
||||||
|
/* default is float */
|
||||||
|
# define kiss_fft_scalar float
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef SOUNDPIPE_H
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
kiss_fft_scalar r;
|
||||||
|
kiss_fft_scalar i;
|
||||||
|
}kiss_fft_cpx;
|
||||||
|
|
||||||
|
typedef struct kiss_fft_state* kiss_fft_cfg;
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* kiss_fft_alloc
|
||||||
|
*
|
||||||
|
* Initialize a FFT (or IFFT) algorithm's cfg/state buffer.
|
||||||
|
*
|
||||||
|
* typical usage: kiss_fft_cfg mycfg=kiss_fft_alloc(1024,0,NULL,NULL);
|
||||||
|
*
|
||||||
|
* The return value from fft_alloc is a cfg buffer used internally
|
||||||
|
* by the fft routine or NULL.
|
||||||
|
*
|
||||||
|
* If lenmem is NULL, then kiss_fft_alloc will allocate a cfg buffer using malloc.
|
||||||
|
* The returned value should be free()d when done to avoid memory leaks.
|
||||||
|
*
|
||||||
|
* The state can be placed in a user supplied buffer 'mem':
|
||||||
|
* If lenmem is not NULL and mem is not NULL and *lenmem is large enough,
|
||||||
|
* then the function places the cfg in mem and the size used in *lenmem
|
||||||
|
* and returns mem.
|
||||||
|
*
|
||||||
|
* If lenmem is not NULL and ( mem is NULL or *lenmem is not large enough),
|
||||||
|
* then the function returns NULL and places the minimum cfg
|
||||||
|
* buffer size in *lenmem.
|
||||||
|
* */
|
||||||
|
|
||||||
|
kiss_fft_cfg kiss_fft_alloc(int nfft,int inverse_fft,void * mem,size_t * lenmem);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* kiss_fft(cfg,in_out_buf)
|
||||||
|
*
|
||||||
|
* Perform an FFT on a complex input buffer.
|
||||||
|
* for a forward FFT,
|
||||||
|
* fin should be f[0] , f[1] , ... ,f[nfft-1]
|
||||||
|
* fout will be F[0] , F[1] , ... ,F[nfft-1]
|
||||||
|
* Note that each element is complex and can be accessed like
|
||||||
|
f[k].r and f[k].i
|
||||||
|
* */
|
||||||
|
void kiss_fft(kiss_fft_cfg cfg,const kiss_fft_cpx *fin,kiss_fft_cpx *fout);
|
||||||
|
|
||||||
|
/*
|
||||||
|
A more generic version of the above function. It reads its input from every Nth sample.
|
||||||
|
* */
|
||||||
|
void kiss_fft_stride(kiss_fft_cfg cfg,const kiss_fft_cpx *fin,kiss_fft_cpx *fout,int fin_stride);
|
||||||
|
|
||||||
|
/* If kiss_fft_alloc allocated a buffer, it is one contiguous
|
||||||
|
buffer and can be simply free()d when no longer needed*/
|
||||||
|
#define kiss_fft_free free
|
||||||
|
|
||||||
|
/*
|
||||||
|
Cleans up some memory that gets managed internally. Not necessary to call, but it might clean up
|
||||||
|
your compiler output to call this before you exit.
|
||||||
|
*/
|
||||||
|
void kiss_fft_cleanup(void);
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Returns the smallest integer k, such that k>=n and k has only "fast" factors (2,3,5)
|
||||||
|
*/
|
||||||
|
int kiss_fft_next_fast_size(int n);
|
||||||
|
|
||||||
|
/* for real ffts, we need an even size */
|
||||||
|
#define kiss_fftr_next_fast_size_real(n) \
|
||||||
|
(kiss_fft_next_fast_size( ((n)+1)>>1)<<1)
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
49
Packages/KissFFT/Sources/KissFFT/include/kiss_fftr.h
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
#ifndef KISS_FTR_H
|
||||||
|
#define KISS_FTR_H
|
||||||
|
|
||||||
|
#include "kiss_fft.h"
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
|
||||||
|
Real optimized version can save about 45% cpu time vs. complex fft of a real seq.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef SOUNDPIPE_H
|
||||||
|
|
||||||
|
typedef struct kiss_fftr_state *kiss_fftr_cfg;
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
kiss_fftr_cfg kiss_fftr_alloc(int nfft,int inverse_fft,void * mem, size_t * lenmem);
|
||||||
|
/*
|
||||||
|
nfft must be even
|
||||||
|
|
||||||
|
If you don't care to allocate space, use mem = lenmem = NULL
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
void kiss_fftr(kiss_fftr_cfg cfg,const kiss_fft_scalar *timedata,kiss_fft_cpx *freqdata);
|
||||||
|
/*
|
||||||
|
input timedata has nfft scalar points
|
||||||
|
output freqdata has nfft/2+1 complex points
|
||||||
|
*/
|
||||||
|
|
||||||
|
void kiss_fftri(kiss_fftr_cfg cfg,const kiss_fft_cpx *freqdata,kiss_fft_scalar *timedata);
|
||||||
|
/*
|
||||||
|
input freqdata has nfft/2+1 complex points
|
||||||
|
output timedata has nfft scalar points
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define kiss_fftr_free free
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
409
Packages/KissFFT/Sources/KissFFT/kiss_fft.c
Normal file
@@ -0,0 +1,409 @@
|
|||||||
|
/*
|
||||||
|
Copyright (c) 2003-2010, Mark Borgerding
|
||||||
|
|
||||||
|
All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
|
||||||
|
|
||||||
|
* Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
|
||||||
|
* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
|
||||||
|
* Neither the author nor the names of any contributors may be used to endorse or promote products derived from this software without specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#include "_kiss_fft_guts.h"
|
||||||
|
/* The guts header contains all the multiplication and addition macros that are defined for
|
||||||
|
fixed or floating point complex numbers. It also delares the kf_ internal functions.
|
||||||
|
*/
|
||||||
|
|
||||||
|
static void kf_bfly2(
|
||||||
|
kiss_fft_cpx * Fout,
|
||||||
|
const size_t fstride,
|
||||||
|
const kiss_fft_cfg st,
|
||||||
|
int m
|
||||||
|
)
|
||||||
|
{
|
||||||
|
kiss_fft_cpx * Fout2;
|
||||||
|
kiss_fft_cpx * tw1 = st->twiddles;
|
||||||
|
kiss_fft_cpx t;
|
||||||
|
Fout2 = Fout + m;
|
||||||
|
do{
|
||||||
|
C_FIXDIV(*Fout,2); C_FIXDIV(*Fout2,2);
|
||||||
|
|
||||||
|
C_MUL (t, *Fout2 , *tw1);
|
||||||
|
tw1 += fstride;
|
||||||
|
C_SUB( *Fout2 , *Fout , t );
|
||||||
|
C_ADDTO( *Fout , t );
|
||||||
|
++Fout2;
|
||||||
|
++Fout;
|
||||||
|
}while (--m);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void kf_bfly4(
|
||||||
|
kiss_fft_cpx * Fout,
|
||||||
|
const size_t fstride,
|
||||||
|
const kiss_fft_cfg st,
|
||||||
|
const size_t m
|
||||||
|
)
|
||||||
|
{
|
||||||
|
kiss_fft_cpx *tw1,*tw2,*tw3;
|
||||||
|
kiss_fft_cpx scratch[6];
|
||||||
|
size_t k=m;
|
||||||
|
const size_t m2=2*m;
|
||||||
|
const size_t m3=3*m;
|
||||||
|
|
||||||
|
|
||||||
|
tw3 = tw2 = tw1 = st->twiddles;
|
||||||
|
|
||||||
|
do {
|
||||||
|
C_FIXDIV(*Fout,4); C_FIXDIV(Fout[m],4); C_FIXDIV(Fout[m2],4); C_FIXDIV(Fout[m3],4);
|
||||||
|
|
||||||
|
C_MUL(scratch[0],Fout[m] , *tw1 );
|
||||||
|
C_MUL(scratch[1],Fout[m2] , *tw2 );
|
||||||
|
C_MUL(scratch[2],Fout[m3] , *tw3 );
|
||||||
|
|
||||||
|
C_SUB( scratch[5] , *Fout, scratch[1] );
|
||||||
|
C_ADDTO(*Fout, scratch[1]);
|
||||||
|
C_ADD( scratch[3] , scratch[0] , scratch[2] );
|
||||||
|
C_SUB( scratch[4] , scratch[0] , scratch[2] );
|
||||||
|
C_SUB( Fout[m2], *Fout, scratch[3] );
|
||||||
|
tw1 += fstride;
|
||||||
|
tw2 += fstride*2;
|
||||||
|
tw3 += fstride*3;
|
||||||
|
C_ADDTO( *Fout , scratch[3] );
|
||||||
|
|
||||||
|
if(st->inverse) {
|
||||||
|
Fout[m].r = scratch[5].r - scratch[4].i;
|
||||||
|
Fout[m].i = scratch[5].i + scratch[4].r;
|
||||||
|
Fout[m3].r = scratch[5].r + scratch[4].i;
|
||||||
|
Fout[m3].i = scratch[5].i - scratch[4].r;
|
||||||
|
}else{
|
||||||
|
Fout[m].r = scratch[5].r + scratch[4].i;
|
||||||
|
Fout[m].i = scratch[5].i - scratch[4].r;
|
||||||
|
Fout[m3].r = scratch[5].r - scratch[4].i;
|
||||||
|
Fout[m3].i = scratch[5].i + scratch[4].r;
|
||||||
|
}
|
||||||
|
++Fout;
|
||||||
|
}while(--k);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void kf_bfly3(
|
||||||
|
kiss_fft_cpx * Fout,
|
||||||
|
const size_t fstride,
|
||||||
|
const kiss_fft_cfg st,
|
||||||
|
size_t m
|
||||||
|
)
|
||||||
|
{
|
||||||
|
size_t k=m;
|
||||||
|
const size_t m2 = 2*m;
|
||||||
|
kiss_fft_cpx *tw1,*tw2;
|
||||||
|
kiss_fft_cpx scratch[5];
|
||||||
|
kiss_fft_cpx epi3;
|
||||||
|
epi3 = st->twiddles[fstride*m];
|
||||||
|
|
||||||
|
tw1=tw2=st->twiddles;
|
||||||
|
|
||||||
|
do{
|
||||||
|
C_FIXDIV(*Fout,3); C_FIXDIV(Fout[m],3); C_FIXDIV(Fout[m2],3);
|
||||||
|
|
||||||
|
C_MUL(scratch[1],Fout[m] , *tw1);
|
||||||
|
C_MUL(scratch[2],Fout[m2] , *tw2);
|
||||||
|
|
||||||
|
C_ADD(scratch[3],scratch[1],scratch[2]);
|
||||||
|
C_SUB(scratch[0],scratch[1],scratch[2]);
|
||||||
|
tw1 += fstride;
|
||||||
|
tw2 += fstride*2;
|
||||||
|
|
||||||
|
Fout[m].r = Fout->r - HALF_OF(scratch[3].r);
|
||||||
|
Fout[m].i = Fout->i - HALF_OF(scratch[3].i);
|
||||||
|
|
||||||
|
C_MULBYSCALAR( scratch[0] , epi3.i );
|
||||||
|
|
||||||
|
C_ADDTO(*Fout,scratch[3]);
|
||||||
|
|
||||||
|
Fout[m2].r = Fout[m].r + scratch[0].i;
|
||||||
|
Fout[m2].i = Fout[m].i - scratch[0].r;
|
||||||
|
|
||||||
|
Fout[m].r -= scratch[0].i;
|
||||||
|
Fout[m].i += scratch[0].r;
|
||||||
|
|
||||||
|
++Fout;
|
||||||
|
}while(--k);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void kf_bfly5(
|
||||||
|
kiss_fft_cpx * Fout,
|
||||||
|
const size_t fstride,
|
||||||
|
const kiss_fft_cfg st,
|
||||||
|
int m
|
||||||
|
)
|
||||||
|
{
|
||||||
|
kiss_fft_cpx *Fout0,*Fout1,*Fout2,*Fout3,*Fout4;
|
||||||
|
int u;
|
||||||
|
kiss_fft_cpx scratch[13];
|
||||||
|
kiss_fft_cpx * twiddles = st->twiddles;
|
||||||
|
kiss_fft_cpx *tw;
|
||||||
|
kiss_fft_cpx ya,yb;
|
||||||
|
ya = twiddles[fstride*m];
|
||||||
|
yb = twiddles[fstride*2*m];
|
||||||
|
|
||||||
|
Fout0=Fout;
|
||||||
|
Fout1=Fout0+m;
|
||||||
|
Fout2=Fout0+2*m;
|
||||||
|
Fout3=Fout0+3*m;
|
||||||
|
Fout4=Fout0+4*m;
|
||||||
|
|
||||||
|
tw=st->twiddles;
|
||||||
|
for ( u=0; u<m; ++u ) {
|
||||||
|
C_FIXDIV( *Fout0,5); C_FIXDIV( *Fout1,5); C_FIXDIV( *Fout2,5); C_FIXDIV( *Fout3,5); C_FIXDIV( *Fout4,5);
|
||||||
|
scratch[0] = *Fout0;
|
||||||
|
|
||||||
|
C_MUL(scratch[1] ,*Fout1, tw[u*fstride]);
|
||||||
|
C_MUL(scratch[2] ,*Fout2, tw[2*u*fstride]);
|
||||||
|
C_MUL(scratch[3] ,*Fout3, tw[3*u*fstride]);
|
||||||
|
C_MUL(scratch[4] ,*Fout4, tw[4*u*fstride]);
|
||||||
|
|
||||||
|
C_ADD( scratch[7],scratch[1],scratch[4]);
|
||||||
|
C_SUB( scratch[10],scratch[1],scratch[4]);
|
||||||
|
C_ADD( scratch[8],scratch[2],scratch[3]);
|
||||||
|
C_SUB( scratch[9],scratch[2],scratch[3]);
|
||||||
|
|
||||||
|
Fout0->r += scratch[7].r + scratch[8].r;
|
||||||
|
Fout0->i += scratch[7].i + scratch[8].i;
|
||||||
|
|
||||||
|
scratch[5].r = scratch[0].r + S_MUL(scratch[7].r,ya.r) + S_MUL(scratch[8].r,yb.r);
|
||||||
|
scratch[5].i = scratch[0].i + S_MUL(scratch[7].i,ya.r) + S_MUL(scratch[8].i,yb.r);
|
||||||
|
|
||||||
|
scratch[6].r = S_MUL(scratch[10].i,ya.i) + S_MUL(scratch[9].i,yb.i);
|
||||||
|
scratch[6].i = -S_MUL(scratch[10].r,ya.i) - S_MUL(scratch[9].r,yb.i);
|
||||||
|
|
||||||
|
C_SUB(*Fout1,scratch[5],scratch[6]);
|
||||||
|
C_ADD(*Fout4,scratch[5],scratch[6]);
|
||||||
|
|
||||||
|
scratch[11].r = scratch[0].r + S_MUL(scratch[7].r,yb.r) + S_MUL(scratch[8].r,ya.r);
|
||||||
|
scratch[11].i = scratch[0].i + S_MUL(scratch[7].i,yb.r) + S_MUL(scratch[8].i,ya.r);
|
||||||
|
scratch[12].r = - S_MUL(scratch[10].i,yb.i) + S_MUL(scratch[9].i,ya.i);
|
||||||
|
scratch[12].i = S_MUL(scratch[10].r,yb.i) - S_MUL(scratch[9].r,ya.i);
|
||||||
|
|
||||||
|
C_ADD(*Fout2,scratch[11],scratch[12]);
|
||||||
|
C_SUB(*Fout3,scratch[11],scratch[12]);
|
||||||
|
|
||||||
|
++Fout0;++Fout1;++Fout2;++Fout3;++Fout4;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* perform the butterfly for one stage of a mixed radix FFT */
|
||||||
|
static void kf_bfly_generic(
|
||||||
|
kiss_fft_cpx * Fout,
|
||||||
|
const size_t fstride,
|
||||||
|
const kiss_fft_cfg st,
|
||||||
|
int m,
|
||||||
|
int p
|
||||||
|
)
|
||||||
|
{
|
||||||
|
int u,k,q1,q;
|
||||||
|
kiss_fft_cpx * twiddles = st->twiddles;
|
||||||
|
kiss_fft_cpx t;
|
||||||
|
int Norig = st->nfft;
|
||||||
|
|
||||||
|
kiss_fft_cpx * scratch = (kiss_fft_cpx*)KISS_FFT_TMP_ALLOC(sizeof(kiss_fft_cpx)*p);
|
||||||
|
|
||||||
|
for ( u=0; u<m; ++u ) {
|
||||||
|
k=u;
|
||||||
|
for ( q1=0 ; q1<p ; ++q1 ) {
|
||||||
|
scratch[q1] = Fout[ k ];
|
||||||
|
C_FIXDIV(scratch[q1],p);
|
||||||
|
k += m;
|
||||||
|
}
|
||||||
|
|
||||||
|
k=u;
|
||||||
|
for ( q1=0 ; q1<p ; ++q1 ) {
|
||||||
|
int twidx=0;
|
||||||
|
Fout[ k ] = scratch[0];
|
||||||
|
for (q=1;q<p;++q ) {
|
||||||
|
twidx += fstride * k;
|
||||||
|
if (twidx>=Norig) twidx-=Norig;
|
||||||
|
C_MUL(t,scratch[q] , twiddles[twidx] );
|
||||||
|
C_ADDTO( Fout[ k ] ,t);
|
||||||
|
}
|
||||||
|
k += m;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
KISS_FFT_TMP_FREE(scratch);
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
void kf_work(
|
||||||
|
kiss_fft_cpx * Fout,
|
||||||
|
const kiss_fft_cpx * f,
|
||||||
|
const size_t fstride,
|
||||||
|
int in_stride,
|
||||||
|
int * factors,
|
||||||
|
const kiss_fft_cfg st
|
||||||
|
)
|
||||||
|
{
|
||||||
|
kiss_fft_cpx * Fout_beg=Fout;
|
||||||
|
const int p=*factors++; /* the radix */
|
||||||
|
const int m=*factors++; /* stage's fft length/p */
|
||||||
|
const kiss_fft_cpx * Fout_end = Fout + p*m;
|
||||||
|
|
||||||
|
#ifdef _OPENMP
|
||||||
|
/* use openmp extensions at the */
|
||||||
|
/* top-level (not recursive) */
|
||||||
|
if (fstride==1 && p<=5)
|
||||||
|
{
|
||||||
|
int k;
|
||||||
|
|
||||||
|
/* execute the p different work units in different threads */
|
||||||
|
# pragma omp parallel for
|
||||||
|
for (k=0;k<p;++k)
|
||||||
|
kf_work( Fout +k*m, f+ fstride*in_stride*k,fstride*p,in_stride,factors,st);
|
||||||
|
// all threads have joined by this point
|
||||||
|
|
||||||
|
switch (p) {
|
||||||
|
case 2: kf_bfly2(Fout,fstride,st,m); break;
|
||||||
|
case 3: kf_bfly3(Fout,fstride,st,m); break;
|
||||||
|
case 4: kf_bfly4(Fout,fstride,st,m); break;
|
||||||
|
case 5: kf_bfly5(Fout,fstride,st,m); break;
|
||||||
|
default: kf_bfly_generic(Fout,fstride,st,m,p); break;
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (m==1) {
|
||||||
|
do{
|
||||||
|
*Fout = *f;
|
||||||
|
f += fstride*in_stride;
|
||||||
|
}while(++Fout != Fout_end );
|
||||||
|
}else{
|
||||||
|
do{
|
||||||
|
/* recursive call:
|
||||||
|
* DFT of size m*p performed by doing
|
||||||
|
* p instances of smaller DFTs of size m,
|
||||||
|
* each one takes a decimated version of the input
|
||||||
|
*/
|
||||||
|
kf_work( Fout , f, fstride*p, in_stride, factors,st);
|
||||||
|
f += fstride*in_stride;
|
||||||
|
}while( (Fout += m) != Fout_end );
|
||||||
|
}
|
||||||
|
|
||||||
|
Fout=Fout_beg;
|
||||||
|
|
||||||
|
/* recombine the p smaller DFTs */
|
||||||
|
switch (p) {
|
||||||
|
case 2: kf_bfly2(Fout,fstride,st,m); break;
|
||||||
|
case 3: kf_bfly3(Fout,fstride,st,m); break;
|
||||||
|
case 4: kf_bfly4(Fout,fstride,st,m); break;
|
||||||
|
case 5: kf_bfly5(Fout,fstride,st,m); break;
|
||||||
|
default: kf_bfly_generic(Fout,fstride,st,m,p); break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* facbuf is populated by p1,m1,p2,m2, ...
|
||||||
|
where
|
||||||
|
p[i] * m[i] = m[i-1]
|
||||||
|
m0 = n */
|
||||||
|
static
|
||||||
|
void kf_factor(int n,int * facbuf)
|
||||||
|
{
|
||||||
|
int p=4;
|
||||||
|
double floor_sqrt;
|
||||||
|
floor_sqrt = floor( sqrt((double)n) );
|
||||||
|
|
||||||
|
/*factor out powers of 4, powers of 2, then any remaining primes */
|
||||||
|
do {
|
||||||
|
while (n % p) {
|
||||||
|
switch (p) {
|
||||||
|
case 4: p = 2; break;
|
||||||
|
case 2: p = 3; break;
|
||||||
|
default: p += 2; break;
|
||||||
|
}
|
||||||
|
if (p > floor_sqrt)
|
||||||
|
p = n; /* no more factors, skip to end */
|
||||||
|
}
|
||||||
|
n /= p;
|
||||||
|
*facbuf++ = p;
|
||||||
|
*facbuf++ = n;
|
||||||
|
} while (n > 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
*
|
||||||
|
* User-callable function to allocate all necessary storage space for the fft.
|
||||||
|
*
|
||||||
|
* The return value is a contiguous block of memory, allocated with malloc. As such,
|
||||||
|
* It can be freed with free(), rather than a kiss_fft-specific function.
|
||||||
|
* */
|
||||||
|
kiss_fft_cfg kiss_fft_alloc(int nfft,int inverse_fft,void * mem,size_t * lenmem )
|
||||||
|
{
|
||||||
|
kiss_fft_cfg st=NULL;
|
||||||
|
size_t memneeded = sizeof(struct kiss_fft_state)
|
||||||
|
+ sizeof(kiss_fft_cpx)*(nfft-1); /* twiddle factors*/
|
||||||
|
|
||||||
|
if ( lenmem==NULL ) {
|
||||||
|
st = ( kiss_fft_cfg)KISS_FFT_MALLOC( memneeded );
|
||||||
|
}else{
|
||||||
|
if (mem != NULL && *lenmem >= memneeded)
|
||||||
|
st = (kiss_fft_cfg)mem;
|
||||||
|
*lenmem = memneeded;
|
||||||
|
}
|
||||||
|
if (st) {
|
||||||
|
int i;
|
||||||
|
st->nfft=nfft;
|
||||||
|
st->inverse = inverse_fft;
|
||||||
|
|
||||||
|
for (i=0;i<nfft;++i) {
|
||||||
|
const double pi=3.141592653589793238462643383279502884197169399375105820974944;
|
||||||
|
double phase = -2*pi*i / nfft;
|
||||||
|
if (st->inverse)
|
||||||
|
phase *= -1;
|
||||||
|
kf_cexp(st->twiddles+i, phase );
|
||||||
|
}
|
||||||
|
|
||||||
|
kf_factor(nfft,st->factors);
|
||||||
|
}
|
||||||
|
return st;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void kiss_fft_stride(kiss_fft_cfg st,const kiss_fft_cpx *fin,kiss_fft_cpx *fout,int in_stride)
|
||||||
|
{
|
||||||
|
if (fin == fout) {
|
||||||
|
/* NOTE: this is not really an in-place FFT algorithm. */
|
||||||
|
/* It just performs an out-of-place FFT into a temp buffer */
|
||||||
|
kiss_fft_cpx * tmpbuf = (kiss_fft_cpx*)KISS_FFT_TMP_ALLOC( sizeof(kiss_fft_cpx)*st->nfft);
|
||||||
|
kf_work(tmpbuf,fin,1,in_stride, st->factors,st);
|
||||||
|
memcpy(fout,tmpbuf,sizeof(kiss_fft_cpx)*st->nfft);
|
||||||
|
KISS_FFT_TMP_FREE(tmpbuf);
|
||||||
|
}else{
|
||||||
|
kf_work( fout, fin, 1,in_stride, st->factors,st );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void kiss_fft(kiss_fft_cfg cfg,const kiss_fft_cpx *fin,kiss_fft_cpx *fout)
|
||||||
|
{
|
||||||
|
kiss_fft_stride(cfg,fin,fout,1);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void kiss_fft_cleanup(void)
|
||||||
|
{
|
||||||
|
/* nothing needed any more */
|
||||||
|
}
|
||||||
|
|
||||||
|
int kiss_fft_next_fast_size(int n)
|
||||||
|
{
|
||||||
|
while(1) {
|
||||||
|
int m=n;
|
||||||
|
while ( (m%2) == 0 ) m/=2;
|
||||||
|
while ( (m%3) == 0 ) m/=3;
|
||||||
|
while ( (m%5) == 0 ) m/=5;
|
||||||
|
if (m<=1)
|
||||||
|
break; /* n is completely factorable by twos, threes, and fives */
|
||||||
|
n++;
|
||||||
|
}
|
||||||
|
return n;
|
||||||
|
}
|
||||||
159
Packages/KissFFT/Sources/KissFFT/kiss_fftr.c
Normal file
@@ -0,0 +1,159 @@
|
|||||||
|
/*
|
||||||
|
Copyright (c) 2003-2004, Mark Borgerding
|
||||||
|
|
||||||
|
All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
|
||||||
|
|
||||||
|
* Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
|
||||||
|
* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
|
||||||
|
* Neither the author nor the names of any contributors may be used to endorse or promote products derived from this software without specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "kiss_fftr.h"
|
||||||
|
#include "_kiss_fft_guts.h"
|
||||||
|
|
||||||
|
struct kiss_fftr_state{
|
||||||
|
kiss_fft_cfg substate;
|
||||||
|
kiss_fft_cpx * tmpbuf;
|
||||||
|
kiss_fft_cpx * super_twiddles;
|
||||||
|
#ifdef USE_SIMD
|
||||||
|
void * pad;
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
kiss_fftr_cfg kiss_fftr_alloc(int nfft,int inverse_fft,void * mem,size_t * lenmem)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
kiss_fftr_cfg st = NULL;
|
||||||
|
size_t subsize, memneeded;
|
||||||
|
|
||||||
|
if (nfft & 1) {
|
||||||
|
fprintf(stderr,"Real FFT optimization must be even.\n");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
nfft >>= 1;
|
||||||
|
|
||||||
|
kiss_fft_alloc (nfft, inverse_fft, NULL, &subsize);
|
||||||
|
memneeded = sizeof(struct kiss_fftr_state) + subsize + sizeof(kiss_fft_cpx) * ( nfft * 3 / 2);
|
||||||
|
|
||||||
|
if (lenmem == NULL) {
|
||||||
|
st = (kiss_fftr_cfg) KISS_FFT_MALLOC (memneeded);
|
||||||
|
} else {
|
||||||
|
if (*lenmem >= memneeded)
|
||||||
|
st = (kiss_fftr_cfg) mem;
|
||||||
|
*lenmem = memneeded;
|
||||||
|
}
|
||||||
|
if (!st)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
st->substate = (kiss_fft_cfg) (st + 1); /*just beyond kiss_fftr_state struct */
|
||||||
|
st->tmpbuf = (kiss_fft_cpx *) (((char *) st->substate) + subsize);
|
||||||
|
st->super_twiddles = st->tmpbuf + nfft;
|
||||||
|
kiss_fft_alloc(nfft, inverse_fft, st->substate, &subsize);
|
||||||
|
|
||||||
|
for (i = 0; i < nfft/2; ++i) {
|
||||||
|
double phase =
|
||||||
|
-3.14159265358979323846264338327 * ((double) (i+1) / nfft + .5);
|
||||||
|
if (inverse_fft)
|
||||||
|
phase *= -1;
|
||||||
|
kf_cexp (st->super_twiddles+i,phase);
|
||||||
|
}
|
||||||
|
return st;
|
||||||
|
}
|
||||||
|
|
||||||
|
void kiss_fftr(kiss_fftr_cfg st,const kiss_fft_scalar *timedata,kiss_fft_cpx *freqdata)
|
||||||
|
{
|
||||||
|
/* input buffer timedata is stored row-wise */
|
||||||
|
int k,ncfft;
|
||||||
|
kiss_fft_cpx fpnk,fpk,f1k,f2k,tw,tdc;
|
||||||
|
|
||||||
|
if ( st->substate->inverse) {
|
||||||
|
fprintf(stderr,"kiss fft usage error: improper alloc\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
ncfft = st->substate->nfft;
|
||||||
|
|
||||||
|
/*perform the parallel fft of two real signals packed in real,imag*/
|
||||||
|
kiss_fft( st->substate , (const kiss_fft_cpx*)timedata, st->tmpbuf );
|
||||||
|
/* The real part of the DC element of the frequency spectrum in st->tmpbuf
|
||||||
|
* contains the sum of the even-numbered elements of the input time sequence
|
||||||
|
* The imag part is the sum of the odd-numbered elements
|
||||||
|
*
|
||||||
|
* The sum of tdc.r and tdc.i is the sum of the input time sequence.
|
||||||
|
* yielding DC of input time sequence
|
||||||
|
* The difference of tdc.r - tdc.i is the sum of the input (dot product) [1,-1,1,-1...
|
||||||
|
* yielding Nyquist bin of input time sequence
|
||||||
|
*/
|
||||||
|
|
||||||
|
tdc.r = st->tmpbuf[0].r;
|
||||||
|
tdc.i = st->tmpbuf[0].i;
|
||||||
|
C_FIXDIV(tdc,2);
|
||||||
|
CHECK_OVERFLOW_OP(tdc.r ,+, tdc.i);
|
||||||
|
CHECK_OVERFLOW_OP(tdc.r ,-, tdc.i);
|
||||||
|
freqdata[0].r = tdc.r + tdc.i;
|
||||||
|
freqdata[ncfft].r = tdc.r - tdc.i;
|
||||||
|
#ifdef USE_SIMD
|
||||||
|
freqdata[ncfft].i = freqdata[0].i = _mm_set1_ps(0);
|
||||||
|
#else
|
||||||
|
freqdata[ncfft].i = freqdata[0].i = 0;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
for ( k=1;k <= ncfft/2 ; ++k ) {
|
||||||
|
fpk = st->tmpbuf[k];
|
||||||
|
fpnk.r = st->tmpbuf[ncfft-k].r;
|
||||||
|
fpnk.i = - st->tmpbuf[ncfft-k].i;
|
||||||
|
C_FIXDIV(fpk,2);
|
||||||
|
C_FIXDIV(fpnk,2);
|
||||||
|
|
||||||
|
C_ADD( f1k, fpk , fpnk );
|
||||||
|
C_SUB( f2k, fpk , fpnk );
|
||||||
|
C_MUL( tw , f2k , st->super_twiddles[k-1]);
|
||||||
|
|
||||||
|
freqdata[k].r = HALF_OF(f1k.r + tw.r);
|
||||||
|
freqdata[k].i = HALF_OF(f1k.i + tw.i);
|
||||||
|
freqdata[ncfft-k].r = HALF_OF(f1k.r - tw.r);
|
||||||
|
freqdata[ncfft-k].i = HALF_OF(tw.i - f1k.i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void kiss_fftri(kiss_fftr_cfg st,const kiss_fft_cpx *freqdata,kiss_fft_scalar *timedata)
|
||||||
|
{
|
||||||
|
/* input buffer timedata is stored row-wise */
|
||||||
|
int k, ncfft;
|
||||||
|
|
||||||
|
if (st->substate->inverse == 0) {
|
||||||
|
fprintf (stderr, "kiss fft usage error: improper alloc\n");
|
||||||
|
exit (1);
|
||||||
|
}
|
||||||
|
|
||||||
|
ncfft = st->substate->nfft;
|
||||||
|
|
||||||
|
st->tmpbuf[0].r = freqdata[0].r + freqdata[ncfft].r;
|
||||||
|
st->tmpbuf[0].i = freqdata[0].r - freqdata[ncfft].r;
|
||||||
|
C_FIXDIV(st->tmpbuf[0],2);
|
||||||
|
|
||||||
|
for (k = 1; k <= ncfft / 2; ++k) {
|
||||||
|
kiss_fft_cpx fk, fnkc, fek, fok, tmp;
|
||||||
|
fk = freqdata[k];
|
||||||
|
fnkc.r = freqdata[ncfft - k].r;
|
||||||
|
fnkc.i = -freqdata[ncfft - k].i;
|
||||||
|
C_FIXDIV( fk , 2 );
|
||||||
|
C_FIXDIV( fnkc , 2 );
|
||||||
|
|
||||||
|
C_ADD (fek, fk, fnkc);
|
||||||
|
C_SUB (tmp, fk, fnkc);
|
||||||
|
C_MUL (fok, tmp, st->super_twiddles[k-1]);
|
||||||
|
C_ADD (st->tmpbuf[k], fek, fok);
|
||||||
|
C_SUB (st->tmpbuf[ncfft - k], fek, fok);
|
||||||
|
#ifdef USE_SIMD
|
||||||
|
st->tmpbuf[ncfft - k].i *= _mm_set1_ps(-1.0);
|
||||||
|
#else
|
||||||
|
st->tmpbuf[ncfft - k].i *= -1;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
kiss_fft (st->substate, st->tmpbuf, (kiss_fft_cpx *) timedata);
|
||||||
|
}
|
||||||
76
README.md
Normal file
@@ -0,0 +1,76 @@
|
|||||||
|
# ECGSynKit
|
||||||
|
|
||||||
|
Swift Package for generating synthetic ECG signals. Includes implementation of ECGSYN [[1]](#1).
|
||||||
|
|
||||||
|
# Notes
|
||||||
|
|
||||||
|
Implementation roughly corresponds with MATLAB/Java implementation of ECGSYN [[2]](#2) with a few
|
||||||
|
implementation differences to improve performance. The library is also structured so that expensive
|
||||||
|
computations can be reused for multiple signals and a single RR series can be reused to generate multi-lead
|
||||||
|
ECGs.
|
||||||
|
|
||||||
|
This implementation generalizes the attractor array to arbitrary size to allow modeling R′ and S′ morphologies.
|
||||||
|
|
||||||
|
# Usage
|
||||||
|
|
||||||
|
Initialize `TimeParameters` and `RRParameters`:
|
||||||
|
```swift
|
||||||
|
import ECGSynKit
|
||||||
|
|
||||||
|
let timeParameters = TimeParameters(
|
||||||
|
numBeats: 500,
|
||||||
|
srInternal: 10, // internal generator sampling rate
|
||||||
|
decimateFactor: 2, // decimation factor (output signal sample rate will be `srInternal / decimateFactor`)
|
||||||
|
hrMean: 60, // mean heart rate in BPM
|
||||||
|
hrStd: 1, // heart rate standard deviation
|
||||||
|
seed: 1) // rng seed value
|
||||||
|
|
||||||
|
let rrParameters = RRParameters(
|
||||||
|
flo: 0.1, // low frequency oscillation (Mayer wave) in Hz
|
||||||
|
flostd: 0.01, // low frequency oscillation standard deviation
|
||||||
|
fhi: 0.25, // high frequency oscillation (respiration) in Hz
|
||||||
|
fhistd: 0.01, // high frequency oscillation standard deviation
|
||||||
|
lfhfratio: 0.5) // low frequency to high frequency power ratio
|
||||||
|
```
|
||||||
|
|
||||||
|
Initialize an RR Series generator. This will prepare an FFT setup for the required signal size.
|
||||||
|
Afterwards generate the RR Series:
|
||||||
|
|
||||||
|
``` swift
|
||||||
|
let rrGenerator = ECGSynRRGenerator(params: timeParameters)
|
||||||
|
let rrSeries = rrGenerator.generateSeries(params: rrParameters)
|
||||||
|
```
|
||||||
|
|
||||||
|
The `rrSeries` can be used multiple times such as to generate multilead ECG signals.
|
||||||
|
|
||||||
|
|
||||||
|
The `attractors` parameter specify the morphology of the exponential extrema of the ECG. For a normal
|
||||||
|
ECG there are 5 attractors corresponding to PQRST. The parameters `θ`, `a`, `b` are as described in the paper
|
||||||
|
and are angular position around the signal limit circle, amplitude, and width. The `θrf` parameter is optional
|
||||||
|
and is a generalization of the stretching factors for `θ`. Each `θ` will be adjusted by `θ * pow(hrMean / 60.0, θrf)`.
|
||||||
|
|
||||||
|
``` swift
|
||||||
|
let params = ECGSyn.Parameters(
|
||||||
|
range: (-0.4, 1.2) // the voltage range to scale the signal in mV
|
||||||
|
noiseAmplitude: 0.01, // the amplitude of the additive uniform noise
|
||||||
|
attractors: [
|
||||||
|
// θ, a, b, θrf
|
||||||
|
.make(deg: -70, 1.2, 0.25, 0.25),
|
||||||
|
.make(deg: -15, -5.0, 0.1, 0.5),
|
||||||
|
.make(deg: 0, 30, 0.1),
|
||||||
|
.make(deg: 15, -7.5, 0.1, 0.5),
|
||||||
|
.make(deg: 100, 0.75, 0.4, 0.25),
|
||||||
|
]
|
||||||
|
)
|
||||||
|
|
||||||
|
let signal = ECGSyn.generate(params: timeParameters) // signal is [Double]
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
# References
|
||||||
|
|
||||||
|
<a id="1">[1]</a>
|
||||||
|
McSharry PE, Clifford GD, Tarassenko L, Smith L. A dynamical model for generating synthetic electrocardiogram signals. IEEE Transactions on Biomedical Engineering 50(3): 289-294; March 2003.
|
||||||
|
|
||||||
|
<a id="2">[2]</a>
|
||||||
|
Goldberger, A., Amaral, L., Glass, L., Hausdorff, J., Ivanov, P. C., Mark, R., ... & Stanley, H. E. (2000). PhysioBank, PhysioToolkit, and PhysioNet: Components of a new research resource for complex physiologic signals. Circulation [Online]. 101 (23), pp. e215–e220.
|
||||||
105
Sources/ECGSynKit/ECGSyn.swift
Normal file
@@ -0,0 +1,105 @@
|
|||||||
|
import Foundation
|
||||||
|
import OdeInt
|
||||||
|
import RealModule
|
||||||
|
|
||||||
|
public struct ECGSyn {
|
||||||
|
public struct Attractor {
|
||||||
|
/// Angle of attractor in radians
|
||||||
|
public let θ: Double
|
||||||
|
/// Position of extremum above or below the z=0 plane.
|
||||||
|
public let a: Double
|
||||||
|
/// Width of the attractor.
|
||||||
|
public let b: Double
|
||||||
|
/// Angle rate factor adjustment `θ * pow(hrMean / 60.0, θrf)`
|
||||||
|
public let θrf: Double
|
||||||
|
|
||||||
|
public init(θ: Double, a: Double, b: Double, θrf: Double = 0.0) {
|
||||||
|
self.θ = θ
|
||||||
|
self.a = a
|
||||||
|
self.b = b
|
||||||
|
self.θrf = θrf
|
||||||
|
}
|
||||||
|
|
||||||
|
public init(deg: Double, a: Double, b: Double, θrf: Double = 0.0) {
|
||||||
|
self.init(θ: deg * .pi / 180, a: a, b: b, θrf: θrf)
|
||||||
|
}
|
||||||
|
|
||||||
|
static func make(deg: Double, _ a: Double, _ b: Double, _ θrf: Double = 0.0) -> Attractor {
|
||||||
|
Attractor(deg: deg, a: a, b: b, θrf: θrf)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public struct Parameters {
|
||||||
|
/// The ECG amplitude in mV.
|
||||||
|
public let range: (Double, Double) = (-0.4, 1.2)
|
||||||
|
|
||||||
|
/// Amplitude of the noise.
|
||||||
|
public let noiseAmplitude: Double = 0.0
|
||||||
|
|
||||||
|
/// Descriptors of the extrema/attractors for the dynamical model.
|
||||||
|
public let attractors: [Attractor] = [
|
||||||
|
.make(deg: -70, 1.2, 0.25, 0.25),
|
||||||
|
.make(deg: -15, -5.0, 0.1, 0.5),
|
||||||
|
.make(deg: 0, 30, 0.1),
|
||||||
|
.make(deg: 15, -7.5, 0.1, 0.5),
|
||||||
|
.make(deg: 100, 0.75, 0.4, 0.25),
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
public static func generate(params: Parameters, rrSeries: ECGSynRRSeries<Double>) -> [Double] {
|
||||||
|
var rng = rrSeries.rng
|
||||||
|
let srInternal = rrSeries.timeParameters.srInternal
|
||||||
|
|
||||||
|
let hrSec = rrSeries.timeParameters.hrMean / 60.0
|
||||||
|
let hrFact = sqrt(hrSec)
|
||||||
|
|
||||||
|
// adjust extrema parameters for mean heart rate
|
||||||
|
let ti = params.attractors.map { $0.θ * pow(hrSec, $0.θrf) }
|
||||||
|
let ai = params.attractors.map { $0.a }
|
||||||
|
let bi = params.attractors.map { $0.b * hrFact }
|
||||||
|
|
||||||
|
let fhi = rrSeries.rrParamaters.fhi
|
||||||
|
|
||||||
|
let nt = rrSeries.count
|
||||||
|
|
||||||
|
let dt = 1.0 / Double(srInternal)
|
||||||
|
let ts = (0 ..< nt).map { Double($0) * dt }
|
||||||
|
let x0 = SIMD3<Double>(1.0, 0.0, 0.04)
|
||||||
|
|
||||||
|
let result = SIMD3<Double>.integrate(over: ts, y0: x0, tol: 1e-6) { x, t in
|
||||||
|
let ta = atan2(x[1], x[0])
|
||||||
|
|
||||||
|
let r0 = 1.0
|
||||||
|
let a0 = 1.0 - sqrt(x[0] * x[0] + x[1] * x[1]) / r0
|
||||||
|
|
||||||
|
let w0 = 2 * .pi / rrSeries.valueAt(t)
|
||||||
|
|
||||||
|
let zbase = 0.005 * sin(2 * .pi * fhi * t)
|
||||||
|
|
||||||
|
var dxdt = SIMD3<Double>(a0 * x[0] - w0 * x[1], a0 * x[1] + w0 * x[0], 0.0)
|
||||||
|
|
||||||
|
for i in 0 ..< ti.count {
|
||||||
|
let dt = remainder(ta - ti[i], 2 * .pi)
|
||||||
|
|
||||||
|
dxdt[2] += -ai[i] * dt * exp(-0.5 * (dt * dt) / (bi[i] * bi[i]))
|
||||||
|
}
|
||||||
|
dxdt[2] += -1.0 * (x[2] - zbase)
|
||||||
|
|
||||||
|
return dxdt
|
||||||
|
}
|
||||||
|
|
||||||
|
// extract z and downsample to output sampling frequency
|
||||||
|
var zresult = stride(from: 0, to: nt, by: rrSeries.timeParameters.decimateFactor).map { result[$0][2] }
|
||||||
|
|
||||||
|
let (zmin, zmax) = zresult.minAndMax()!
|
||||||
|
let zrange = zmax - zmin
|
||||||
|
|
||||||
|
// Scale signal between -0.4 and 1.2 mV
|
||||||
|
// add uniformly distributed measurement noise
|
||||||
|
for i in 0 ..< zresult.count {
|
||||||
|
zresult[i] = (params.range.1 - params.range.0) * (zresult[i] - zmin) / zrange + params.range.0
|
||||||
|
zresult[i] += params.noiseAmplitude * (2.0 * rng.nextDouble() - 1.0)
|
||||||
|
}
|
||||||
|
return zresult
|
||||||
|
}
|
||||||
|
}
|
||||||
48
Sources/ECGSynKit/ECGSynKit.swift
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
import Algorithms
|
||||||
|
import ComplexModule
|
||||||
|
import RealModule
|
||||||
|
import Foundation
|
||||||
|
import PFFFT
|
||||||
|
|
||||||
|
public struct TimeParameters {
|
||||||
|
/// The number of beats to simulate.
|
||||||
|
let numBeats: Int = 12
|
||||||
|
|
||||||
|
/// The internal sampling frequency in Hz.
|
||||||
|
let srInternal: Int = 512
|
||||||
|
|
||||||
|
/// Output decimation factor
|
||||||
|
let decimateFactor: Int = 2
|
||||||
|
|
||||||
|
/// The mean heart rate in beats per minute.
|
||||||
|
let hrMean: Double = 60.0
|
||||||
|
|
||||||
|
/// The standard deviation of the heart rate.
|
||||||
|
let hrStd: Double = 1.0
|
||||||
|
|
||||||
|
/// RNG seed value.
|
||||||
|
let seed: UInt64 = 8
|
||||||
|
}
|
||||||
|
|
||||||
|
public struct RRParameters {
|
||||||
|
/// Mayer wave frequency in Hz.
|
||||||
|
let flo = 0.1
|
||||||
|
|
||||||
|
/// flo standard deviation.
|
||||||
|
let flostd = 0.01
|
||||||
|
|
||||||
|
/// Respiratory rate frequency in Hz.
|
||||||
|
let fhi = 0.25
|
||||||
|
|
||||||
|
/// fhi standard deviation.
|
||||||
|
let fhistd = 0.01
|
||||||
|
|
||||||
|
/// The ratio of power between low and high frequencies.
|
||||||
|
let lfhfRatio: Double = 0.5
|
||||||
|
}
|
||||||
|
|
||||||
|
func stdev(_ data: [Double]) -> Double {
|
||||||
|
let n = Double(data.count)
|
||||||
|
let mean = data.reduce(0.0, +) / n
|
||||||
|
return sqrt(data.lazy.map { ($0 - mean) * ($0 - mean) }.reduce(0.0, +) / (n - 1))
|
||||||
|
}
|
||||||
81
Sources/ECGSynKit/ECGSynRRGenerator.swift
Normal file
@@ -0,0 +1,81 @@
|
|||||||
|
import ComplexModule
|
||||||
|
import Foundation
|
||||||
|
import PFFFT
|
||||||
|
import RealModule
|
||||||
|
|
||||||
|
public struct ECGSynRRGenerator: ~Copyable {
|
||||||
|
let nrr: Int
|
||||||
|
|
||||||
|
let fft: FFT<Double>
|
||||||
|
let spectrum: Buffer<Complex<Double>>
|
||||||
|
let signal: Buffer<Double>
|
||||||
|
|
||||||
|
var rng: RandomNumberGenerator
|
||||||
|
|
||||||
|
// mean and standard deviation of RR intervals
|
||||||
|
let rrMean: Double
|
||||||
|
let rrStd: Double
|
||||||
|
|
||||||
|
let timeParameters: TimeParameters
|
||||||
|
|
||||||
|
public init(params: TimeParameters) {
|
||||||
|
typealias FFT = PFFFT.FFT<Double>
|
||||||
|
|
||||||
|
let sr = params.srInternal
|
||||||
|
rrMean = 60.0 / params.hrMean
|
||||||
|
rrStd = 60.0 * params.hrStd / (params.hrMean * params.hrMean)
|
||||||
|
|
||||||
|
nrr = FFT.nearestValidSize(params.numBeats * sr * Int(rrMean.rounded(.up)), higher: true)
|
||||||
|
fft = try! FFT(n: nrr)
|
||||||
|
spectrum = fft.makeSpectrumBuffer(extra: 1)
|
||||||
|
signal = fft.makeSignalBuffer()
|
||||||
|
|
||||||
|
timeParameters = params
|
||||||
|
rng = Xoshiro256Plus(seed: params.seed)
|
||||||
|
}
|
||||||
|
|
||||||
|
public mutating func generateSeries(params: RRParameters) -> ECGSynRRSeries<Double> {
|
||||||
|
let rr = generateSignal(params: params)
|
||||||
|
return ECGSynRRSeries(timeParameters: timeParameters, rrParamaters: params, rng: rng, signal: rr)
|
||||||
|
}
|
||||||
|
|
||||||
|
public mutating func generateSignal(params: RRParameters) -> [Double] {
|
||||||
|
let w1 = 2.0 * .pi * params.flo
|
||||||
|
let w2 = 2.0 * .pi * params.fhi
|
||||||
|
let c1 = 2.0 * .pi * params.flostd
|
||||||
|
let c2 = 2.0 * .pi * params.fhistd
|
||||||
|
|
||||||
|
let sig2 = 1.0
|
||||||
|
let sig1 = params.lfhfRatio
|
||||||
|
|
||||||
|
let sr = Double(timeParameters.srInternal)
|
||||||
|
|
||||||
|
let dw = (sr / Double(nrr)) * 2.0 * .pi
|
||||||
|
|
||||||
|
spectrum.mapInPlaceSwapLast { i in
|
||||||
|
let w = dw * Double(i)
|
||||||
|
|
||||||
|
let dw1 = w - w1
|
||||||
|
let dw2 = w - w2
|
||||||
|
let hw = sig1 * exp(-dw1 * dw1 / (2.0 * c1 * c1)) / sqrt(2.0 * .pi * c1 * c1)
|
||||||
|
+ sig2 * exp(-dw2 * dw2 / (2.0 * c2 * c2)) / sqrt(2.0 * .pi * c2 * c2)
|
||||||
|
|
||||||
|
let sw = (sr / 2.0) * sqrt(hw)
|
||||||
|
let ph = 2.0 * .pi * rng.nextDouble()
|
||||||
|
|
||||||
|
return Complex(length: sw, phase: ph)
|
||||||
|
}
|
||||||
|
|
||||||
|
fft.inverse(spectrum: spectrum, signal: signal)
|
||||||
|
|
||||||
|
var rr = signal.map { $0 * 1.0 / Double(nrr) }
|
||||||
|
|
||||||
|
let xstd = stdev(rr)
|
||||||
|
let ratio = rrStd / xstd
|
||||||
|
|
||||||
|
for i in 0 ..< nrr {
|
||||||
|
rr[i] = rr[i] * ratio + rrMean
|
||||||
|
}
|
||||||
|
return rr
|
||||||
|
}
|
||||||
|
}
|
||||||
46
Sources/ECGSynKit/ECGSynRRSeries.swift
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
import Foundation
|
||||||
|
import RealModule
|
||||||
|
import Algorithms
|
||||||
|
|
||||||
|
public struct ECGSynRRSeries<T: BinaryFloatingPoint> {
|
||||||
|
let timeParameters: TimeParameters
|
||||||
|
let rrParamaters: RRParameters
|
||||||
|
let rng: RandomNumberGenerator
|
||||||
|
let count: Int
|
||||||
|
|
||||||
|
struct Segment {
|
||||||
|
let end: T
|
||||||
|
let value: T
|
||||||
|
}
|
||||||
|
let segments: [Segment]
|
||||||
|
|
||||||
|
public init(timeParameters: TimeParameters, rrParamaters: RRParameters, rng: RandomNumberGenerator, signal: [T]) {
|
||||||
|
self.timeParameters = timeParameters
|
||||||
|
self.rrParamaters = rrParamaters
|
||||||
|
self.rng = rng
|
||||||
|
|
||||||
|
let sr = T(timeParameters.srInternal)
|
||||||
|
|
||||||
|
var rrn = [Segment]()
|
||||||
|
// generate piecewise RR time series
|
||||||
|
do {
|
||||||
|
var tecg = T.zero
|
||||||
|
var i = 0
|
||||||
|
while i < signal.count {
|
||||||
|
tecg += signal[i]
|
||||||
|
rrn.append(Segment(end: tecg, value: signal[i]))
|
||||||
|
i = Int((tecg * sr).rounded(.toNearestOrEven)) + 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
segments = rrn
|
||||||
|
count = signal.count
|
||||||
|
}
|
||||||
|
|
||||||
|
@inline(__always)
|
||||||
|
public func valueAt(_ t: T) -> T {
|
||||||
|
let index = min(segments.partitioningIndex { t < $0.end }, segments.endIndex - 1)
|
||||||
|
return segments[index].value
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
9
Sources/ECGSynKit/RandomNumberGenerator.swift
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
extension RandomNumberGenerator {
|
||||||
|
mutating func nextDouble() -> Double {
|
||||||
|
Double(next() >> 11) * 0x1.0p-53
|
||||||
|
}
|
||||||
|
|
||||||
|
mutating func nextFloat() -> Float {
|
||||||
|
Float(next() >> 40) * 0x1.0p-24
|
||||||
|
}
|
||||||
|
}
|
||||||
21
Sources/ECGSynKit/SplitMix64.swift
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
|
||||||
|
struct SplitMix64 : RandomNumberGenerator {
|
||||||
|
public typealias State = UInt64
|
||||||
|
public private(set) var state: State
|
||||||
|
|
||||||
|
init(state: UInt64) {
|
||||||
|
self.state = state
|
||||||
|
}
|
||||||
|
|
||||||
|
public mutating func next() -> UInt64 {
|
||||||
|
state &+= 0x9E3779B97F4A7C15
|
||||||
|
var z = state
|
||||||
|
z = (z ^ (z >> 30)) &* 0xBF58476D1CE4E5B9
|
||||||
|
z = (z ^ (z >> 27)) &* 0x94D049BB133111EB
|
||||||
|
return z ^ (z >> 31)
|
||||||
|
}
|
||||||
|
|
||||||
|
public mutating func nextDouble() -> Double {
|
||||||
|
Double(next() >> 11) * 0x1.0p-53
|
||||||
|
}
|
||||||
|
}
|
||||||
59
Sources/ECGSynKit/Xoshiro256Plus.swift
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
import Foundation
|
||||||
|
|
||||||
|
public enum Xoshiro256: Equatable {
|
||||||
|
public typealias State = (UInt64, UInt64, UInt64, UInt64)
|
||||||
|
|
||||||
|
internal static var invalidState: State { (0, 0, 0, 0) }
|
||||||
|
|
||||||
|
internal static func isValid(state: State) -> Bool {
|
||||||
|
state != invalidState
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@inlinable
|
||||||
|
@inline(__always)
|
||||||
|
internal func rotl(_ x: UInt64, _ k: UInt64) -> UInt64 {
|
||||||
|
(x << k) | (x >> (64 &- k))
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Xoshiro256Plus: RandomNumberGenerator {
|
||||||
|
public typealias State = Xoshiro256.State
|
||||||
|
|
||||||
|
private var state: State
|
||||||
|
|
||||||
|
public init() {
|
||||||
|
var generator = SystemRandomNumberGenerator()
|
||||||
|
self.init(seed: generator.next())
|
||||||
|
}
|
||||||
|
|
||||||
|
public init(seed: UInt64) {
|
||||||
|
var generator = SplitMix64(state: seed)
|
||||||
|
var state = Xoshiro256.invalidState
|
||||||
|
|
||||||
|
repeat {
|
||||||
|
state = (generator.next(), generator.next(), generator.next(), generator.next())
|
||||||
|
} while !Xoshiro256.isValid(state: state)
|
||||||
|
|
||||||
|
self.init(state: state)
|
||||||
|
}
|
||||||
|
|
||||||
|
public init(state: State) {
|
||||||
|
precondition(Xoshiro256.isValid(state: state), "The state must not be zero")
|
||||||
|
self.state = state
|
||||||
|
}
|
||||||
|
|
||||||
|
public mutating func next() -> UInt64 {
|
||||||
|
let result = state.0 &+ state.3
|
||||||
|
let t = state.1 << 17
|
||||||
|
|
||||||
|
state.2 ^= state.0
|
||||||
|
state.3 ^= state.1
|
||||||
|
state.1 ^= state.2
|
||||||
|
state.0 ^= state.3
|
||||||
|
|
||||||
|
state.2 ^= t
|
||||||
|
state.3 = rotl(state.3, 45)
|
||||||
|
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
}
|
||||||
19
Tests/ECGSynKitTests/ECGSynKitTests.swift
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
import Testing
|
||||||
|
@testable import ECGSynKit
|
||||||
|
import PFFFT
|
||||||
|
import ComplexModule
|
||||||
|
import Foundation
|
||||||
|
|
||||||
|
@Test func ecgSynTest () {
|
||||||
|
let timeParameters = TimeParameters()
|
||||||
|
let rrParameters = RRParameters()
|
||||||
|
|
||||||
|
var rrg = ECGSynRRGenerator(params: timeParameters)
|
||||||
|
|
||||||
|
let parameters = ECGSyn.Parameters()
|
||||||
|
let ecg = ECGSyn.generate(params: parameters, rrSeries: rrg.generateSeries(params: rrParameters))
|
||||||
|
// write ecg to file
|
||||||
|
let url = URL(fileURLWithPath: "ecg.txt")
|
||||||
|
let ecgString = ecg.map { String($0) }.joined(separator: "\n")
|
||||||
|
try! ecgString.write(to: url, atomically: true, encoding: .utf8)
|
||||||
|
}
|
||||||
11
ecgsyn-1.0.0/C/index.html
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
<html>
|
||||||
|
<head><title>Index of /static/published-projects/ecgsyn/1.0.0/C/</title></head>
|
||||||
|
<body>
|
||||||
|
<h1>Index of /static/published-projects/ecgsyn/1.0.0/C/</h1><hr><pre><a href="../">../</a>
|
||||||
|
<a href="linux/">linux/</a> 12-Apr-2019 17:35 -
|
||||||
|
<a href="solaris/">solaris/</a> 12-Apr-2019 17:35 -
|
||||||
|
<a href="src/">src/</a> 12-Apr-2019 17:35 -
|
||||||
|
<a href="windows/">windows/</a> 12-Apr-2019 17:35 -
|
||||||
|
<a href="index.shtml">index.shtml</a> 12-Apr-2019 17:35 4274
|
||||||
|
</pre><hr></body>
|
||||||
|
</html>
|
||||||
114
ecgsyn-1.0.0/C/index.shtml
Normal file
@@ -0,0 +1,114 @@
|
|||||||
|
<!--#set var="TITLE" value="Compiling and using the C version of ECGSYN"-->
|
||||||
|
<!--#include virtual="/head.shtml"-->
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<h2>Compiling ECGSYN</h2>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Sources for the C version of <a href="../">ECGSYN</a> are <a
|
||||||
|
href="src/">here</a>. Note, however, that two additional files are required in
|
||||||
|
order to compile ECGSYN. These files (<tt>dfour1.c</tt> and <tt>ran1.c</tt>)
|
||||||
|
are those included in <a href="http://www.nr.com" target="other">Numerical
|
||||||
|
Recipes in C</a>. Before attempting to compile ECGSYN, obtain these two files
|
||||||
|
from Numerical Recipes in C and place them in the same directory as the other
|
||||||
|
sources. (These files are not provided here because they cannot be freely
|
||||||
|
redistributed.)
|
||||||
|
|
||||||
|
<p>
|
||||||
|
If you cannot obtain <tt>dfour1.c</tt> and <tt>ran1.c</tt>, several
|
||||||
|
alternatives are available, including ready-to-run executable versions of
|
||||||
|
ECGSYN for <a href="linux/">GNU/Linux</a>, <a href="solaris/">Solaris</a>, and
|
||||||
|
<a href="windows/">MS-Windows</a>, as well as <a
|
||||||
|
href="../Matlab/">Matlab/Octave</a> and <a href="../Java/">Java</a>
|
||||||
|
implementations of ECGSYN.
|
||||||
|
|
||||||
|
<p>
|
||||||
|
On most platforms, including GNU/Linux, MacOS X, and Unix, compile ECGSYN
|
||||||
|
by typing
|
||||||
|
<pre>
|
||||||
|
make
|
||||||
|
</pre>
|
||||||
|
in a terminal window. This will also work under MS-Windows if you have
|
||||||
|
installed the free <a href="http://www.cygwin.com" target="other">Cygwin/gcc
|
||||||
|
development toolkit</a>. If you wish to use another compiler under MS-Windows,
|
||||||
|
you are on your own.
|
||||||
|
|
||||||
|
|
||||||
|
<h2>Running ECGSYN</h2>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
The executable version is named <tt>ecgsyn</tt> (or, under MS-Windows,
|
||||||
|
<tt>ecgsyn.exe</tt>). Once you have this file, move it into any directory in
|
||||||
|
your PATH and run it by typing
|
||||||
|
<pre>
|
||||||
|
ecgsyn
|
||||||
|
</pre>
|
||||||
|
in a terminal window. You may add options (switches) to the '<tt>ecgsyn</tt>'
|
||||||
|
command; the option '<tt>$</tt>', as in
|
||||||
|
<pre>
|
||||||
|
ecgsyn $
|
||||||
|
</pre>
|
||||||
|
starts ECGSYN in interactive mode, as shown below:
|
||||||
|
|
||||||
|
<pre>
|
||||||
|
>> ecgsyn $
|
||||||
|
ECGSYN: A program for generating a realistic synthetic ECG
|
||||||
|
Copyright (c) 2003 by Patrick McSharry & Gari Clifford. All rights reserved.
|
||||||
|
|
||||||
|
O Name of output data file "ecgsyn.dat"
|
||||||
|
n Approximate number of heart beats 256
|
||||||
|
s ECG sampling frequency [Hz] 256
|
||||||
|
S Internal Sampling frequency [Hz] 256
|
||||||
|
a Amplitude of additive uniform noise [mV] 0
|
||||||
|
h Heart rate mean [bpm] 60
|
||||||
|
H Heart rate standard deviation [bpm] 1
|
||||||
|
f Low frequency [Hz] 0.1
|
||||||
|
F High frequency [Hz] 0.25
|
||||||
|
v Low frequency standard deviation [Hz] 0.01
|
||||||
|
V High frequency standard deviation [Hz] 0.01
|
||||||
|
q LF/HF ratio 0.5
|
||||||
|
R Seed 1
|
||||||
|
(Type ? for Help)
|
||||||
|
->
|
||||||
|
</pre>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
At the prompt, you can then type <tt>?</tt> for help, or simply specify each
|
||||||
|
parameter that you want to change by typing the corresponding option letter (in
|
||||||
|
the first column above) followed by a space and the new value, then
|
||||||
|
<enter>. To review the current settings, enter a blank line. After you
|
||||||
|
have modified all the parameters you want, type = followed by <enter> to
|
||||||
|
run the program. You may also specify the parameters in a file called
|
||||||
|
<tt>ecgsyn.opt</tt>, which is automatically read (if it exists) the next time
|
||||||
|
you run the program.
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Any of the options can also be entered directly on the command line, by
|
||||||
|
prefixing the option letter with '<tt>-</tt>', as in:
|
||||||
|
<pre>
|
||||||
|
ecgsyn -h 80 -n 100
|
||||||
|
</pre>
|
||||||
|
(which would create output at a mean heart rate of 80 bpm, lasting for about
|
||||||
|
100 beats).
|
||||||
|
|
||||||
|
<p>
|
||||||
|
The source files <tt>opt.c</tt> and <tt>opt.h</tt> provide the option
|
||||||
|
interpreter for ECGSYN; they were written by James Theiler. For additional
|
||||||
|
information, and for the most recent version of <tt>opt</tt>, see
|
||||||
|
<a href="http://nis-www.lanl.gov/~jt/Software/"
|
||||||
|
target="other"><tt>http://nis-www.lanl.gov/~jt/Software/</tt></a>.
|
||||||
|
|
||||||
|
|
||||||
|
<h2>Interpreting ECGSYN's output</h2>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Unless you have changed the name of the output file with the '<tt>O</tt>'
|
||||||
|
parameter, you will find the synthetic ECG written to a text file called
|
||||||
|
<tt>ecgsyn.dat</tt>. Click <a href="../sample-output/">here</a> for a sample
|
||||||
|
of ECGSYN output and for a description of the format of this file.
|
||||||
|
|
||||||
|
<hr>
|
||||||
|
<!--#include virtual="/footer.shtml"-->
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
10
ecgsyn-1.0.0/C/linux/HEADER.shtml
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
<!--#set var="TITLE" value="ECGSYN for GNU/Linux"-->
|
||||||
|
<!--#include virtual="/head.shtml"-->
|
||||||
|
|
||||||
|
|
||||||
|
<p>
|
||||||
|
The executable <tt>ecgsyn</tt> file in this directory was compiled from
|
||||||
|
these <a href="../src/">ECGSYN sources</a> with gcc 2.96 under Red Hat
|
||||||
|
Linux 7.2. It is known to work under Red Hat Linux 7.1, 7.2, 7.3, 8, and 9,
|
||||||
|
and may also work under other versions of GNU/Linux.
|
||||||
|
|
||||||
BIN
ecgsyn-1.0.0/C/linux/ecgsyn
Normal file
8
ecgsyn-1.0.0/C/linux/index.html
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
<html>
|
||||||
|
<head><title>Index of /static/published-projects/ecgsyn/1.0.0/C/linux/</title></head>
|
||||||
|
<body>
|
||||||
|
<h1>Index of /static/published-projects/ecgsyn/1.0.0/C/linux/</h1><hr><pre><a href="../">../</a>
|
||||||
|
<a href="HEADER.shtml">HEADER.shtml</a> 12-Apr-2019 17:35 371
|
||||||
|
<a href="ecgsyn">ecgsyn</a> 12-Apr-2019 17:35 46457
|
||||||
|
</pre><hr></body>
|
||||||
|
</html>
|
||||||
9
ecgsyn-1.0.0/C/solaris/HEADER.shtml
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
<!--#set var="TITLE" value="ECGSYN for Solaris"-->
|
||||||
|
<!--#include virtual="/head.shtml"-->
|
||||||
|
|
||||||
|
|
||||||
|
<p>
|
||||||
|
The executable <tt>ecgsyn</tt> file in this directory was compiled from
|
||||||
|
these <a href="../src/">ECGSYN sources</a> with gcc 3.1 under SunOS 5.8
|
||||||
|
(Solaris 8).
|
||||||
|
|
||||||
BIN
ecgsyn-1.0.0/C/solaris/ecgsyn
Normal file
8
ecgsyn-1.0.0/C/solaris/index.html
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
<html>
|
||||||
|
<head><title>Index of /static/published-projects/ecgsyn/1.0.0/C/solaris/</title></head>
|
||||||
|
<body>
|
||||||
|
<h1>Index of /static/published-projects/ecgsyn/1.0.0/C/solaris/</h1><hr><pre><a href="../">../</a>
|
||||||
|
<a href="HEADER.shtml">HEADER.shtml</a> 12-Apr-2019 17:35 253
|
||||||
|
<a href="ecgsyn">ecgsyn</a> 12-Apr-2019 17:35 43854
|
||||||
|
</pre><hr></body>
|
||||||
|
</html>
|
||||||
116
ecgsyn-1.0.0/C/src/00README
Normal file
@@ -0,0 +1,116 @@
|
|||||||
|
ECGSYN: A program for generating a realistic synthetic ECG
|
||||||
|
Copyright (C) 2003 by Patrick McSharry & Gari Clifford. All rights reserved.
|
||||||
|
|
||||||
|
|
||||||
|
Compiling ECGSYN
|
||||||
|
================
|
||||||
|
|
||||||
|
This directory contains sources for the C version of ECGSYN. Note, however,
|
||||||
|
that two additional files are required in order to compile ECGSYN. These
|
||||||
|
files (dfour1.c and ran1.c) are those included in Numerical Recipes in C
|
||||||
|
(http://www.nr.com/). Before attempting to compile ECGSYN, obtain these
|
||||||
|
two files from Numerical Recipes in C and place them in this directory.
|
||||||
|
(These files are missing from this directory because they cannot be freely
|
||||||
|
redistributed.)
|
||||||
|
|
||||||
|
If you cannot obtain dfour1.c and ran1.c, several alternatives are available,
|
||||||
|
including ready-to-run executable versions of ECGSYN for GNU/Linux, Solaris,
|
||||||
|
and MS-Windows (see the directory above this one), as well as Matlab/Octave
|
||||||
|
and Java implementations of ECGSYN. See http://www.physionet.org/ for details.
|
||||||
|
|
||||||
|
On most platforms, including GNU/Linux, MacOS X, and Unix, compile ECGSYN
|
||||||
|
by typing
|
||||||
|
make
|
||||||
|
in a terminal window. This will also work under MS-Windows if you have
|
||||||
|
installed the free Cygwin/gcc development toolkit (http://www.cygwin.com/).
|
||||||
|
If you wish to use another compiler under MS-Windows, you are on your own.
|
||||||
|
|
||||||
|
|
||||||
|
Running ECGSYN
|
||||||
|
==============
|
||||||
|
|
||||||
|
The executable version is named 'ecgsyn' (or, under MS-Windows, 'ecgsyn.exe').
|
||||||
|
Once you have this file, move it into any directory in your PATH and run
|
||||||
|
it by typing
|
||||||
|
ecgsyn
|
||||||
|
in a terminal window. You may add options (switches) to the 'ecgsyn' command;
|
||||||
|
the option '$', as in
|
||||||
|
ecgsyn $
|
||||||
|
starts 'ecgsyn' in interactive mode, as shown below:
|
||||||
|
|
||||||
|
>> ecgsyn $
|
||||||
|
ECGSYN: A program for generating a realistic synthetic ECG
|
||||||
|
Copyright (c) 2003 by Patrick McSharry & Gari Clifford. All rights reserved.
|
||||||
|
|
||||||
|
O Name of output data file "ecgsyn.dat"
|
||||||
|
n Approximate number of heart beats 256
|
||||||
|
s ECG sampling frequency [Hz] 256
|
||||||
|
S Internal Sampling frequency [Hz] 256
|
||||||
|
a Amplitude of additive uniform noise [mV] 0
|
||||||
|
h Heart rate mean [bpm] 60
|
||||||
|
H Heart rate standard deviation [bpm] 1
|
||||||
|
f Low frequency [Hz] 0.1
|
||||||
|
F High frequency [Hz] 0.25
|
||||||
|
v Low frequency standard deviation [Hz] 0.01
|
||||||
|
V High frequency standard deviation [Hz] 0.01
|
||||||
|
q LF/HF ratio 0.5
|
||||||
|
R Seed 1
|
||||||
|
(Type ? for Help)
|
||||||
|
->
|
||||||
|
|
||||||
|
At the prompt, you can then type ? for help, or simply specify each parameter
|
||||||
|
above that you want to change by typing the corresponding option letter (in the
|
||||||
|
first column above) followed by a space and the new value, then <enter>. To
|
||||||
|
review the current settings, enter a blank line. After you have modified all
|
||||||
|
the parameters you want, type = followed by <enter> to run the program. You may
|
||||||
|
also specify the parameters in a file called ecgsyn.opt, which is automatically
|
||||||
|
read (if it exists) the next time you run the program.
|
||||||
|
|
||||||
|
Any of the options can also be entered directly on the command line, by
|
||||||
|
prefixing the option letter with '-', as in:
|
||||||
|
ecgsyn -h 80 -n 100
|
||||||
|
(which would create output at a mean heart rate of 80 bpm, lasting for about
|
||||||
|
100 beats).
|
||||||
|
|
||||||
|
The source files opt.c and opt.h provide the option interpreter for ecgsyn;
|
||||||
|
they were written by James Theiler. For additional information, and for the
|
||||||
|
most recent version of 'opt', see http://nis-www.lanl.gov/~jt/Software/.
|
||||||
|
|
||||||
|
|
||||||
|
Interpreting ECGSYN's output
|
||||||
|
============================
|
||||||
|
|
||||||
|
Unless you have changed the name of the output file with the 'O' parameter,
|
||||||
|
you will find the synthetic ECG written to a text file called ecgsyn.dat,
|
||||||
|
which contains three columns:
|
||||||
|
* the time in seconds
|
||||||
|
* the ECG amplitude in millivolts
|
||||||
|
* markers to indicate the locations of the waveform peaks:
|
||||||
|
0 - (no peak)
|
||||||
|
1 - Top of P-wave
|
||||||
|
2 - Q-point
|
||||||
|
3 - Peak of R-wave
|
||||||
|
4 - S-point
|
||||||
|
5 - Peak of T-wave
|
||||||
|
|
||||||
|
To convert the ECG output into PhysioBank (WFDB) format, use a command
|
||||||
|
such as
|
||||||
|
wrsamp -F 256 -o synth -x 200 1 <ecgsyn.dat
|
||||||
|
(assuming you have not changed the default sampling frequency of 256 Hz).
|
||||||
|
This command produces a record named 'synth' (a signal file named 'synth.dat'
|
||||||
|
and a header file named 'synth.hea'), which can be read by other PhysioToolkit
|
||||||
|
applications. 'wrsamp' is part of the WFDB software package; see
|
||||||
|
http://www.physionet.org/physiotools/wfdb.shtml for details.
|
||||||
|
|
||||||
|
|
||||||
|
Further information
|
||||||
|
===================
|
||||||
|
|
||||||
|
The most recent version of this software can always be obtained from
|
||||||
|
http://www.physionet.org/physiotools/ecgsyn/
|
||||||
|
|
||||||
|
See IEEE Transactions on Biomedical Engineering, 50(3),289-294, March 2003.
|
||||||
|
|
||||||
|
Authors: P. McSharry (patrick AT mcsharry DOT net)
|
||||||
|
G. Clifford (gari AT mit DOT edu)
|
||||||
|
|
||||||
19
ecgsyn-1.0.0/C/src/Makefile
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
# file: Makefile
|
||||||
|
|
||||||
|
# 'make' description file for compiling ecgsyn
|
||||||
|
|
||||||
|
CFILES = ecgsyn.c opt.c dfour1.c ran1.c
|
||||||
|
CFLAGS = -O
|
||||||
|
|
||||||
|
ecgsyn: $(CFILES) opt.h
|
||||||
|
$(CC) $(CFLAGS) -o ecgsyn $(CFILES) -lm
|
||||||
|
|
||||||
|
dfour1.c ran1.c:
|
||||||
|
@echo "To compile ecgsyn, first get copies of dfour1.c and ran1.c"
|
||||||
|
@echo "(from Numerical Recipes in C) and place them in this directory."
|
||||||
|
@echo "Then type:"
|
||||||
|
@echo " make ecgsyn"
|
||||||
|
@exit 1
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -f *~ *.o *.obj
|
||||||
664
ecgsyn-1.0.0/C/src/ecgsyn.c
Normal file
@@ -0,0 +1,664 @@
|
|||||||
|
/* 09 Oct 2003 "ecgsyn.c" */
|
||||||
|
/* */
|
||||||
|
/* Copyright (c)2003 by Patrick McSharry & Gari Clifford, All Rights Reserved */
|
||||||
|
/* See IEEE Transactions On Biomedical Engineering, 50(3),289-294, March 2003.*/
|
||||||
|
/* Contact P. McSharry (patrick AT mcsharry DOT net) or */
|
||||||
|
/* G. Clifford (gari AT mit DOT edu) */
|
||||||
|
/* */
|
||||||
|
/* This program is free software; you can redistribute it and/or modify */
|
||||||
|
/* it under the terms of the GNU General Public License as published by */
|
||||||
|
/* the Free Software Foundation; either version 2 of the License, or */
|
||||||
|
/* (at your option) any later version. */
|
||||||
|
/* */
|
||||||
|
/* This program is distributed in the hope that it will be useful, */
|
||||||
|
/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
|
||||||
|
/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
|
||||||
|
/* GNU General Public License for more details. */
|
||||||
|
/* */
|
||||||
|
/* You should have received a copy of the GNU General Public License */
|
||||||
|
/* along with this program; if not, write to the Free Software Foundation */
|
||||||
|
/* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
|
||||||
|
/* */
|
||||||
|
/* ecgsyn.m and its dependents are freely availble from Physionet - */
|
||||||
|
/* http://www.physionet.org/ - please report any bugs to the authors above. */
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <math.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include "opt.h"
|
||||||
|
#define PI (2.0*asin(1.0))
|
||||||
|
#define SWAP(a,b) tempr=(a);(a)=(b);(b)=tempr
|
||||||
|
#define MIN(a,b) (a < b ? a : b)
|
||||||
|
#define MAX(a,b) (a > b ? a : b)
|
||||||
|
#define PI (2.0*asin(1.0))
|
||||||
|
#define OFFSET 1
|
||||||
|
#define ARG1 char*
|
||||||
|
|
||||||
|
#define IA 16807
|
||||||
|
#define IM 2147483647
|
||||||
|
#define AM (1.0/IM)
|
||||||
|
#define IQ 127773
|
||||||
|
#define IR 2836
|
||||||
|
#define NTAB 32
|
||||||
|
#define NDIV (1+(IM-1)/NTAB)
|
||||||
|
#define EPS 1.2e-7
|
||||||
|
#define RNMX (1.0-EPS)
|
||||||
|
|
||||||
|
/*--------------------------------------------------------------------------*/
|
||||||
|
/* DEFINE PARAMETERS AS GLOBAL VARIABLES */
|
||||||
|
/*--------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
char outfile[100]="ecgsyn.dat";/* Output data file */
|
||||||
|
int N = 256; /* Number of heart beats */
|
||||||
|
int sfecg = 256; /* ECG sampling frequency */
|
||||||
|
int sf = 256; /* Internal sampling frequency */
|
||||||
|
double Anoise = 0.0; /* Amplitude of additive uniform noise*/
|
||||||
|
double hrmean = 60.0; /* Heart rate mean */
|
||||||
|
double hrstd = 1.0; /* Heart rate std */
|
||||||
|
double flo = 0.1; /* Low frequency */
|
||||||
|
double fhi = 0.25; /* High frequency */
|
||||||
|
double flostd = 0.01; /* Low frequency std */
|
||||||
|
double fhistd = 0.01; /* High frequency std */
|
||||||
|
double lfhfratio = 0.5; /* LF/HF ratio */
|
||||||
|
|
||||||
|
int Necg = 0; /* Number of ECG outputs */
|
||||||
|
int mstate = 3; /* System state space dimension */
|
||||||
|
double xinitial = 1.0; /* Initial x co-ordinate value */
|
||||||
|
double yinitial = 0.0; /* Initial y co-ordinate value */
|
||||||
|
double zinitial = 0.04; /* Initial z co-ordinate value */
|
||||||
|
int seed = 1; /* Seed */
|
||||||
|
long rseed;
|
||||||
|
double h;
|
||||||
|
double *rr,*rrpc;
|
||||||
|
double *ti,*ai,*bi;
|
||||||
|
|
||||||
|
/* prototypes for externally defined functions */
|
||||||
|
void dfour1(double data[], unsigned long nn, int isign);
|
||||||
|
float ran1(long *idum);
|
||||||
|
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
/* ALLOCATE MEMORY FOR VECTOR */
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
double *mallocVect(long n0, long nx)
|
||||||
|
{
|
||||||
|
double *vect;
|
||||||
|
|
||||||
|
vect=(double *)malloc((size_t) ((nx-n0+1+OFFSET)*sizeof(double)));
|
||||||
|
if (!vect){
|
||||||
|
printf("Memory allocation failure in mallocVect");
|
||||||
|
}
|
||||||
|
return vect-n0+OFFSET;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
/* FREE MEMORY FOR MALLOCVECT */
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
void freeVect(double *vect, long n0, long nx)
|
||||||
|
{
|
||||||
|
free((ARG1) (vect+n0-OFFSET));
|
||||||
|
}
|
||||||
|
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
/* MEAN CALCULATOR */
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
double mean(double *x, int n)
|
||||||
|
/* n-by-1 vector, calculate mean */
|
||||||
|
{
|
||||||
|
int j;
|
||||||
|
double add;
|
||||||
|
|
||||||
|
add = 0.0;
|
||||||
|
for(j=1;j<=n;j++) add += x[j];
|
||||||
|
|
||||||
|
return (add/n);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
/* STANDARD DEVIATION CALCULATOR */
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
double stdev(double *x, int n)
|
||||||
|
/* n-by-1 vector, calculate standard deviation */
|
||||||
|
{
|
||||||
|
int j;
|
||||||
|
double add,mean,diff,total;
|
||||||
|
|
||||||
|
add = 0.0;
|
||||||
|
for(j=1;j<=n;j++) add += x[j];
|
||||||
|
mean = add/n;
|
||||||
|
|
||||||
|
total = 0.0;
|
||||||
|
for(j=1;j<=n;j++)
|
||||||
|
{
|
||||||
|
diff = x[j] - mean;
|
||||||
|
total += diff*diff;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (sqrt(total/(n-1)));
|
||||||
|
}
|
||||||
|
|
||||||
|
/*--------------------------------------------------------------------------*/
|
||||||
|
/* WRITE VECTOR IN A FILE */
|
||||||
|
/*--------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
void vecfile(char filename[], double *x, int n)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
FILE *fp;
|
||||||
|
|
||||||
|
fp = fopen(filename,"w");
|
||||||
|
for(i=1;i<=n;i++) fprintf(fp,"%e\n",x[i]);
|
||||||
|
fclose(fp);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*--------------------------------------------------------------------------*/
|
||||||
|
/* INTERP */
|
||||||
|
/*--------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
void interp(double *y, double *x, int n, int r)
|
||||||
|
{
|
||||||
|
int i,j;
|
||||||
|
double a;
|
||||||
|
|
||||||
|
for(i=1;i<=n-1;i++)
|
||||||
|
{
|
||||||
|
for(j=1;j<=r;j++)
|
||||||
|
{
|
||||||
|
a = (j-1)*1.0/r;
|
||||||
|
y[(i-1)*r+j] = (1.0-a)*x[i] + a*x[i+1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*--------------------------------------------------------------------------*/
|
||||||
|
/* GENERATE RR PROCESS */
|
||||||
|
/*--------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
void rrprocess(double *rr, double flo, double fhi,
|
||||||
|
double flostd, double fhistd, double lfhfratio,
|
||||||
|
double hrmean, double hrstd, double sf, int n)
|
||||||
|
{
|
||||||
|
int i,j;
|
||||||
|
double c1,c2,w1,w2,sig1,sig2,rrmean,rrstd,xstd,ratio;
|
||||||
|
double df,dw1,dw2,*w,*Hw,*Sw,*ph0,*ph,*SwC;
|
||||||
|
|
||||||
|
w = mallocVect(1,n);
|
||||||
|
Hw = mallocVect(1,n);
|
||||||
|
Sw = mallocVect(1,n);
|
||||||
|
ph0 = mallocVect(1,n/2-1);
|
||||||
|
ph = mallocVect(1,n);
|
||||||
|
SwC = mallocVect(1,2*n);
|
||||||
|
|
||||||
|
|
||||||
|
w1 = 2.0*PI*flo;
|
||||||
|
w2 = 2.0*PI*fhi;
|
||||||
|
c1 = 2.0*PI*flostd;
|
||||||
|
c2 = 2.0*PI*fhistd;
|
||||||
|
sig2 = 1.0;
|
||||||
|
sig1 = lfhfratio;
|
||||||
|
rrmean = 60.0/hrmean;
|
||||||
|
rrstd = 60.0*hrstd/(hrmean*hrmean);
|
||||||
|
|
||||||
|
df = sf/n;
|
||||||
|
for(i=1;i<=n;i++) w[i] = (i-1)*2.0*PI*df;
|
||||||
|
for(i=1;i<=n;i++)
|
||||||
|
{
|
||||||
|
dw1 = w[i]-w1;
|
||||||
|
dw2 = w[i]-w2;
|
||||||
|
Hw[i] = sig1*exp(-dw1*dw1/(2.0*c1*c1))/sqrt(2*PI*c1*c1)
|
||||||
|
+ sig2*exp(-dw2*dw2/(2.0*c2*c2))/sqrt(2*PI*c2*c2);
|
||||||
|
}
|
||||||
|
for(i=1;i<=n/2;i++) Sw[i] = (sf/2.0)*sqrt(Hw[i]);
|
||||||
|
for(i=n/2+1;i<=n;i++) Sw[i] = (sf/2.0)*sqrt(Hw[n-i+1]);
|
||||||
|
|
||||||
|
|
||||||
|
/* randomise the phases */
|
||||||
|
for(i=1;i<=n/2-1;i++) ph0[i] = 2.0*PI*ran1(&rseed);
|
||||||
|
ph[1] = 0.0;
|
||||||
|
for(i=1;i<=n/2-1;i++) ph[i+1] = ph0[i];
|
||||||
|
ph[n/2+1] = 0.0;
|
||||||
|
for(i=1;i<=n/2-1;i++) ph[n-i+1] = - ph0[i];
|
||||||
|
|
||||||
|
|
||||||
|
/* make complex spectrum */
|
||||||
|
for(i=1;i<=n;i++) SwC[2*i-1] = Sw[i]*cos(ph[i]);
|
||||||
|
for(i=1;i<=n;i++) SwC[2*i] = Sw[i]*sin(ph[i]);
|
||||||
|
|
||||||
|
/* calculate inverse fft */
|
||||||
|
dfour1(SwC,n,-1);
|
||||||
|
|
||||||
|
/* extract real part */
|
||||||
|
for(i=1;i<=n;i++) rr[i] = (1.0/n)*SwC[2*i-1];
|
||||||
|
|
||||||
|
xstd = stdev(rr,n);
|
||||||
|
ratio = rrstd/xstd;
|
||||||
|
|
||||||
|
for(i=1;i<=n;i++) rr[i] *= ratio;
|
||||||
|
for(i=1;i<=n;i++) rr[i] += rrmean;
|
||||||
|
|
||||||
|
freeVect(w,1,n);
|
||||||
|
freeVect(Hw,1,n);
|
||||||
|
freeVect(Sw,1,n);
|
||||||
|
freeVect(ph0,1,n/2-1);
|
||||||
|
freeVect(ph,1,n);
|
||||||
|
freeVect(SwC,1,2*n);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*--------------------------------------------------------------------------*/
|
||||||
|
/* THE ANGULAR FREQUENCY */
|
||||||
|
/*--------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
double angfreq(double t)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
i = 1 + (int)floor(t/h);
|
||||||
|
|
||||||
|
return 2.0*PI/rrpc[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
/*--------------------------------------------------------------------------*/
|
||||||
|
/* THE EXACT NONLINEAR DERIVATIVES */
|
||||||
|
/*--------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
void derivspqrst(double t0,double x[],double dxdt[])
|
||||||
|
{
|
||||||
|
int i,k;
|
||||||
|
double a0,w0,r0,x0,y0,z0;
|
||||||
|
double t,dt,dt2,*xi,*yi,zbase;
|
||||||
|
|
||||||
|
k = 5;
|
||||||
|
xi = mallocVect(1,k);
|
||||||
|
yi = mallocVect(1,k);
|
||||||
|
|
||||||
|
w0 = angfreq(t0);
|
||||||
|
r0 = 1.0; x0 = 0.0; y0 = 0.0; z0 = 0.0;
|
||||||
|
a0 = 1.0 - sqrt((x[1]-x0)*(x[1]-x0) + (x[2]-y0)*(x[2]-y0))/r0;
|
||||||
|
|
||||||
|
for(i=1;i<=k;i++) xi[i] = cos(ti[i]);
|
||||||
|
for(i=1;i<=k;i++) yi[i] = sin(ti[i]);
|
||||||
|
|
||||||
|
zbase = 0.005*sin(2.0*PI*fhi*t0);
|
||||||
|
|
||||||
|
t = atan2(x[2],x[1]);
|
||||||
|
dxdt[1] = a0*(x[1] - x0) - w0*(x[2] - y0);
|
||||||
|
dxdt[2] = a0*(x[2] - y0) + w0*(x[1] - x0);
|
||||||
|
dxdt[3] = 0.0;
|
||||||
|
for(i=1;i<=k;i++)
|
||||||
|
{
|
||||||
|
dt = fmod(t-ti[i],2.0*PI);
|
||||||
|
dt2 = dt*dt;
|
||||||
|
dxdt[3] += -ai[i]*dt*exp(-0.5*dt2/(bi[i]*bi[i]));
|
||||||
|
}
|
||||||
|
dxdt[3] += -1.0*(x[3] - zbase);
|
||||||
|
|
||||||
|
freeVect(xi,1,k);
|
||||||
|
freeVect(yi,1,k);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*--------------------------------------------------------------------------*/
|
||||||
|
/* RUNGA-KUTTA FOURTH ORDER INTEGRATION */
|
||||||
|
/*--------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
void drk4(double y[], int n, double x, double h, double yout[],
|
||||||
|
void (*derivs)(double, double [], double []))
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
double xh,hh,h6,*dydx,*dym,*dyt,*yt;
|
||||||
|
|
||||||
|
dydx=mallocVect(1,n);
|
||||||
|
dym=mallocVect(1,n);
|
||||||
|
dyt=mallocVect(1,n);
|
||||||
|
yt=mallocVect(1,n);
|
||||||
|
|
||||||
|
hh=h*0.5;
|
||||||
|
h6=h/6.0;
|
||||||
|
xh=x+hh;
|
||||||
|
(*derivs)(x,y,dydx);
|
||||||
|
for (i=1;i<=n;i++) yt[i]=y[i]+hh*dydx[i];
|
||||||
|
(*derivs)(xh,yt,dyt);
|
||||||
|
for (i=1;i<=n;i++) yt[i]=y[i]+hh*dyt[i];
|
||||||
|
(*derivs)(xh,yt,dym);
|
||||||
|
for (i=1;i<=n;i++) {
|
||||||
|
yt[i]=y[i]+h*dym[i];
|
||||||
|
dym[i] += dyt[i];
|
||||||
|
}
|
||||||
|
(*derivs)(x+h,yt,dyt);
|
||||||
|
for (i=1;i<=n;i++)
|
||||||
|
yout[i]=y[i]+h6*(dydx[i]+dyt[i]+2.0*dym[i]);
|
||||||
|
|
||||||
|
freeVect(dydx,1,n);
|
||||||
|
freeVect(dym,1,n);
|
||||||
|
freeVect(dyt,1,n);
|
||||||
|
freeVect(yt,1,n);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*--------------------------------------------------------------------------*/
|
||||||
|
/* DETECT PEAKS */
|
||||||
|
/*--------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
double detectpeaks(double *ipeak, double *x, double *y, double *z, int n)
|
||||||
|
{
|
||||||
|
int i,j,j1,j2,jmin,jmax,d;
|
||||||
|
double thetap1,thetap2,thetap3,thetap4,thetap5;
|
||||||
|
double theta1,theta2,d1,d2,zmin,zmax;
|
||||||
|
|
||||||
|
/* use globally defined angles for PQRST */
|
||||||
|
thetap1 = ti[1];
|
||||||
|
thetap2 = ti[2];
|
||||||
|
thetap3 = ti[3];
|
||||||
|
thetap4 = ti[4];
|
||||||
|
thetap5 = ti[5];
|
||||||
|
|
||||||
|
for(i=1;i<=n;i++) ipeak[i] = 0.0;
|
||||||
|
theta1 = atan2(y[1],x[1]);
|
||||||
|
for(i=1;i<n;i++)
|
||||||
|
{
|
||||||
|
theta2 = atan2(y[i+1],x[i+1]);
|
||||||
|
if( (theta1 <= thetap1) && (thetap1 <= theta2) )
|
||||||
|
{
|
||||||
|
d1 = thetap1 - theta1;
|
||||||
|
d2 = theta2 - thetap1;
|
||||||
|
if(d1 < d2) ipeak[i] = 1.0;
|
||||||
|
else ipeak[i+1] = 1.0;
|
||||||
|
}
|
||||||
|
else if( (theta1 <= thetap2) && (thetap2 <= theta2) )
|
||||||
|
{
|
||||||
|
d1 = thetap2 - theta1;
|
||||||
|
d2 = theta2 - thetap2;
|
||||||
|
if(d1 < d2) ipeak[i] = 2.0;
|
||||||
|
else ipeak[i+1] = 2.0;
|
||||||
|
}
|
||||||
|
else if( (theta1 <= thetap3) && (thetap3 <= theta2) )
|
||||||
|
{
|
||||||
|
d1 = thetap3 - theta1;
|
||||||
|
d2 = theta2 - thetap3;
|
||||||
|
if(d1 < d2) ipeak[i] = 3.0;
|
||||||
|
else ipeak[i+1] = 3.0;
|
||||||
|
}
|
||||||
|
else if( (theta1 <= thetap4) && (thetap4 <= theta2) )
|
||||||
|
{
|
||||||
|
d1 = thetap4 - theta1;
|
||||||
|
d2 = theta2 - thetap4;
|
||||||
|
if(d1 < d2) ipeak[i] = 4.0;
|
||||||
|
else ipeak[i+1] = 4.0;
|
||||||
|
}
|
||||||
|
else if( (theta1 <= thetap5) && (thetap5 <= theta2) )
|
||||||
|
{
|
||||||
|
d1 = thetap5 - theta1;
|
||||||
|
d2 = theta2 - thetap5;
|
||||||
|
if(d1 < d2) ipeak[i] = 5.0;
|
||||||
|
else ipeak[i+1] = 5.0;
|
||||||
|
}
|
||||||
|
theta1 = theta2;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* correct the peaks */
|
||||||
|
d = (int)ceil(sfecg/64);
|
||||||
|
for(i=1;i<=n;i++)
|
||||||
|
{
|
||||||
|
if( ipeak[i]==1 || ipeak[i]==3 || ipeak[i]==5 )
|
||||||
|
{
|
||||||
|
j1 = MAX(1,i-d);
|
||||||
|
j2 = MIN(n,i+d);
|
||||||
|
jmax = j1;
|
||||||
|
zmax = z[j1];
|
||||||
|
for(j=j1+1;j<=j2;j++)
|
||||||
|
{
|
||||||
|
if(z[j] > zmax)
|
||||||
|
{
|
||||||
|
jmax = j;
|
||||||
|
zmax = z[j];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(jmax != i)
|
||||||
|
{
|
||||||
|
ipeak[jmax] = ipeak[i];
|
||||||
|
ipeak[i] = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if( ipeak[i]==2 || ipeak[i]==4 )
|
||||||
|
{
|
||||||
|
j1 = MAX(1,i-d);
|
||||||
|
j2 = MIN(n,i+d);
|
||||||
|
jmin = j1;
|
||||||
|
zmin = z[j1];
|
||||||
|
for(j=j1+1;j<=j2;j++)
|
||||||
|
{
|
||||||
|
if(z[j] < zmin)
|
||||||
|
{
|
||||||
|
jmin = j;
|
||||||
|
zmin = z[j];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(jmin != i)
|
||||||
|
{
|
||||||
|
ipeak[jmin] = ipeak[i];
|
||||||
|
ipeak[i] = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/*--------------------------------------------------------------------------*/
|
||||||
|
/* MAIN PROGRAM */
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
main(argc,argv)
|
||||||
|
int argc;
|
||||||
|
char **argv;
|
||||||
|
{
|
||||||
|
|
||||||
|
/* First step is to register the options */
|
||||||
|
|
||||||
|
optregister(outfile,CSTRING,'O',"Name of output data file");
|
||||||
|
optregister(N,INT,'n',"Approximate number of heart beats");
|
||||||
|
optregister(sfecg,INT,'s',"ECG sampling frequency [Hz]");
|
||||||
|
optregister(sf,INT,'S',"Internal Sampling frequency [Hz]");
|
||||||
|
optregister(Anoise,DOUBLE,'a',"Amplitude of additive uniform noise [mV]");
|
||||||
|
optregister(hrmean,DOUBLE,'h',"Heart rate mean [bpm]");
|
||||||
|
optregister(hrstd,DOUBLE,'H',"Heart rate standard deviation [bpm]");
|
||||||
|
optregister(flo,DOUBLE,'f',"Low frequency [Hz]");
|
||||||
|
optregister(fhi,DOUBLE,'F',"High frequency [Hz]");
|
||||||
|
optregister(flostd,DOUBLE,'v',"Low frequency standard deviation [Hz]");
|
||||||
|
optregister(fhistd,DOUBLE,'V',"High frequency standard deviation [Hz]");
|
||||||
|
optregister(lfhfratio,DOUBLE,'q',"LF/HF ratio");
|
||||||
|
optregister(seed,INT,'R',"Seed");
|
||||||
|
opt_title_set("ECGSYN: A program for generating a realistic synthetic ECG\n"
|
||||||
|
"Copyright (c) 2003 by Patrick McSharry & Gari Clifford. All rights reserved.\n");
|
||||||
|
|
||||||
|
getopts(argc,argv);
|
||||||
|
|
||||||
|
dorun();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*--------------------------------------------------------------------------*/
|
||||||
|
/* DORUN PART OF PROGRAM */
|
||||||
|
/*--------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
int dorun()
|
||||||
|
{
|
||||||
|
int i,j,k,q,Nrr,Nt,Nts;
|
||||||
|
double *x,tstep,tecg,rrmean,qd,hrfact,hrfact2;
|
||||||
|
double *xt,*yt,*zt,*xts,*yts,*zts;
|
||||||
|
double timev,*ipeak,zmin,zmax,zrange;
|
||||||
|
FILE *fp;
|
||||||
|
void (*derivs)(double, double [], double []);
|
||||||
|
|
||||||
|
/* perform some checks on input values */
|
||||||
|
q = (int)rint(sf/sfecg);
|
||||||
|
qd = (double)sf/(double)sfecg;
|
||||||
|
if(q != qd) {
|
||||||
|
printf("Internal sampling frequency must be an integer multiple of the \n");
|
||||||
|
printf("ECG sampling frequency!\n");
|
||||||
|
printf("Your current choices are:\n");
|
||||||
|
printf("ECG sampling frequency: %d Hertz\n",sfecg);
|
||||||
|
printf("Internal sampling frequency: %d Hertz\n",sf);
|
||||||
|
exit(1);}
|
||||||
|
|
||||||
|
|
||||||
|
/* declare and initialise the state vector */
|
||||||
|
x=mallocVect(1,mstate);
|
||||||
|
x[1] = xinitial;
|
||||||
|
x[2] = yinitial;
|
||||||
|
x[3] = zinitial;
|
||||||
|
|
||||||
|
/* declare and define the ECG morphology vectors (PQRST extrema parameters) */
|
||||||
|
ti=mallocVect(1,5);
|
||||||
|
ai=mallocVect(1,5);
|
||||||
|
bi=mallocVect(1,5);
|
||||||
|
/* P Q R S T */
|
||||||
|
ti[1]=-60.0; ti[2]=-15.0; ti[3]=0.0; ti[4]=15.0; ti[5]=90.0;
|
||||||
|
ai[1]=1.2; ai[2]=-5.0; ai[3]=30.0; ai[4]=-7.5; ai[5]=0.75;
|
||||||
|
bi[1]=0.25; bi[2]=0.1; bi[3]=0.1; bi[4]=0.1; bi[5]=0.4;
|
||||||
|
|
||||||
|
/* convert angles from degrees to radians */
|
||||||
|
for(i=1;i<=5;i++) ti[i] *= PI/180.0;
|
||||||
|
|
||||||
|
/* adjust extrema parameters for mean heart rate */
|
||||||
|
hrfact = sqrt(hrmean/60.0);
|
||||||
|
hrfact2 = sqrt(hrfact);
|
||||||
|
for(i=1;i<=5;i++) bi[i] *= hrfact;
|
||||||
|
ti[1]*=hrfact2; ti[2]*=hrfact; ti[3]*=1.0; ti[4]*=hrfact; ti[5]*=1.0;
|
||||||
|
|
||||||
|
|
||||||
|
/* calculate time scales */
|
||||||
|
h = 1.0/sf;
|
||||||
|
tstep = 1.0/sfecg;
|
||||||
|
|
||||||
|
printf("ECGSYN: A program for generating a realistic synthetic ECG\n"
|
||||||
|
"Copyright (c) 2003 by Patrick McSharry & Gari Clifford. All rights reserved.\n"
|
||||||
|
"See IEEE Transactions On Biomedical Engineering, 50(3), 289-294, March 2003.\n"
|
||||||
|
"Contact P. McSharry (patrick@mcsharry.net) or G. Clifford (gari@mit.edu)\n");
|
||||||
|
|
||||||
|
printf("Approximate number of heart beats: %d\n",N);
|
||||||
|
printf("ECG sampling frequency: %d Hertz\n",sfecg);
|
||||||
|
printf("Internal sampling frequency: %d Hertz\n",sf);
|
||||||
|
printf("Amplitude of additive uniformly distributed noise: %g mV\n",Anoise);
|
||||||
|
printf("Heart rate mean: %g beats per minute\n",hrmean);
|
||||||
|
printf("Heart rate std: %g beats per minute\n",hrstd);
|
||||||
|
printf("Low frequency: %g Hertz\n",flo);
|
||||||
|
printf("High frequency std: %g Hertz\n",fhistd);
|
||||||
|
printf("Low frequency std: %g Hertz\n",flostd);
|
||||||
|
printf("High frequency: %g Hertz\n",fhi);
|
||||||
|
printf("LF/HF ratio: %g\n",lfhfratio);
|
||||||
|
|
||||||
|
/* initialise seed */
|
||||||
|
rseed = -seed;
|
||||||
|
|
||||||
|
|
||||||
|
/* select the derivs to use */
|
||||||
|
derivs = derivspqrst;
|
||||||
|
|
||||||
|
/* calculate length of RR time series */
|
||||||
|
rrmean = (60/hrmean);
|
||||||
|
Nrr = (int)pow(2.0, ceil(log10(N*rrmean*sf)/log10(2.0)));
|
||||||
|
printf("Using %d = 2^%d samples for calculating RR intervals\n",
|
||||||
|
Nrr,(int)(log10(1.0*Nrr)/log10(2.0)));
|
||||||
|
|
||||||
|
|
||||||
|
/* create rrprocess with required spectrum */
|
||||||
|
rr = mallocVect(1,Nrr);
|
||||||
|
rrprocess(rr, flo, fhi, flostd, fhistd, lfhfratio, hrmean, hrstd, sf, Nrr);
|
||||||
|
vecfile("rr.dat",rr,Nrr);
|
||||||
|
|
||||||
|
/* create piecewise constant rr */
|
||||||
|
rrpc = mallocVect(1,2*Nrr);
|
||||||
|
tecg = 0.0;
|
||||||
|
i = 1;
|
||||||
|
j = 1;
|
||||||
|
while(i <= Nrr)
|
||||||
|
{
|
||||||
|
tecg += rr[j];
|
||||||
|
j = (int)rint(tecg/h);
|
||||||
|
for(k=i;k<=j;k++) rrpc[k] = rr[i];
|
||||||
|
i = j+1;
|
||||||
|
}
|
||||||
|
Nt = j;
|
||||||
|
vecfile("rrpc.dat",rrpc,Nt);
|
||||||
|
|
||||||
|
printf("Printing ECG signal to file: %s\n",outfile);
|
||||||
|
|
||||||
|
/* integrate dynamical system using fourth order Runge-Kutta*/
|
||||||
|
xt = mallocVect(1,Nt);
|
||||||
|
yt = mallocVect(1,Nt);
|
||||||
|
zt = mallocVect(1,Nt);
|
||||||
|
|
||||||
|
timev = 0.0;
|
||||||
|
for(i=1;i<=Nt;i++)
|
||||||
|
{
|
||||||
|
xt[i] = x[1];
|
||||||
|
yt[i] = x[2];
|
||||||
|
zt[i] = x[3];
|
||||||
|
drk4(x, mstate, timev, h, x, derivs);
|
||||||
|
timev += h;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* downsample to ECG sampling frequency */
|
||||||
|
xts = mallocVect(1,Nt);
|
||||||
|
yts = mallocVect(1,Nt);
|
||||||
|
zts = mallocVect(1,Nt);
|
||||||
|
|
||||||
|
j=0;
|
||||||
|
for(i=1;i<=Nt;i+=q)
|
||||||
|
{
|
||||||
|
j++;
|
||||||
|
xts[j] = xt[i];
|
||||||
|
yts[j] = yt[i];
|
||||||
|
zts[j] = zt[i];
|
||||||
|
}
|
||||||
|
Nts = j;
|
||||||
|
|
||||||
|
|
||||||
|
/* do peak detection using angle */
|
||||||
|
ipeak = mallocVect(1,Nts);
|
||||||
|
detectpeaks(ipeak, xts, yts, zts, Nts);
|
||||||
|
|
||||||
|
/* scale signal to lie between -0.4 and 1.2 mV */
|
||||||
|
zmin = zts[1];
|
||||||
|
zmax = zts[1];
|
||||||
|
for(i=2;i<=Nts;i++)
|
||||||
|
{
|
||||||
|
if(zts[i] < zmin) zmin = zts[i];
|
||||||
|
else if(zts[i] > zmax) zmax = zts[i];
|
||||||
|
}
|
||||||
|
zrange = zmax-zmin;
|
||||||
|
for(i=1;i<=Nts;i++) zts[i] = (zts[i]-zmin)*(1.6)/zrange - 0.4;
|
||||||
|
|
||||||
|
/* include additive uniformly distributed measurement noise */
|
||||||
|
for(i=1;i<=Nts;i++) zts[i] += Anoise*(2.0*ran1(&rseed) - 1.0);
|
||||||
|
|
||||||
|
/* output ECG file */
|
||||||
|
fp = fopen(outfile,"w");
|
||||||
|
for(i=1;i<=Nts;i++) fprintf(fp,"%f %f %d\n",(i-1)*tstep,zts[i],(int)ipeak[i]);
|
||||||
|
fclose(fp);
|
||||||
|
|
||||||
|
|
||||||
|
printf("Finished ECG output\n");
|
||||||
|
|
||||||
|
freeVect(x,1,mstate);
|
||||||
|
freeVect(rr,1,Nrr);
|
||||||
|
freeVect(rrpc,1,2*Nrr);
|
||||||
|
freeVect(ti,1,5);
|
||||||
|
freeVect(ai,1,5);
|
||||||
|
freeVect(bi,1,5);
|
||||||
|
freeVect(xt,1,Nt);
|
||||||
|
freeVect(yt,1,Nt);
|
||||||
|
freeVect(zt,1,Nt);
|
||||||
|
freeVect(xts,1,Nt);
|
||||||
|
freeVect(yts,1,Nt);
|
||||||
|
freeVect(zts,1,Nt);
|
||||||
|
freeVect(ipeak,1,Nts);
|
||||||
|
|
||||||
|
/* END OF DORUN */
|
||||||
|
}
|
||||||
|
|
||||||
11
ecgsyn-1.0.0/C/src/index.html
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
<html>
|
||||||
|
<head><title>Index of /static/published-projects/ecgsyn/1.0.0/C/src/</title></head>
|
||||||
|
<body>
|
||||||
|
<h1>Index of /static/published-projects/ecgsyn/1.0.0/C/src/</h1><hr><pre><a href="../">../</a>
|
||||||
|
<a href="00README">00README</a> 12-Apr-2019 17:35 4672
|
||||||
|
<a href="Makefile">Makefile</a> 12-Apr-2019 17:35 426
|
||||||
|
<a href="ecgsyn.c">ecgsyn.c</a> 12-Apr-2019 17:35 20586
|
||||||
|
<a href="opt.c">opt.c</a> 12-Apr-2019 17:35 56582
|
||||||
|
<a href="opt.h">opt.h</a> 12-Apr-2019 17:35 5237
|
||||||
|
</pre><hr></body>
|
||||||
|
</html>
|
||||||
2581
ecgsyn-1.0.0/C/src/opt.c
Normal file
159
ecgsyn-1.0.0/C/src/opt.h
Normal file
@@ -0,0 +1,159 @@
|
|||||||
|
/*
|
||||||
|
opt.h version 3.17 - User Include File for options package.
|
||||||
|
|
||||||
|
OPT is a subroutine library which facilitates the convenient
|
||||||
|
input of parameters to a C or C++ program. Parameters are parsed
|
||||||
|
from a command line, with further facilities for reading options
|
||||||
|
from files, from environment strings, or from an interactive
|
||||||
|
environment. The aim of the opt package is to permit programs to
|
||||||
|
be both user- and programmer- friendly. The package attempts to
|
||||||
|
on the one hand provide a direct and relatively full-featured
|
||||||
|
input interface to the ultimate user of the program, and at the
|
||||||
|
same time impose a minimal amount of work on the programmer to
|
||||||
|
"attach" the package to his or her software. A texinfo file is
|
||||||
|
part of the distribution; or you can view the html documentation at:
|
||||||
|
http://nis-www.lanl.gov/~jt/Software/opt/opt_toc.html
|
||||||
|
|
||||||
|
Download the lastest version of the source code from:
|
||||||
|
http://nis-www.lanl.gov/~jt/Software/
|
||||||
|
|
||||||
|
opt is available to the public under the GNU General Public License:
|
||||||
|
http://www.gnu.org/copyleft/gpl.html
|
||||||
|
|
||||||
|
This SOFTWARE has been authored by an employee of the University of
|
||||||
|
California, operator of the Los Alamos National Laboratory under
|
||||||
|
Contract No. W-7405-ENG-36 with the U.S. Department of Energy. The
|
||||||
|
U.S. Government has rights to use, reproduce, and distribute this
|
||||||
|
SOFTWARE. The public may copy, distribute, prepare derivative works
|
||||||
|
and publicly display this SOFTWARE without charge, provided that this
|
||||||
|
Notice and any statement of authorship are reproduced on all
|
||||||
|
copies. Neither the Government nor the University makes any warranty,
|
||||||
|
express or implied, or assumes any liability or responsibility for the
|
||||||
|
use of this SOFTWARE. If SOFTWARE is modified to produce derivative
|
||||||
|
works, such modified SOFTWARE should be clearly marked, so as not to
|
||||||
|
confuse it with the version available from LANL.
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef _OPT_H
|
||||||
|
#define _OPT_H /* Signal that this header file has been included */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* These are delimiter characters
|
||||||
|
*/
|
||||||
|
#define DELIM '-' /* option delimiter character */
|
||||||
|
#define ALTDELIM '/' /* alternate delimiter character */
|
||||||
|
#define OPTFROMFILE '@' /* denotes options are in a file */
|
||||||
|
#define OPTTOFILE '%' /* says to put options in a file */
|
||||||
|
#define DOCUMENT '-' /* write document to file */
|
||||||
|
#define INTERACT '$' /* Flags interactive menu */
|
||||||
|
#define HELPCH '?' /* Help character */
|
||||||
|
/*
|
||||||
|
* These are not available on command line
|
||||||
|
* But may be invoked from a file
|
||||||
|
*/
|
||||||
|
#define IGNOREEOL ';' /* Ignore until the end of line */
|
||||||
|
#define RUN '=' /* Says to just run to completion */
|
||||||
|
#define QUITCH '.' /* Quit character */
|
||||||
|
/*
|
||||||
|
* These are not available on command line or from a file
|
||||||
|
* But may be invoked from the menu
|
||||||
|
*/
|
||||||
|
#define BANG '!' /* Shell escape character */
|
||||||
|
#define ADDITIONAL_OPTS '+' /* Additional options */
|
||||||
|
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
INT, UNSINT, LONG, CHAR,
|
||||||
|
INTLEVEL,
|
||||||
|
FLOAT, DOUBLE,
|
||||||
|
FLAG, NEGFLAG, ABSFLAG, ABSNEGFLAG,
|
||||||
|
VSTRING, CSTRING, UNDELIMV, UNDELIMC
|
||||||
|
}
|
||||||
|
opt_TYPE;
|
||||||
|
|
||||||
|
|
||||||
|
typedef int (*PFI)();
|
||||||
|
|
||||||
|
#define OPT_EXT ".opt" /* standard options file extension */
|
||||||
|
|
||||||
|
#ifndef TRUE
|
||||||
|
#define TRUE 1
|
||||||
|
#define FALSE 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef ARGCHECK
|
||||||
|
#ifdef __TURBOC__
|
||||||
|
#define ARGCHECK
|
||||||
|
#endif /* __TURBOC__ */
|
||||||
|
#ifdef __cplusplus
|
||||||
|
#define ARGCHECK
|
||||||
|
#endif /* __cplusplus */
|
||||||
|
#endif /* ARGCHECK */
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef ARGCHECK
|
||||||
|
extern int opt_register(char *,opt_TYPE,char,char *);
|
||||||
|
extern void opt_usage_set(char *);
|
||||||
|
extern void opt_title_set(char *);
|
||||||
|
extern void opt_verify_set(PFI);
|
||||||
|
extern void opt_doc_set(PFI);
|
||||||
|
extern void opt_quit_set(PFI);
|
||||||
|
extern void opt_run_set(PFI);
|
||||||
|
extern void opt_help_setf(PFI);
|
||||||
|
extern void opt_help_set(char,char *);
|
||||||
|
extern void opt_ufilter_set(PFI);
|
||||||
|
extern void opt_dfilter_set(PFI);
|
||||||
|
extern void opt_env_set(char *);
|
||||||
|
extern void opt_default_set(char *);
|
||||||
|
#if DISABLE_VARARGS
|
||||||
|
extern void opt_errmess(char *);
|
||||||
|
extern void opt_message(char *);
|
||||||
|
extern void opt_warning(char *);
|
||||||
|
extern void opt_fatal(char *);
|
||||||
|
#else
|
||||||
|
extern void opt_errmess();
|
||||||
|
extern void opt_message();
|
||||||
|
extern void opt_warning();
|
||||||
|
extern void opt_fatal();
|
||||||
|
#endif /* DISABLE_VARARGS */
|
||||||
|
extern void opt_abort_run(void);
|
||||||
|
extern int opt_begin_run(PFI);
|
||||||
|
extern int getopts(int,char **);
|
||||||
|
#else
|
||||||
|
extern int opt_register();
|
||||||
|
extern void opt_usage_set();
|
||||||
|
extern void opt_title_set();
|
||||||
|
extern void opt_verify_set();
|
||||||
|
extern void opt_doc_set();
|
||||||
|
extern void opt_quit_set();
|
||||||
|
extern void opt_run_set();
|
||||||
|
extern void opt_help_setf();
|
||||||
|
extern void opt_help_set();
|
||||||
|
extern void opt_help_set();
|
||||||
|
extern void opt_ufilter_set();
|
||||||
|
extern void opt_dfilter_set();
|
||||||
|
extern void opt_env_set();
|
||||||
|
extern void opt_default_set();
|
||||||
|
|
||||||
|
extern void opt_errmess();
|
||||||
|
extern void opt_message();
|
||||||
|
extern void opt_warning();
|
||||||
|
extern void opt_fatal();
|
||||||
|
|
||||||
|
extern void opt_abort_run();
|
||||||
|
extern int opt_begin_run();
|
||||||
|
extern int getopts();
|
||||||
|
|
||||||
|
#endif /* ARGCHECK */
|
||||||
|
|
||||||
|
|
||||||
|
/*********************************
|
||||||
|
* Macro's for registering options
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define optregister(val,typ,c,str) opt_register((char *)&val,typ,c,str)
|
||||||
|
#define optrunset(r) {int r(); opt_run_set( r );}
|
||||||
|
|
||||||
|
#endif /* _OPT_H */
|
||||||
14
ecgsyn-1.0.0/C/windows/HEADER.shtml
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
<!--#set var="TITLE" value="ECGSYN for Windows"-->
|
||||||
|
<!--#include virtual="/head.shtml"-->
|
||||||
|
|
||||||
|
<p>
|
||||||
|
There are two versions of the <code>ecgsyn.exe</code> executable in this directory. Using the
|
||||||
|
<a href="../src/">ECGSYN source files</a>, the first version was compiled with <code>Cygwin64 2.6.0 gcc 5.4.0</code>,
|
||||||
|
and the second version with <code>MinGW-w64 gcc 4.9.2</code>, both under Windows 10.</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
To run the Cygwin executable, you will need to have the Cygwin DLLs installed in your PATH in
|
||||||
|
order to run this program successfully. The simplest and most reliable
|
||||||
|
way to do this is to install the <a href="http://www.cygwin.com/" target="other">Cygwin development toolkit</a>.
|
||||||
|
To run the MinGW executable, you should install <a href="https://sourceforge.net/projects/mingw-w64/" target="other">MinGW-w64</a>.
|
||||||
|
</p>
|
||||||
BIN
ecgsyn-1.0.0/C/windows/cygwin_ecgsyn.zip
Normal file
10
ecgsyn-1.0.0/C/windows/index.html
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
<html>
|
||||||
|
<head><title>Index of /static/published-projects/ecgsyn/1.0.0/C/windows/</title></head>
|
||||||
|
<body>
|
||||||
|
<h1>Index of /static/published-projects/ecgsyn/1.0.0/C/windows/</h1><hr><pre><a href="../">../</a>
|
||||||
|
<a href="HEADER.shtml">HEADER.shtml</a> 12-Apr-2019 17:35 821
|
||||||
|
<a href="HEADER.shtml~">HEADER.shtml~</a> 12-Apr-2019 17:35 647
|
||||||
|
<a href="cygwin_ecgsyn.zip">cygwin_ecgsyn.zip</a> 12-Apr-2019 17:35 35146
|
||||||
|
<a href="mingw_ecgsyn.zip">mingw_ecgsyn.zip</a> 12-Apr-2019 17:35 34966
|
||||||
|
</pre><hr></body>
|
||||||
|
</html>
|
||||||
BIN
ecgsyn-1.0.0/C/windows/mingw_ecgsyn.zip
Normal file
BIN
ecgsyn-1.0.0/Java/FormatNumber.class
Normal file
21
ecgsyn-1.0.0/Java/HEADER.shtml
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
<!--#set var="TITLE" value="ECGSYN implemented in Java"-->
|
||||||
|
<!--#include virtual="/head.shtml"-->
|
||||||
|
|
||||||
|
|
||||||
|
<p>
|
||||||
|
This directory contains Mauricio Villarroel's implementation of
|
||||||
|
<a href="../">ECGSYN</a> as a Java applet.
|
||||||
|
|
||||||
|
<p>
|
||||||
|
To run the applet in your web browser, click
|
||||||
|
<a href="ecgsyn-java.html">here</a>.
|
||||||
|
|
||||||
|
<p>
|
||||||
|
The individual Java files can be downloaded by following the links
|
||||||
|
below, or you may download all of them, together with the C and Matlab
|
||||||
|
implementations of ECGSYN, as a single gzip-compressed tar archive, <a
|
||||||
|
href="../ecgsyn.tar.gz"><tt>ecgsyn.tar.gz</tt></a>. (See <a
|
||||||
|
href="/faq.shtml#tar-gz">How can I unpack a .tar.gz archive?</a> if
|
||||||
|
you need help doing this.)
|
||||||
|
|
||||||
|
<hr>
|
||||||
1200
ecgsyn-1.0.0/Java/ecgApplet.form
Normal file
64
ecgsyn-1.0.0/Java/ecgApplet.html
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
<HTML>
|
||||||
|
<HEAD>
|
||||||
|
<TITLE>ECGSYN Java Application</TITLE>
|
||||||
|
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"></HEAD>
|
||||||
|
<BODY bgcolor="#003366" text="#FFFFCC" link="#FFFF33" vlink="#FFCC00" leftmargin="0" topmargin="0" marginwidth="0" marginheight="0">
|
||||||
|
<table width="925" border="0" align="center" cellpadding="0" cellspacing="5">
|
||||||
|
<tr>
|
||||||
|
<td height="50" colspan="2">
|
||||||
|
<H3>
|
||||||
|
<HR WIDTH="100%">
|
||||||
|
</H3>
|
||||||
|
<H3 align="center"><font color="#FF9900">JAVA Application for <br>
|
||||||
|
ECGSYN: A Dynamical Model for Generating
|
||||||
|
Synthetic Electrocardiogram Signals
|
||||||
|
</font></H3>
|
||||||
|
<H3>
|
||||||
|
<HR WIDTH="100%">
|
||||||
|
</H3>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td width="300" align="left" valign="top"><p><strong>ECGSYN</strong>:</p>
|
||||||
|
<p><strong>©</strong> ECGSYN Copyright by Patrick E. McSharry and Gari
|
||||||
|
D. Clifford. <br>
|
||||||
|
© Java code copyright by Mauricio Villarroel.<br>
|
||||||
|
<br>
|
||||||
|
For the Mathematical Model, see:</p>
|
||||||
|
<table width="100%" border="1" cellspacing="0" cellpadding="5">
|
||||||
|
<tr>
|
||||||
|
<td align="left" valign="top">IEEE Transactions On Biomedical Engineering,
|
||||||
|
50(3), 289-294, March 2003</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
<p> Contact: </p>
|
||||||
|
<ul>
|
||||||
|
<li><a href="mailto:patrick@mcsharry.net">Patrck McSharry</a></li>
|
||||||
|
<li><a href="mailto:gari@mit.edu">Gari Clifford</a></li>
|
||||||
|
<li><a href="mailto:mauricio.villarroel@estudiantes.ucb.edu.bo">Mauricio Villarroel</a></li>
|
||||||
|
</ul>
|
||||||
|
<p>Please read the <a href="ecgLicense.txt">Software License</a>.
|
||||||
|
</p></td>
|
||||||
|
<td align="center" valign="middle">ECG Ouput Sample image:<br><p><img src="ecgplot.PNG" alt="ECGSYN-Java Output Sample image" width="580" height="330" border="1"></p>
|
||||||
|
<p>Source code: <a href="ecgApplet.tar.gz">ecgApplet.tar.gz</a></p></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td height="50"> </td>
|
||||||
|
<td height="50" align="center" valign="middle"> </td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td colspan="2" align="center" valign="top"><strong><font size="4">You can
|
||||||
|
test the ECGSYN Java Application:</font></strong></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td colspan="2" align="center" valign="top"><applet name= "ecgApplet" code="ecgApplet.class" width=915 height=570>
|
||||||
|
</applet></td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
<H3> </H3>
|
||||||
|
<P> </P>
|
||||||
|
<HR WIDTH="100%"><FONT SIZE=-1><I>ECGSYN Java Application<br>
|
||||||
|
Last updated on October 27, 2003</I></FONT>
|
||||||
|
<p align="justify">Return to ECGSYN <a href="http://www.maths.ox.ac.uk/~mcsharry/ecgsyn">Home page</a>.</p>
|
||||||
|
</BODY>
|
||||||
|
</HTML>
|
||||||
2623
ecgsyn-1.0.0/Java/ecgApplet.java
Normal file
39
ecgsyn-1.0.0/Java/ecgLicense.txt
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
/************************************************************************/
|
||||||
|
/* */
|
||||||
|
/* ECGSYN Java Application */
|
||||||
|
/* */
|
||||||
|
/* Copyright (C) 2003 Mauricio Villarroel */
|
||||||
|
/* (mauricio DOT villarroel AT estudiantes DOT ucb DOT edu DOT bo) */
|
||||||
|
/* */
|
||||||
|
/* ecgApplet.java and all its components are free software; you can */
|
||||||
|
/* redistribute them and/or modify it under the terms of the */
|
||||||
|
/* GNU General Public License as published by the Free Software */
|
||||||
|
/* Foundation; either version 2 of the License, or (at your option) */
|
||||||
|
/* any later version. */
|
||||||
|
/* */
|
||||||
|
/* This file is distributed in the hope that it will be useful, but */
|
||||||
|
/* WITHOUT ANY WARRANTY; without even the implied warranty of */
|
||||||
|
/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. */
|
||||||
|
/* See the GNU General Public License for more details. */
|
||||||
|
/* */
|
||||||
|
/************************************************************************/
|
||||||
|
/* */
|
||||||
|
/* This file was created for the ECGSYN Application. */
|
||||||
|
/* */
|
||||||
|
/* ECGSYN: A program for generating a realistic synthetic */
|
||||||
|
/* Electrocardiogram Signals. */
|
||||||
|
/* Copyright (c) 2003 by Patrick McSharry & Gari Clifford. */
|
||||||
|
/* All rights reserved. */
|
||||||
|
/* */
|
||||||
|
/* See IEEE Transactions On Biomedical Engineering, */
|
||||||
|
/* 50(3), 289-294, March 2003. */
|
||||||
|
/* Contact: */
|
||||||
|
/* P. McSharry (patrick AT mcsharry DOT net) */
|
||||||
|
/* G. Clifford (gari AT mit DOT edu) */
|
||||||
|
/* */
|
||||||
|
/************************************************************************/
|
||||||
|
/* */
|
||||||
|
/* Further updates to this software will be published on: */
|
||||||
|
/* http://www.physionet.org/ */
|
||||||
|
/* */
|
||||||
|
/************************************************************************/
|
||||||
BIN
ecgsyn-1.0.0/Java/ecgplot.PNG
Normal file
|
After Width: | Height: | Size: 10 KiB |
64
ecgsyn-1.0.0/Java/ecgsyn-java.html
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
<HTML>
|
||||||
|
<HEAD>
|
||||||
|
<TITLE>ECGSYN Java Application</TITLE>
|
||||||
|
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"></HEAD>
|
||||||
|
<BODY bgcolor="#003366" text="#FFFFCC" link="#FFFF33" vlink="#FFCC00" leftmargin="0" topmargin="0" marginwidth="0" marginheight="0">
|
||||||
|
<table width="925" border="0" align="center" cellpadding="0" cellspacing="5">
|
||||||
|
<tr>
|
||||||
|
<td height="50" colspan="2">
|
||||||
|
<H3>
|
||||||
|
<HR WIDTH="100%">
|
||||||
|
</H3>
|
||||||
|
<H3 align="center"><font color="#FF9900">JAVA Application for <br>
|
||||||
|
ECGSYN: A Dynamical Model for Generating
|
||||||
|
Synthetic Electrocardiogram Signals
|
||||||
|
</font></H3>
|
||||||
|
<H3>
|
||||||
|
<HR WIDTH="100%">
|
||||||
|
</H3>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td width="300" align="left" valign="top"><p><strong>ECGSYN</strong>:</p>
|
||||||
|
<p><strong>©</strong> ECGSYN Copyright by Patrick E. McSharry and Gari
|
||||||
|
D. Clifford. <br>
|
||||||
|
© Java code copyright by Mauricio Villarroel.<br>
|
||||||
|
<br>
|
||||||
|
For the Mathematical Model, see:</p>
|
||||||
|
<table width="100%" border="1" cellspacing="0" cellpadding="5">
|
||||||
|
<tr>
|
||||||
|
<td align="left" valign="top">IEEE Transactions On Biomedical Engineering,
|
||||||
|
50(3), 289-294, March 2003</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
<p> Contact: </p>
|
||||||
|
<ul>
|
||||||
|
<li><a href="mailto:patrick@mcsharry.net">Patrck McSharry</a></li>
|
||||||
|
<li><a href="mailto:gari@mit.edu">Gari Clifford</a></li>
|
||||||
|
<li><a href="mailto:mauricio.villarroel@estudiantes.ucb.edu.bo">Mauricio Villarroel</a></li>
|
||||||
|
</ul>
|
||||||
|
<p>Please read the <a href="ecgLicense.txt">Software License</a>.
|
||||||
|
</p></td>
|
||||||
|
<td align="center" valign="middle">ECG Ouput Sample image:<br><p><img src="ecgplot.PNG" alt="ECGSYN-Java Output Sample image" width="580" height="330" border="1"></p>
|
||||||
|
<p>Source code: <a href="../ecgsyn.tar.gz">ecgsyn.tar.gz</a></p></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td height="50"> </td>
|
||||||
|
<td height="50" align="center" valign="middle"> </td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td colspan="2" align="center" valign="top"><strong><font size="4">You can
|
||||||
|
test the ECGSYN Java Application:</font></strong></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td colspan="2" align="center" valign="top"><applet name= "ecgApplet" code="ecgApplet.class" width=915 height=570>
|
||||||
|
</applet></td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
<H3> </H3>
|
||||||
|
<P> </P>
|
||||||
|
<HR WIDTH="100%"><FONT SIZE=-1><I>ECGSYN Java Application<br>
|
||||||
|
Last updated on October 27, 2003</I></FONT>
|
||||||
|
<p align="justify">Return to ECGSYN <a href="../">Home page</a>.</p>
|
||||||
|
</BODY>
|
||||||
|
</HTML>
|
||||||
40
ecgsyn-1.0.0/Java/index.html
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
<html>
|
||||||
|
<head><title>Index of /static/published-projects/ecgsyn/1.0.0/Java/</title></head>
|
||||||
|
<body>
|
||||||
|
<h1>Index of /static/published-projects/ecgsyn/1.0.0/Java/</h1><hr><pre><a href="../">../</a>
|
||||||
|
<a href="FormatNumber.class">FormatNumber.class</a> 12-Apr-2019 17:35 1020
|
||||||
|
<a href="HEADER.shtml">HEADER.shtml</a> 12-Apr-2019 17:35 673
|
||||||
|
<a href="ecgApplet%241.class">ecgApplet$1.class</a> 12-Apr-2019 17:35 989
|
||||||
|
<a href="ecgApplet%2410.class">ecgApplet$10.class</a> 12-Apr-2019 17:35 671
|
||||||
|
<a href="ecgApplet%2411.class">ecgApplet$11.class</a> 12-Apr-2019 17:35 671
|
||||||
|
<a href="ecgApplet%2412.class">ecgApplet$12.class</a> 12-Apr-2019 17:35 671
|
||||||
|
<a href="ecgApplet%2413.class">ecgApplet$13.class</a> 12-Apr-2019 17:35 671
|
||||||
|
<a href="ecgApplet%2414.class">ecgApplet$14.class</a> 12-Apr-2019 17:35 671
|
||||||
|
<a href="ecgApplet%2415.class">ecgApplet$15.class</a> 12-Apr-2019 17:35 671
|
||||||
|
<a href="ecgApplet%2416.class">ecgApplet$16.class</a> 12-Apr-2019 17:35 672
|
||||||
|
<a href="ecgApplet%2417.class">ecgApplet$17.class</a> 12-Apr-2019 17:35 672
|
||||||
|
<a href="ecgApplet%2418.class">ecgApplet$18.class</a> 12-Apr-2019 17:35 672
|
||||||
|
<a href="ecgApplet%242.class">ecgApplet$2.class</a> 12-Apr-2019 17:35 669
|
||||||
|
<a href="ecgApplet%243.class">ecgApplet$3.class</a> 12-Apr-2019 17:35 669
|
||||||
|
<a href="ecgApplet%244.class">ecgApplet$4.class</a> 12-Apr-2019 17:35 669
|
||||||
|
<a href="ecgApplet%245.class">ecgApplet$5.class</a> 12-Apr-2019 17:35 941
|
||||||
|
<a href="ecgApplet%246.class">ecgApplet$6.class</a> 12-Apr-2019 17:35 941
|
||||||
|
<a href="ecgApplet%247.class">ecgApplet$7.class</a> 12-Apr-2019 17:35 941
|
||||||
|
<a href="ecgApplet%248.class">ecgApplet$8.class</a> 12-Apr-2019 17:35 1108
|
||||||
|
<a href="ecgApplet%249.class">ecgApplet$9.class</a> 12-Apr-2019 17:35 669
|
||||||
|
<a href="ecgApplet%24ECGAnimate.class">ecgApplet$ECGAnimate.class</a> 12-Apr-2019 17:35 2716
|
||||||
|
<a href="ecgApplet%24doubleVerifier.class">ecgApplet$doubleVerifier.class</a> 12-Apr-2019 17:35 1485
|
||||||
|
<a href="ecgApplet%24ecgCalc.class">ecgApplet$ecgCalc.class</a> 12-Apr-2019 17:35 13305
|
||||||
|
<a href="ecgApplet%24ecgPanel.class">ecgApplet$ecgPanel.class</a> 12-Apr-2019 17:35 2618
|
||||||
|
<a href="ecgApplet%24integerVerifier.class">ecgApplet$integerVerifier.class</a> 12-Apr-2019 17:35 1489
|
||||||
|
<a href="ecgApplet%24sfVerifier.class">ecgApplet$sfVerifier.class</a> 12-Apr-2019 17:35 1825
|
||||||
|
<a href="ecgApplet%24sfecgVerifier.class">ecgApplet$sfecgVerifier.class</a> 12-Apr-2019 17:35 1615
|
||||||
|
<a href="ecgApplet.class">ecgApplet.class</a> 12-Apr-2019 17:35 40664
|
||||||
|
<a href="ecgApplet.form">ecgApplet.form</a> 12-Apr-2019 17:35 79509
|
||||||
|
<a href="ecgApplet.html">ecgApplet.html</a> 12-Apr-2019 17:35 2583
|
||||||
|
<a href="ecgApplet.java">ecgApplet.java</a> 12-Apr-2019 17:35 109386
|
||||||
|
<a href="ecgLicense.txt">ecgLicense.txt</a> 12-Apr-2019 17:35 2964
|
||||||
|
<a href="ecgplot.PNG">ecgplot.PNG</a> 12-Apr-2019 17:35 10273
|
||||||
|
<a href="ecgsyn-java.html">ecgsyn-java.html</a> 12-Apr-2019 17:35 2541
|
||||||
|
</pre><hr></body>
|
||||||
|
</html>
|
||||||
9
ecgsyn-1.0.0/Matlab/HEADER.shtml
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
<!--#set var="TITLE" value="ECGSYN for Matlab/Octave"-->
|
||||||
|
<!--#include virtual="/head.shtml"-->
|
||||||
|
|
||||||
|
|
||||||
|
<p>
|
||||||
|
This directory contains <a href="../">ECGSYN</a> implemented in Matlab
|
||||||
|
m-code.
|
||||||
|
|
||||||
|
<hr>
|
||||||
52
ecgsyn-1.0.0/Matlab/derivsecgsyn.m
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
function dxdt = derivsecgsyn(t,x,flag,rr,sfint,ti,ai,bi)
|
||||||
|
% dxdt = derivsecgsyn(t,x,flag,rr,sampfreq,ti,ai,bi)
|
||||||
|
% ODE file for generating the synthetic ECG
|
||||||
|
% This file provides dxdt = F(t,x) taking input paramters:
|
||||||
|
% rr: rr process
|
||||||
|
% sfint: Internal sampling frequency [Hertz]
|
||||||
|
% Order of extrema: [P Q R S T]
|
||||||
|
% ti = angles of extrema [radians]
|
||||||
|
% ai = z-position of extrema
|
||||||
|
% bi = Gaussian width of peaks
|
||||||
|
% Copyright (c) 2003 by Patrick McSharry & Gari Clifford, All Rights Reserved
|
||||||
|
% See IEEE Transactions On Biomedical Engineering, 50(3), 289-294, March 2003.
|
||||||
|
% Contact P. McSharry (patrick AT mcsharry DOT net) or
|
||||||
|
% G.D. Clifford (gari AT mit DOT edu)
|
||||||
|
|
||||||
|
% This program is free software; you can redistribute it and/or modify
|
||||||
|
% it under the terms of the GNU General Public License as published by
|
||||||
|
% the Free Software Foundation; either version 2 of the License, or
|
||||||
|
% (at your option) any later version.
|
||||||
|
%
|
||||||
|
% This program is distributed in the hope that it will be useful,
|
||||||
|
% but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
% GNU General Public License for more details.
|
||||||
|
%
|
||||||
|
% You should have received a copy of the GNU General Public License
|
||||||
|
% along with this program; if not, write to the Free Software
|
||||||
|
% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
%
|
||||||
|
% ecgsyn.m and its dependents are freely availble from Physionet -
|
||||||
|
% http://www.physionet.org/ - please report any bugs to the authors above.
|
||||||
|
|
||||||
|
|
||||||
|
xi = cos(ti);
|
||||||
|
yi = sin(ti);
|
||||||
|
ta = atan2(x(2),x(1));
|
||||||
|
r0 = 1;
|
||||||
|
a0 = 1.0 - sqrt(x(1)^2 + x(2)^2)/r0;
|
||||||
|
ip = 1+floor(t*sfint);
|
||||||
|
w0 = 2*pi/rr(ip);
|
||||||
|
|
||||||
|
|
||||||
|
fresp = 0.25;
|
||||||
|
zbase = 0.005*sin(2*pi*fresp*t);
|
||||||
|
|
||||||
|
dx1dt = a0*x(1) - w0*x(2);
|
||||||
|
dx2dt = a0*x(2) + w0*x(1);
|
||||||
|
|
||||||
|
dti = rem(ta - ti, 2*pi);
|
||||||
|
dx3dt = - sum(ai.*dti.*exp(-0.5*(dti./bi).^2)) - 1.0*(x(3) - zbase);
|
||||||
|
|
||||||
|
dxdt = [dx1dt; dx2dt; dx3dt];
|
||||||
240
ecgsyn-1.0.0/Matlab/ecgsyn.m
Normal file
@@ -0,0 +1,240 @@
|
|||||||
|
function [s, ipeaks] = ecgsyn(sfecg,N,Anoise,hrmean,hrstd,lfhfratio,sfint,ti,ai,bi)
|
||||||
|
% [s, ipeaks] = ecgsyn(sfecg,N,Anoise,hrmean,hrstd,lfhfratio,sfint,ti,ai,bi)
|
||||||
|
% Produces synthetic ECG with the following outputs:
|
||||||
|
% s: ECG (mV)
|
||||||
|
% ipeaks: labels for PQRST peaks: P(1), Q(2), R(3), S(4), T(5)
|
||||||
|
% A zero lablel is output otherwise ... use R=find(ipeaks==3);
|
||||||
|
% to find the R peaks s(R), etc.
|
||||||
|
%
|
||||||
|
% Operation uses the following parameters (default values in []s):
|
||||||
|
% sfecg: ECG sampling frequency [256 Hertz]
|
||||||
|
% N: approximate number of heart beats [256]
|
||||||
|
% Anoise: Additive uniformly distributed measurement noise [0 mV]
|
||||||
|
% hrmean: Mean heart rate [60 beats per minute]
|
||||||
|
% hrstd: Standard deviation of heart rate [1 beat per minute]
|
||||||
|
% lfhfratio: LF/HF ratio [0.5]
|
||||||
|
% sfint: Internal sampling frequency [256 Hertz]
|
||||||
|
% Order of extrema: [P Q R S T]
|
||||||
|
% ti = angles of extrema [-70 -15 0 15 100] degrees
|
||||||
|
% ai = z-position of extrema [1.2 -5 30 -7.5 0.75]
|
||||||
|
% bi = Gaussian width of peaks [0.25 0.1 0.1 0.1 0.4]
|
||||||
|
% Copyright (c) 2003 by Patrick McSharry & Gari Clifford, All Rights Reserved
|
||||||
|
% See IEEE Transactions On Biomedical Engineering, 50(3), 289-294, March 2003.
|
||||||
|
% Contact P. McSharry (patrick@mcsharry.net) or G. Clifford (gari@mit.edu)
|
||||||
|
|
||||||
|
% This program is free software; you can redistribute it and/or modify
|
||||||
|
% it under the terms of the GNU General Public License as published by
|
||||||
|
% the Free Software Foundation; either version 2 of the License, or
|
||||||
|
% (at your option) any later version.
|
||||||
|
%
|
||||||
|
% This program is distributed in the hope that it will be useful,
|
||||||
|
% but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
% GNU General Public License for more details.
|
||||||
|
%
|
||||||
|
% You should have received a copy of the GNU General Public License
|
||||||
|
% along with this program; if not, write to the Free Software
|
||||||
|
% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
%
|
||||||
|
% ecgsyn.m and its dependents are freely availble from Physionet -
|
||||||
|
% http://www.physionet.org/ - please report any bugs to the authors above.
|
||||||
|
|
||||||
|
% set parameter default values
|
||||||
|
if nargin < 1
|
||||||
|
sfecg = 256;
|
||||||
|
end
|
||||||
|
if nargin < 2
|
||||||
|
N = 256;
|
||||||
|
end
|
||||||
|
if nargin < 3
|
||||||
|
Anoise = 0;
|
||||||
|
end
|
||||||
|
if nargin < 4
|
||||||
|
hrmean = 60;
|
||||||
|
end
|
||||||
|
if nargin < 5
|
||||||
|
hrstd = 1;
|
||||||
|
end
|
||||||
|
if nargin < 6
|
||||||
|
lfhfratio = 0.5;
|
||||||
|
end
|
||||||
|
if nargin < 7
|
||||||
|
sfint = 512;
|
||||||
|
end
|
||||||
|
if nargin <8
|
||||||
|
% P Q R S T
|
||||||
|
ti = [-70 -15 0 15 100];
|
||||||
|
end
|
||||||
|
% convert to radians
|
||||||
|
ti = ti*pi/180;
|
||||||
|
if nargin <9 % z position of attractor
|
||||||
|
% P Q R S T
|
||||||
|
ai = [1.2 -5 30 -7.5 0.75];
|
||||||
|
end
|
||||||
|
if nargin <10 % Gaussian width of each attractor
|
||||||
|
% P Q R S T
|
||||||
|
bi = [0.25 0.1 0.1 0.1 0.4];
|
||||||
|
end
|
||||||
|
|
||||||
|
% adjust extrema parameters for mean heart rate
|
||||||
|
hrfact = sqrt(hrmean/60);
|
||||||
|
hrfact2 = sqrt(hrfact);
|
||||||
|
bi = hrfact*bi;
|
||||||
|
ti = [hrfact2 hrfact 1 hrfact hrfact2].*ti;
|
||||||
|
|
||||||
|
% check that sfint is an integer multiple of sfecg
|
||||||
|
q = round(sfint/sfecg);
|
||||||
|
qd = sfint/sfecg;
|
||||||
|
if q ~= qd
|
||||||
|
error(['Internal sampling frequency (sfint) must be an integer multiple ' ...
|
||||||
|
'of the ECG sampling frequency (sfecg). Your current choices are: ' ...
|
||||||
|
'sfecg = ' int2str(sfecg) ' and sfint = ' int2str(sfint) '.']);
|
||||||
|
end
|
||||||
|
|
||||||
|
% define frequency parameters for rr process
|
||||||
|
% flo and fhi correspond to the Mayer waves and respiratory rate respectively
|
||||||
|
flo = 0.1;
|
||||||
|
fhi = 0.25;
|
||||||
|
flostd = 0.01;
|
||||||
|
fhistd = 0.01;
|
||||||
|
|
||||||
|
fid = 1;
|
||||||
|
fprintf(fid,'ECG sampled at %d Hz\n',sfecg);
|
||||||
|
fprintf(fid,'Approximate number of heart beats: %d\n',N);
|
||||||
|
fprintf(fid,'Measurement noise amplitude: %d \n',Anoise);
|
||||||
|
fprintf(fid,'Heart rate mean: %d bpm\n',hrmean);
|
||||||
|
fprintf(fid,'Heart rate std: %d bpm\n',hrstd);
|
||||||
|
fprintf(fid,'LF/HF ratio: %g\n',lfhfratio);
|
||||||
|
fprintf(fid,'Internal sampling frequency: %g\n',sfint);
|
||||||
|
fprintf(fid,' P Q R S T\n');
|
||||||
|
fprintf(fid,'ti = [%g %g %g %g %g] radians\n',ti(1),ti(2),ti(3),ti(4),ti(5));
|
||||||
|
fprintf(fid,'ai = [%g %g %g %g %g]\n',ai(1),ai(2),ai(3),ai(4),ai(5));
|
||||||
|
fprintf(fid,'bi = [%g %g %g %g %g]\n',bi(1),bi(2),bi(3),bi(4),bi(5));
|
||||||
|
|
||||||
|
|
||||||
|
% calculate time scales for rr and total output
|
||||||
|
sampfreqrr = 1;
|
||||||
|
trr = 1/sampfreqrr;
|
||||||
|
tstep = 1/sfecg;
|
||||||
|
rrmean = (60/hrmean);
|
||||||
|
Nrr = 2^(ceil(log2(N*rrmean/trr)));
|
||||||
|
|
||||||
|
% compute rr process
|
||||||
|
rr0 = rrprocess(flo,fhi,flostd,fhistd,lfhfratio,hrmean,hrstd,sampfreqrr,Nrr);
|
||||||
|
|
||||||
|
% upsample rr time series from 1 Hz to sfint Hz
|
||||||
|
rr = interp(rr0,sfint);
|
||||||
|
|
||||||
|
% make the rrn time series
|
||||||
|
dt = 1/sfint;
|
||||||
|
rrn = zeros(length(rr),1);
|
||||||
|
tecg=0;
|
||||||
|
i = 1;
|
||||||
|
while i <= length(rr)
|
||||||
|
tecg = tecg+rr(i);
|
||||||
|
ip = round(tecg/dt);
|
||||||
|
rrn(i:ip) = rr(i);
|
||||||
|
i = ip+1;
|
||||||
|
end
|
||||||
|
Nt = ip;
|
||||||
|
|
||||||
|
% integrate system using fourth order Runge-Kutta
|
||||||
|
fprintf(fid,'Integrating dynamical system\n');
|
||||||
|
x0 = [1,0,0.04];
|
||||||
|
Tspan = [0:dt:(Nt-1)*dt];
|
||||||
|
[T,X0] = ode45('derivsecgsyn',Tspan,x0,[],rrn,sfint,ti,ai,bi);
|
||||||
|
|
||||||
|
% downsample to required sfecg
|
||||||
|
X = X0(1:q:end,:);
|
||||||
|
|
||||||
|
% extract R-peaks times
|
||||||
|
ipeaks = detectpeaks(X, ti, sfecg);
|
||||||
|
|
||||||
|
% Scale signal to lie between -0.4 and 1.2 mV
|
||||||
|
z = X(:,3);
|
||||||
|
zmin = min(z);
|
||||||
|
zmax = max(z);
|
||||||
|
zrange = zmax - zmin;
|
||||||
|
z = (z - zmin)*(1.6)/zrange -0.4;
|
||||||
|
|
||||||
|
% include additive uniformly distributed measurement noise
|
||||||
|
eta = 2*rand(length(z),1)-1;
|
||||||
|
s = z + Anoise*eta;
|
||||||
|
|
||||||
|
|
||||||
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
function rr = rrprocess(flo, fhi, flostd, fhistd, lfhfratio, hrmean, hrstd, sfrr, n)
|
||||||
|
w1 = 2*pi*flo;
|
||||||
|
w2 = 2*pi*fhi;
|
||||||
|
c1 = 2*pi*flostd;
|
||||||
|
c2 = 2*pi*fhistd;
|
||||||
|
sig2 = 1;
|
||||||
|
sig1 = lfhfratio;
|
||||||
|
rrmean = 60/hrmean;
|
||||||
|
rrstd = 60*hrstd/(hrmean*hrmean);
|
||||||
|
|
||||||
|
df = sfrr/n;
|
||||||
|
w = [0:n-1]'*2*pi*df;
|
||||||
|
dw1 = w-w1;
|
||||||
|
dw2 = w-w2;
|
||||||
|
|
||||||
|
Hw1 = sig1*exp(-0.5*(dw1/c1).^2)/sqrt(2*pi*c1^2);
|
||||||
|
Hw2 = sig2*exp(-0.5*(dw2/c2).^2)/sqrt(2*pi*c2^2);
|
||||||
|
Hw = Hw1 + Hw2;
|
||||||
|
Hw0 = [Hw(1:n/2+1); Hw(n/2:-1:2)];
|
||||||
|
Sw = (sfrr/2)*sqrt(Hw0);
|
||||||
|
|
||||||
|
ph0 = 2*pi*rand(n/2-1,1);
|
||||||
|
ph = [ 0; ph0; 0; -flipud(ph0) ];
|
||||||
|
SwC = Sw .* exp(j*ph);
|
||||||
|
x = (1/n)*real(ifft(SwC));
|
||||||
|
|
||||||
|
xstd = std(x);
|
||||||
|
ratio = rrstd/xstd;
|
||||||
|
rr = rrmean + x*ratio;
|
||||||
|
|
||||||
|
|
||||||
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
function ind = detectpeaks(X, thetap, sfecg)
|
||||||
|
N = length(X);
|
||||||
|
irpeaks = zeros(N,1);
|
||||||
|
|
||||||
|
theta = atan2(X(:,2),X(:,1));
|
||||||
|
ind0 = zeros(N,1);
|
||||||
|
for i=1:N-1
|
||||||
|
a = ( (theta(i) <= thetap) & (thetap <= theta(i+1)) );
|
||||||
|
j = find(a==1);
|
||||||
|
if ~isempty(j)
|
||||||
|
d1 = thetap(j) - theta(i);
|
||||||
|
d2 = theta(i+1) - thetap(j);
|
||||||
|
if d1 < d2
|
||||||
|
ind0(i) = j;
|
||||||
|
else
|
||||||
|
ind0(i+1) = j;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
d = ceil(sfecg/64);
|
||||||
|
d = max([2 d])
|
||||||
|
ind = zeros(N,1);
|
||||||
|
z = X(:,3);
|
||||||
|
zmin = min(z);
|
||||||
|
zmax = max(z);
|
||||||
|
zext = [zmin zmax zmin zmax zmin];
|
||||||
|
sext = [1 -1 1 -1 1];
|
||||||
|
for i=1:5
|
||||||
|
clear ind1 Z k vmax imax iext;
|
||||||
|
ind1 = find(ind0==i);
|
||||||
|
n = length(ind1);
|
||||||
|
Z = ones(n,2*d+1)*zext(i)*sext(i);
|
||||||
|
for j=-d:d
|
||||||
|
k = find( (1 <= ind1+j) & (ind1+j <= N) );
|
||||||
|
Z(k,d+j+1) = z(ind1(k)+j)*sext(i);
|
||||||
|
end
|
||||||
|
[vmax, ivmax] = max(Z,[],2);
|
||||||
|
iext = ind1 + ivmax-d-1;
|
||||||
|
ind(iext) = i;
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
9
ecgsyn-1.0.0/Matlab/index.html
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
<html>
|
||||||
|
<head><title>Index of /static/published-projects/ecgsyn/1.0.0/Matlab/</title></head>
|
||||||
|
<body>
|
||||||
|
<h1>Index of /static/published-projects/ecgsyn/1.0.0/Matlab/</h1><hr><pre><a href="../">../</a>
|
||||||
|
<a href="HEADER.shtml">HEADER.shtml</a> 12-Apr-2019 17:35 186
|
||||||
|
<a href="derivsecgsyn.m">derivsecgsyn.m</a> 12-Apr-2019 17:35 1911
|
||||||
|
<a href="ecgsyn.m">ecgsyn.m</a> 12-Apr-2019 17:35 6795
|
||||||
|
</pre><hr></body>
|
||||||
|
</html>
|
||||||
BIN
ecgsyn-1.0.0/ecgsyn.tar.gz
Normal file
12
ecgsyn-1.0.0/index.html
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
<html>
|
||||||
|
<head><title>Index of /static/published-projects/ecgsyn/1.0.0/</title></head>
|
||||||
|
<body>
|
||||||
|
<h1>Index of /static/published-projects/ecgsyn/1.0.0/</h1><hr><pre><a href="../">../</a>
|
||||||
|
<a href="C/">C/</a> 12-Apr-2019 17:35 -
|
||||||
|
<a href="Java/">Java/</a> 12-Apr-2019 17:35 -
|
||||||
|
<a href="Matlab/">Matlab/</a> 12-Apr-2019 17:35 -
|
||||||
|
<a href="paper/">paper/</a> 12-Apr-2019 17:35 -
|
||||||
|
<a href="sample-output/">sample-output/</a> 12-Apr-2019 17:35 -
|
||||||
|
<a href="ecgsyn.tar.gz">ecgsyn.tar.gz</a> 12-Apr-2019 17:35 165286
|
||||||
|
</pre><hr></body>
|
||||||
|
</html>
|
||||||
30
ecgsyn-1.0.0/paper/ecgpqrst.css
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
/* Century Schoolbook font is very similar to Computer Modern Math: cmmi */
|
||||||
|
.MATH { font-family: "Century Schoolbook", serif; }
|
||||||
|
.MATH I { font-family: "Century Schoolbook", serif; font-style: italic }
|
||||||
|
.BOLDMATH { font-family: "Century Schoolbook", serif; font-weight: bold }
|
||||||
|
|
||||||
|
/* implement both fixed-size and relative sizes */
|
||||||
|
SMALL.XTINY { font-size : xx-small }
|
||||||
|
SMALL.TINY { font-size : x-small }
|
||||||
|
SMALL.SCRIPTSIZE { font-size : smaller }
|
||||||
|
SMALL.FOOTNOTESIZE { font-size : small }
|
||||||
|
SMALL.SMALL { }
|
||||||
|
BIG.LARGE { }
|
||||||
|
BIG.XLARGE { font-size : large }
|
||||||
|
BIG.XXLARGE { font-size : x-large }
|
||||||
|
BIG.HUGE { font-size : larger }
|
||||||
|
BIG.XHUGE { font-size : xx-large }
|
||||||
|
|
||||||
|
/* heading styles */
|
||||||
|
H1 { }
|
||||||
|
H2 { }
|
||||||
|
H3 { }
|
||||||
|
H4 { }
|
||||||
|
H5 { }
|
||||||
|
|
||||||
|
/* mathematics styles */
|
||||||
|
DIV.displaymath { } /* math displays */
|
||||||
|
TD.eqno { } /* equation-number cells */
|
||||||
|
|
||||||
|
|
||||||
|
/* document-specific styles come next */
|
||||||
79
ecgsyn-1.0.0/paper/footnode.html
Normal file
@@ -0,0 +1,79 @@
|
|||||||
|
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
|
||||||
|
|
||||||
|
<!--Converted with jLaTeX2HTML 2002 (1.62) JA patch-1.4
|
||||||
|
patched version by: Kenshi Muto, Debian Project.
|
||||||
|
LaTeX2HTML 2002 (1.62),
|
||||||
|
original version by: Nikos Drakos, CBLU, University of Leeds
|
||||||
|
* revised and updated by: Marcus Hennecke, Ross Moore, Herb Swan
|
||||||
|
* with significant contributions from:
|
||||||
|
Jens Lippmann, Marek Rouchal, Martin Wilck and others -->
|
||||||
|
<HTML>
|
||||||
|
<HEAD>
|
||||||
|
<TITLE>Footnotes</TITLE>
|
||||||
|
<META NAME="description" CONTENT="Footnotes">
|
||||||
|
<META NAME="keywords" CONTENT="ecgpqrst">
|
||||||
|
<META NAME="resource-type" CONTENT="document">
|
||||||
|
<META NAME="distribution" CONTENT="global">
|
||||||
|
|
||||||
|
<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1">
|
||||||
|
<META NAME="Generator" CONTENT="jLaTeX2HTML v2002 JA patch-1.4">
|
||||||
|
<META HTTP-EQUIV="Content-Style-Type" CONTENT="text/css">
|
||||||
|
|
||||||
|
<LINK REL="STYLESHEET" HREF="ecgpqrst.css">
|
||||||
|
|
||||||
|
<LINK REL="previous" HREF="node8.html">
|
||||||
|
<LINK REL="up" HREF="index.shtml">
|
||||||
|
</HEAD>
|
||||||
|
|
||||||
|
<BODY >
|
||||||
|
|
||||||
|
<DL>
|
||||||
|
<DT><A NAME="foot31">...<IMG
|
||||||
|
WIDTH="21" HEIGHT="17" ALIGN="BOTTOM" BORDER="0"
|
||||||
|
SRC="img6.png"
|
||||||
|
ALT="$^{2,3}$"></A><A
|
||||||
|
HREF="index.shtml#tex2html1"><SUP><IMG ALIGN="BOTTOM" BORDER="1" ALT="[*]"
|
||||||
|
SRC="file:/usr/share/latex2html/icons/footnote.png"></SUP></A></DT>
|
||||||
|
<DD><IMG
|
||||||
|
WIDTH="11" HEIGHT="17" ALIGN="BOTTOM" BORDER="0"
|
||||||
|
SRC="img5.png"
|
||||||
|
ALT="$^1$">Department of Engineering Science,
|
||||||
|
University of Oxford, Oxford OX1 3PJ.
|
||||||
|
|
||||||
|
<PRE>.
|
||||||
|
</PRE>
|
||||||
|
</DD>
|
||||||
|
<DT><A NAME="foot32">...</A><A
|
||||||
|
HREF="index.shtml#tex2html2"><SUP><IMG ALIGN="BOTTOM" BORDER="1" ALT="[*]"
|
||||||
|
SRC="file:/usr/share/latex2html/icons/footnote.png"></SUP></A></DT>
|
||||||
|
<DD><IMG
|
||||||
|
WIDTH="11" HEIGHT="17" ALIGN="BOTTOM" BORDER="0"
|
||||||
|
SRC="img7.png"
|
||||||
|
ALT="$^2$">Mathematical Institute, University of Oxford, Oxford OX1 3LB.
|
||||||
|
|
||||||
|
<PRE>.
|
||||||
|
</PRE>
|
||||||
|
</DD>
|
||||||
|
<DT><A NAME="foot33">...</A><A
|
||||||
|
HREF="index.shtml#tex2html3"><SUP><IMG ALIGN="BOTTOM" BORDER="1" ALT="[*]"
|
||||||
|
SRC="file:/usr/share/latex2html/icons/footnote.png"></SUP></A></DT>
|
||||||
|
<DD><IMG
|
||||||
|
WIDTH="11" HEIGHT="17" ALIGN="BOTTOM" BORDER="0"
|
||||||
|
SRC="img8.png"
|
||||||
|
ALT="$^3$">Centre for the Analysis of Time Series, London School
|
||||||
|
of Economics, London WC2A 2AE.
|
||||||
|
|
||||||
|
<PRE>.
|
||||||
|
</PRE>
|
||||||
|
</DD>
|
||||||
|
<DT><A NAME="foot34">...</A><A
|
||||||
|
HREF="index.shtml#tex2html4"><SUP><IMG ALIGN="BOTTOM" BORDER="1" ALT="[*]"
|
||||||
|
SRC="file:/usr/share/latex2html/icons/footnote.png"></SUP></A></DT>
|
||||||
|
<DD>E-mail: mcsharry@robots.ox.ac.uk
|
||||||
|
|
||||||
|
<PRE>.
|
||||||
|
</PRE>
|
||||||
|
</DD>
|
||||||
|
</DL>
|
||||||
|
</BODY>
|
||||||
|
</HTML>
|
||||||
BIN
ecgsyn-1.0.0/paper/img1.png
Normal file
|
After Width: | Height: | Size: 446 B |
BIN
ecgsyn-1.0.0/paper/img10.png
Normal file
|
After Width: | Height: | Size: 3.8 KiB |
BIN
ecgsyn-1.0.0/paper/img11.png
Normal file
|
After Width: | Height: | Size: 393 B |
BIN
ecgsyn-1.0.0/paper/img12.png
Normal file
|
After Width: | Height: | Size: 182 B |
BIN
ecgsyn-1.0.0/paper/img13.png
Normal file
|
After Width: | Height: | Size: 274 B |
BIN
ecgsyn-1.0.0/paper/img14.png
Normal file
|
After Width: | Height: | Size: 293 B |
BIN
ecgsyn-1.0.0/paper/img15.png
Normal file
|
After Width: | Height: | Size: 289 B |
BIN
ecgsyn-1.0.0/paper/img16.png
Normal file
|
After Width: | Height: | Size: 275 B |
BIN
ecgsyn-1.0.0/paper/img17.png
Normal file
|
After Width: | Height: | Size: 264 B |
BIN
ecgsyn-1.0.0/paper/img18.png
Normal file
|
After Width: | Height: | Size: 217 B |
BIN
ecgsyn-1.0.0/paper/img19.png
Normal file
|
After Width: | Height: | Size: 150 B |
BIN
ecgsyn-1.0.0/paper/img2.png
Normal file
|
After Width: | Height: | Size: 392 B |
BIN
ecgsyn-1.0.0/paper/img20.png
Normal file
|
After Width: | Height: | Size: 426 B |
BIN
ecgsyn-1.0.0/paper/img21.png
Normal file
|
After Width: | Height: | Size: 232 B |
BIN
ecgsyn-1.0.0/paper/img22.png
Normal file
|
After Width: | Height: | Size: 445 B |
BIN
ecgsyn-1.0.0/paper/img23.png
Normal file
|
After Width: | Height: | Size: 202 B |
BIN
ecgsyn-1.0.0/paper/img24.png
Normal file
|
After Width: | Height: | Size: 1.7 KiB |
BIN
ecgsyn-1.0.0/paper/img25.png
Normal file
|
After Width: | Height: | Size: 655 B |
BIN
ecgsyn-1.0.0/paper/img26.png
Normal file
|
After Width: | Height: | Size: 813 B |
BIN
ecgsyn-1.0.0/paper/img27.png
Normal file
|
After Width: | Height: | Size: 662 B |
BIN
ecgsyn-1.0.0/paper/img28.png
Normal file
|
After Width: | Height: | Size: 214 B |
BIN
ecgsyn-1.0.0/paper/img29.png
Normal file
|
After Width: | Height: | Size: 236 B |
BIN
ecgsyn-1.0.0/paper/img3.png
Normal file
|
After Width: | Height: | Size: 553 B |
BIN
ecgsyn-1.0.0/paper/img30.png
Normal file
|
After Width: | Height: | Size: 260 B |
BIN
ecgsyn-1.0.0/paper/img31.png
Normal file
|
After Width: | Height: | Size: 823 B |
BIN
ecgsyn-1.0.0/paper/img32.png
Normal file
|
After Width: | Height: | Size: 394 B |
BIN
ecgsyn-1.0.0/paper/img33.png
Normal file
|
After Width: | Height: | Size: 472 B |
BIN
ecgsyn-1.0.0/paper/img34.png
Normal file
|
After Width: | Height: | Size: 256 B |
BIN
ecgsyn-1.0.0/paper/img35.png
Normal file
|
After Width: | Height: | Size: 257 B |
BIN
ecgsyn-1.0.0/paper/img36.png
Normal file
|
After Width: | Height: | Size: 237 B |
BIN
ecgsyn-1.0.0/paper/img37.png
Normal file
|
After Width: | Height: | Size: 249 B |
BIN
ecgsyn-1.0.0/paper/img38.png
Normal file
|
After Width: | Height: | Size: 590 B |
BIN
ecgsyn-1.0.0/paper/img39.png
Normal file
|
After Width: | Height: | Size: 296 B |
BIN
ecgsyn-1.0.0/paper/img4.png
Normal file
|
After Width: | Height: | Size: 220 B |
BIN
ecgsyn-1.0.0/paper/img40.png
Normal file
|
After Width: | Height: | Size: 320 B |
BIN
ecgsyn-1.0.0/paper/img41.png
Normal file
|
After Width: | Height: | Size: 287 B |
BIN
ecgsyn-1.0.0/paper/img42.png
Normal file
|
After Width: | Height: | Size: 274 B |
BIN
ecgsyn-1.0.0/paper/img43.png
Normal file
|
After Width: | Height: | Size: 4.1 KiB |
BIN
ecgsyn-1.0.0/paper/img44.png
Normal file
|
After Width: | Height: | Size: 4.3 KiB |
BIN
ecgsyn-1.0.0/paper/img45.png
Normal file
|
After Width: | Height: | Size: 2.7 KiB |
BIN
ecgsyn-1.0.0/paper/img46.png
Normal file
|
After Width: | Height: | Size: 369 B |
BIN
ecgsyn-1.0.0/paper/img47.png
Normal file
|
After Width: | Height: | Size: 318 B |
BIN
ecgsyn-1.0.0/paper/img48.png
Normal file
|
After Width: | Height: | Size: 275 B |
BIN
ecgsyn-1.0.0/paper/img49.png
Normal file
|
After Width: | Height: | Size: 268 B |