#ifndef vsignal_H #define vsignal_H /* Vector-valued signals, finite or periodic. */ /* Last edited on 2008-02-16 00:01:31 by stolfi */ #include #include #include typedef struct vsignal_t; /* A {vsignal_t} {f} represents a function {f(t)} from a {time} parameter {t} into a space {R^{nc}}. Each coordinate of {R^{nc}} is called a /channel/ of the signal. The number of channels may be zero. */ int vsignal_channel_count(vsignal_t *f); /* Returns the number of channels in signal {f}. */ void vsignal_eval(vsignal_t *f, double t, double v[]); /* Returns the value of {f(t)}, for a given time {t}. Fails if {f} is finite and {t} is outside the domain of {f}. */ void vsignal_eval_diff(vsignal_t *f, double t, double v[], double dv[]); /* Returns the value of {f(t)} and its temporal derivative {f'(t)}, for a given time {t}. Fails if {f} is finite and {t} is outside the domain of {f}. */ /* FINITE AND PERIODIC SIGNALS There are two kinds of {vsignal_t} objects, /finite/ ({circ=FALSE}) and /periodic/ ({circ=TRUE}). In a finite signal {f}, the value of {f(t)} is defined only for times {t} withing a finite interval {[tMin _ tMax]}, called the /domain/ of the signal. In a periodic signal, the value of {f(t)} is defined for every {t}, but it repeats with a constant displacement after a while. Namely, there is a /time period/ {T > 0} and a constant /data period/ {D} in {R^{nch}} such that {f(t+T) = f(t) + D} for every time {t}. (The traditional definition of /periodic/ is the special case where {D} is zero). The /fundamental domain/ of a {vsignal_t} is the domain {[tMin _ tMax]} if {circ} is FALSE, or the interval {[0 _ T]} if {circ} is TRUE. */ bool_t vsignal_is_periodic(vsignal_t *f); /* Returns TRUE iff {f} is a periodic signal. */ interval_t vsignal_fundamental_domain(vsignal_t *f); /* Returns the fundamental domain of signal {f}. */ double vsignal_time_period(vsignal_t *f); /* Returns the time period of {f}, if {f} is periodic; or 0 if {t} is finite. */ void vsignal_data_period(vsignal_t *f, double v[]); /* Stores into {v[0..nc]} the data period of {f}, if {f} is periodic; or all zeros, if {t} is finite. */ /* CONTINUITY ORDER The /continuity/ {c} of a signal is the minimum number of times that the signal can be differentiated while remaining continuous. Thus, a signal with {c==0} is continuous; a signal with {c==1} is continuous and has a continuous first derivative; and so on. The continuity order may also be {-1}, meaning that the signal is piecewise continuous but may have finite discontinuities. The continuity guarantee only applies if the sampling times are *strictly* monotonic. If {m} successive sampling times are equal, the continuity order may be reduced to {c-m+1} at that moment. */ typedef int8_t vsignal_cont_t; /* Continuity order of the signal function {f(t)} of a {vsignal_t} {f} from its samples. */ vsignal_cont_t vsignal_continuity(vsignal_t *f); /* Returns the continuity order of {f}. */ /* EMPTY SIGNALS An /empty signal/ is a degenerate signal with empty domain. An empty signal still may have any number of channels, continuity order, and reconstruction kind. However, an empty signal is not periodic, its domain is an empty interval. */ bool_t vsignal_is_empty(vsignal_t *f); /* TRUE iff the signal {f} is empty. */ /* SAMPLING TIMES AND DATA SAMPLES The function {f} of a non-empty {vsignal_t} is represented internally by a list of /sampling times/ {ts[0..nt-1]}, and an array of /data samples/ {vs[0..nt-1][0..nc-1]}; where {vs[i][j]} is the sample in channel {j} associated to the instant {ts[i]}. The value of {f(t)} for an arbitrary time {t} in its domain is obtained by applying some /reconstruction filter/ to these samples. More precisely, by taking a linear combination of {c+2} consecutive samples whose sampling times bracket {t}, with weights that depend on {t} and on those sampling times. See below for more details. The sampling times {t[0..nt-1]} must be monotonically non-decreasing. !!! Actually, the reconstructed {t(z)} must be non-decreasing. !!! If {f} is non-empty and periodic, any procedure that requires the index of a sampling time or data frame will accept any integer {i}, possibly negative, with the convention that {ts[i+nt] = ts[i] + T} and {vs[i+nt] = vs[i] + D} for all {i}. If {f} is not periodic, the procedures will accept only indices {i} in the range {0..nt-1}. All such procedures will fail if {f} is empty. TIME DOMAIN AND TIME PERIOD The sampling times and data samples also determine the domain of a finite signal, and the time and data periods of a periodic signal. Specifically, if {f} is periodic, the number of sampling times {nt} must be 2 or more. In that case, the time period will be {T = ts[nt-1] - ts[0]}, and the data period will be {D[j] = vs[nc*(nt-1)+j] - vx[j]} for {j} in {0..nc-1}. If {f} is not periodic and {c >= 0}, the number of sampling times {nt} must be at least {c+1}. The lower bound {tMin} of {f}'s domain will be a linear combination of the first {c+1} sampling times {ts[0..c]}, according to the signal's reconstruction filter. Symmetrically, the upper bound {tMax} is determined by the last {c+1} samples {ts[nt-1-c..nt-1]}. For {c==0}, in particular, we will have {tMin == ts[0]} and {tMax == ts[nt-1]}. If {f} is not periodic and {c == -1}, the number of sampling times {nt} must be at least 2. The domain will extend from {tMin == ts[0]-(ts[1]-ts[0])/2} to {tMax == ts[nt-1]+(ts[nt-1]-ts[nt-2])/2}. */ typedef uint64_t vsignal_frame_count_t; /* Type for a count of data frames in a signal. */ vsignal_frame_count_t vsignal_frame_count(vsignal_t *f); /* The number of data frames in {f}. It is zero for an empty signal. */ typedef int64_t vsignal_frame_index_t; /* Type for the index of a frame in a signal. Allows -1 for `no index'. */ void vsignal_set_sample_time(vsignal_t *f, vsignal_frame_index_t i, double t); /* Sets the sampling time of frame {i} to {t}. */ double vsignal_get_sample_time(vsignal_t *f, vsignal_frame_index_t i); /* Returns the sampling time of frame {i}. */ void vsignal_set_sample(vsignal_t *f, vsignal_frame_index_t i, int j, double v); /* Sets the data sample in channel {j} of frame {i} to {v}. */ double vsignal_get_sample(vsignal_t *f, vsignal_frame_index_t i, int j); /* Returns the data sample in channel {j} of frame {i} to {v}. */ void vsignal_set_frame(vsignal_t *f, vsignal_frame_index_t i, double v[]); /* Sets the samples of frame {i} to {v[0..f.nc-1]}. */ void vsignal_get_frame(vsignal_t *f, vsignal_frame_index_t i, double v[]); /* Extracts the samples of frame {i} and saves them into {v[0..f.nc-1]}. */ void vsignal_set_sampling_times(vsignal_t *f, int ts[]); /* Sets the sampling times of {f} to {ts[0..nt-1]}. Note that the times must be monotonically non-decreasing. */ /* RECONSTRUCTION FILTER The reconstruction filter of a signal {f}, used to compute its value {f(t)} from its samples, is determined by its continuity {c} and an internal attribute called the /filter kind/ {k}. */ typedef enum { vsignal_kind_B } vsignal_kind_t; /* Kind of recosntruction filter used to obtain the value {f(t)} of a {vsignal_t} {f} from its samples. The kind {vsignal_kind_B} specifies a B-spline-like filter. In particular, for {c==-1}, it returns the data frame whose sampling time is closest to {t}. For {c==0}, it returns the piecewise linear interpolation of the data frames whose sampling times bracket {t}. For higher continuity orders, the value of {f(t}) does not interpolate the samples, but gets attracted to them. */ vsignal_kind_t vsignal_kind(vsignal_t *f); /* Returns the filter kind of {f}. */ vsignal_t vsignal_new(int nc, vsignal_frame_count_t nt, bool_t per, vsignal_kind_t k, vsignal_cont_t c); /* Creates a new signal with {nc} channels, space for {nt} frames, periodicity {per}, kind {k}, and continuity {c}. Initially, the sampling times {ts[0..nt-1]} will be {0..nt-1]}, and the data samples will be all 0. If {nt} is less than the minimum required by {c} and {per}, the result will be an empty signal. */ void vsignal_set_sample_counts(vsignal_t *f, int nc, vsignal_frame_count_t nt); /* Redefines the number of channels of {f} to be {nc}, and the number of frames to be {nf}. The procedure discards the current sampling times and data samples of {f}, reclaims their storage space, and allocates sufficient storage for the new samples. The sampling times are set to {0..nt-1}, and the data samples are all set to zero. The continuity order and filter kind of {f} are preserved. If {nt} is too small given the current continuity and periodicity of {f}, then {f} will become empty and non-periodic. Othwerwise the periodicity is preserved. */ void vsignal_make_periodic(vsignal_t *f, bool_t per); /* Makes {f} periodic if {f} is TRUE, or finite if {per} is FALSE. If the number of samples of {f} is too small for its continuity order and its new periodicity {per} the signal will become empty and non-periodic. If {f} is already empty, it will remain so (and {per} will be ignored). */ void vsignal_set_kind(vsignal_t *f, vsignal_kind_t k); /* Sets the filter kind of {f} to be {k}. All other attributes of {f} are preserved. */ void vsignal_set_cont(vsignal_t *f, vsignal_cont_t c); /* Sets the continuity order of {f} to be {c}. The filter kind and number of channels of {f} are preserved. If the number of frames of {f} is too small given its periodicity and the new continuity {c}, then {f} will become empty and non-periodic. Othwerwise the periodicity is preserved and number of frames are preserved too. */ /* SIGNAL OPERATIONS */ vsignal_t *vsignal_copy(vsignal_t *f); /* Makes a copy of curve {f}, so that no subsequent call to a method of {f} will affect the copy (or vice-versa). */ void vsignal_copy_contents(vsignal_t *d, vsignal_t *f); /* If {f} and {d} are the same object, does nothing. Otherwise copies the samples and other attributes of {d} into {f}, reallocating the sampling times and frame arrays as needed; so that {f} and {d} will become identical but with disjoint storage areas. */ void vsignal_uniformize(vsignal_t *f, double ); /* Changes the curve's parametrization to the natural (arc-length) one Specifically, changes the sampling times of {f} so that the integrated length of {f(t)} from 0 to {t} is {t}. */ void vsignal_filter(vsignal_t *d, double sigma, vsignal_t *f); /* Sets {f} to a copy of signal {d}, convolved with a Gaussian-like filter with unit area and characteristic duration {sigma}, and resampled to {nt} sampling times, equally spaced in the domain of {d}. The original curve {d} is not changed. */ void vsignal_diff(vsignal_t *d, vsignal_t *f); /* Sets {f} to an approximate time derivative of signal {d}. The periodicity, channelcount, and reconstruction kind are preserved. The sampling times of {f} will be interleaved among those of {d}, and its continuity will reduced by one. The original curve {d} is not changed.. */ #endif