In the past I thought it would be a good idea to distinguish between continuous and discrete data in order to solve several scaling problems arising in Fourier transform, convolution, volume computation, histograms etc. This was until I became aware, that all of these problems can be solved with proper units. The units are sometimes unexpected, but the results are consistent. discrete and continuous signals implement switch Discrete/Continuous maybe the discrete/continuous mode should be made explicit by a phantom type parameter Continuous: audio signals, control curves, distortion tables Discrete: Fourier series, histogram, peaks (random or for zero crossings) discrete can be considered a sequence of Dirac impulses different handling: re-sampling: continuous - amplitude maintained discrete - amplitude adapted energy volume (yields isometric Fourier transform): continuous - sum divided by number of samples discrete - unscaled sum Fourier transform analysis: continuous -> discrete, (1,...,1) -> impulse this means dividing by number of samples synthesis: discrete -> continuous, impulse -> (1,...,1) this means no scaling it shall hold: 1. fourierAnalysis (x <*> y) = fourierAnalysis x * fourierAnalysis y 2. fourierAnalysis (x * y) = fourierAnalysis x <*> fourierAnalysis y 3. fourierSynthesis (x <*> y) = fourierSynthesis x * fourierSynthesis y 4. fourierSynthesis (x * y) = fourierSynthesis x <*> fourierSynthesis y in order to have a neutral element, in 2. one of x and y must be continuous, in order to have constant 1 in 3. one of x and y must be discrete, in order to have dirac 1. and 4. cannot hold, because 1. fourierAnalysis (x <*> dirac) = fourierAnalysis x fourierAnalysis x * fourierAnalysis dirac = fourierAnalysis x / n 4. fourierSynthesis (x * const1) = fourierSynthesis x fourierSynthesis x <*> fourierSynthesis const1 = fourierSynthesis x * n they can be fixed to 1. fourierAnalysis (x <*> y) = fourierAnalysis x * fourierAnalysis y * n 4. fourierSynthesis (x * y) = fourierSynthesis x <*> fourierSynthesis y / n where in 1., y is discrete and in 4., y is continuous How is fourierAnalysis expressed in terms of fourierSynthesis and vice versa? The difference between analysis and synthesis is not just a constant factor, but is also about conjugation and reversing. Looking on the sum that defines the Fourier transform, you obtain fourierAnalysis (conj y) * n = conj (fourierSynthesis y) summarized: 1. fourierAnalysis (x <*> conj y) = fourierAnalysis x * conj (fourierSynthesis y) 2. fourierAnalysis (x * y) = fourierAnalysis x <*> fourierAnalysis y 3. fourierSynthesis (x <*> y) = fourierSynthesis x * fourierSynthesis y 4. fourierSynthesis (x * conj y) = fourierSynthesis x <*> conj (fourierAnalysis y) continuous transform: continuousAnalysis: (t -> v) -> (1/t -> t*v) continuousSynthesis: (t -> v) -> (1/t -> t*v) We would need to implementations of energyVolume, which have the same static type, but different units energyVolumeTimeSpace :: (t -> v) -> v energyVolumeFrequencySpace :: (f -> v) -> v*f (1/t -> t*v) -> v fourierAnalysis (continuousSynthesis x * fourierSynthesis y) would implement a convolution of type (continuous -> discrete -> discrete) but with an extra time factor in the amplitude envelope: continuous * x yields x discrete * discrete is an error convolution / filtering discrete <*> x yields x It holds: stretch k x <*> stretch k y = stretch k (x <*> y) continuous <*> x yields continuous continuous <*> continuous yields differentiable, but this is too fine grained for our approach. Speaking in units, it is (<*>) :: (t -> a) -> (t -> b) -> (t -> a*b*t) It holds: stretch k x <*> stretch k y = k * stretch k (x <*> y) The strange thing is, that differentiable is even better behaved than continuous, but on the Fourier side this is reversed: discrete times discrete (impulse times impulse) is even worse) These considerations suggest that implicit filter windows (universal filter, Moog lowpass, all pass etc.) must be discrete or must be continuous with unit (t -> v/t). We need to manage several properties via types: Signals with volume with volume is the common case Without volume: Gate signals of type [Bool] Pulse or trigger signals of type [Bool] State signal of type (Enum a => [a]) Discrete Histogram of type [Int] maybe control signals as inputs to mapExponential, mapLinear Signals with beginning different from zero examples: distortion by a table, histogram Cyclic signals (excludes signal with non-zero beginning) example: input of Fourier analysis waveform for an oscillator possibly best implemented using an array finite, infinite, either-or finite: input for computation of DC offset, volume, histogram maybe table for a non-linear distoration (wave shaping) cyclic signals are automatically finite one time direction, two time directions discrete or continuous See above Shall Discrete/Continuous be integrated in the signal or in the sample rate context? Since in contrast to the sample rate only a fixed set of values is possible, we could integrate it in the signal type as phantom type parameter. However, shall it be attached to the sample value list (Signal) or to ShiftedSignal? We could also attach it to the sample rate context because it influences the way the sample rate is interpreted. with integrated sample rate or with a sample rate context These features must be combined very flexible SampleRateContext Discrete t t' (Volume y y' (Signal yv)) SampleRateContext Continuous t t' (Volume y y' (ShiftedSignal yv)) SampleRateContext Continuous t t' (Volume y y' (ShiftedSignal Double) -> ShiftedSignal Bool) append :: Volume y y' (Signal mode yv) -> Volume y y' (Signal mode yv) -> Volume y y' (Signal mode yv) amplify :: y' -> Volume y y' (signal mode yv) -> Volume y y' (signal mode yv) envelope :: Volume y y' (signal Continuous yv) -> Volume y y' (signal mode yv) -> Volume y y' (signal mode yv) convolution :: Volume y y' (signal Discrete yv) -> Volume y y' (signal mode yv) -> Volume y y' (signal mode yv) convolutionContinuous :: SampleRateContext q q' (Volume q q' (signal Continuous yv) -> Volume q q' (signal Continuous yv) -> Volume q q' (signal Continuous yv)) resample :: ResampleMode mode => Interpolation t yv -> FixedSampleRate t t' (Signal mode yv) -> SampleRateContext t t' (Signal mode yv) resampleShifted :: ResampleMode mode => Interpolation t yv -> FixedSampleRate t t' (ShiftedSignal mode yv) -> SampleRateContext t t' (ShiftedSignal mode yv) histogramDiscrete :: Volume y y' (signal Discrete y) -> SampleRateContext y y' (ShiftedSignal Discrete Int) histogramContinuous :: SampleRateContext q q' (Volume q q' (signal Continuous q)) -> SampleRateContext q q' (Volume q q' (ShiftedSignal Continuous q)) fourierAnalysis :: -- sample rate forced by output samplerate SampleRateContext t t' (Volume y y' (Cyclic Continuous yv)) -> SampleRateContext t t' (Volume y y' (Cyclic Discrete yv)) fourierSynthesis :: SampleRateContext t t' (Volume y y' (Cyclic Discrete yv)) -> SampleRateContext t t' (Volume y y' (Cyclic Continuous yv))