This post is about design and analysis of digital circuits using haskell as a language and clash as tool to generate digital circuits.

### Main Idea

Frequency analysis can be preformed for digital circuits using only adders, multiplies and register. Intuitive reasoning to get response of single frequency from such circuitry as black box goes as. We insert Signal of complex numbers in circuitry and from resulting complex signal observe phase and amplitude. Registry in this setup is no more than rotation of phase or phase delay that depends on Nyquist frequency of input signal.

Analysis is not done in time, but directly in frequency domain. For one input frequency we get amplitude and phase of output. Approach works best for acyclic circuits, both linear (e.g. fir filter) and nonlinear circuits (e.g. frequency mixer). It can be used for linear cyclic circuits for example iir filter. Anaysis result can be presented as Bode or Nyquist plot. Experimental hacked up implementation is available at github.

### Example of use

Clash compiler can be used to both design digital circuitry and analyze them using the great language Haskell. Both in time and frequency domain. Analysis in time domain is part of standard library that ships with distribution.

We can describe fir filter in language haskell for example as:

``````fir coeffs x = dotp coeffs (windowP x)
where
dotp as bs = sum (zipWith (*) as bs)
``````

This description enables generating digital circuit by compiling in vhdl or verilog language and than burn this in FPGA or in ASIC.

We begin by generating fir coeficients. For example by using python library scipy. There is also haskell library dsp that can do same.

``````>>> from scipy import signal as s
>>> s.firwin2(101,freq=[0,0.5,0.55,1],gain=[1,1,1e-5,1e-5],nfreqs=1024).tolist()
``````

this generates 101 fir coefficient-s with gain 1 in interval [0,0.55] and gain 1e-5 in interval [0.55,1] where interval represents Nyquist frequency. Nyquist frequency is frequency scaled from 0 to 1/2 of sampling frequency.

``````firCoef = -6.478374934754401e-05 :> 6.739792048055188e-05 :> 5.077367641329531e-05 :> -7.20036873194064e-05 :> -3.7245153312760294e-05 :> 7.249856664305871e-05 :> 2.2414720687380852e-05 :> -6.155684145140234e-05 :> -7.664810105984746e-06 :> 2.85804248573473e-05 :> -3.6152309490646324e-08 :> 3.86526486767599e-05 :> -1.4006284245813091e-05 :> -0.00015120836046040963 :> 7.361032727845754e-05 :> 0.0003152579566734551 :> -0.00021195524189591408 :> -0.0005277210648487832 :> 0.0004703572783638681 :> 0.0007717574734980716 :> -0.0008954627919597703 :> -0.001012627857164383 :> 0.0015349575580967327 :> 0.0011943982184525286 :> -0.002432123228258949 :> -0.0012377957439342097 :> 0.0036197818250699866 :> 0.0010392111520942885 :> -0.005114324388627113 :> -0.0004703430147278584 :> 0.00691059332253219 :> -0.0006228059544207712 :> -0.008978362677236961 :> 0.0024241985527292402 :> 0.011261032711201649 :> -0.005160469774066745 :> -0.013676935125896208 :> 0.00913292632920996 :> 0.016123357472055417 :> -0.014794308598846265 :> -0.01848307417265467 :> 0.02293937546874407 :> 0.02063285839843857 :> -0.03523405731548666 :> -0.022453185292383104 :> 0.05602454640129296 :> 0.02383815920968249 :> -0.10138553138188472 :> -0.024704631737024998 :> 0.3167115011351708 :> 0.5250045350057191 :> 0.3167115011351717 :> -0.024704631737024647 :> -0.10138553138188545 :> 0.023838159209682245 :> 0.05602454640129442 :> -0.02245318529238117 :> -0.03523405731548606 :> 0.020632858398438054 :> 0.02293937546874406 :> -0.018483074172654032 :> -0.014794308598846393 :> 0.01612335747205424 :> 0.009132926329209059 :> -0.013676935125896086 :> -0.005160469774066614 :> 0.011261032711201845 :> 0.002424198552728965 :> -0.008978362677237601 :> -0.0006228059544210945 :> 0.006910593322532333 :> -0.0004703430147276999 :> -0.005114324388627051 :> 0.0010392111520945455 :> 0.0036197818250703288 :> -0.001237795743934232 :> -0.0024321232282593064 :> 0.0011943982184523566 :> 0.0015349575580969096 :> -0.0010126278571641848 :> -0.0008954627919598041 :> 0.000771757473497906 :> 0.00047035727836372234 :> -0.0005277210648488565 :> -0.0002119552418958731 :> 0.0003152579566736044 :> 7.361032727858147e-05 :> -0.0001512083604604247 :> -1.4006284245899888e-05 :> 3.865264867673136e-05 :> -3.6152309459163916e-08 :> 2.8580424857355213e-05 :> -7.66481010600899e-06 :> -6.15568414514097e-05 :> 2.24147206873927e-05 :> 7.249856664305469e-05 :> -3.724515331277384e-05 :> -7.200368731939395e-05 :> 5.0773676413330495e-05 :> 6.739792048057118e-05 :> -6.478374934755455e-05 :> Nil
``````

We define our circuitry as

``````firCircuit x = fir firCoef x
``````

Result of calculating response of circuit firCircuit can be presented as following graph x axis represent frequency from 0 to Nyquist frequency and y is gain in dB. More details regarding ploting is available in testing code example available at github.

### Details

Analysis can be precisely performed on acyclic circuits for both linear and some nonlinear systems. By applying iterations it is possible to analyze also cyclic circuits. Only restriction is that circutry is defined by input type that is both `Num` and `Prependable`. Prepend is using polymorphic version of register called prepend.

Naive idea I started to work from is, that we push inside signal of complex numbers. Addition is addition of complex numbers and similar for multiplication. This should work fine at least for linear circuits.

Cyclic circuits can be are analyzed getting more values from output stream and waiting for result to converge. It works for analyzing iir filters.

For mixing/nonlinear circuits multiplication of spectrum is needed. Multiplying two `sin` functions is expressed as following identity.

``````sin(a) * sin(b) = 1/2 (cos(a-b) - cos(a+b))
``````

or when dealing in single frequency we get.

``````sin(x + a) * sin(x + b) ==
1/2 (cos(a - b) - cos(2x + a + b)) ==
1/2 (sin(a - b + pi/2) - sin(2x + a + b + pi/2))
``````

Multiplying two signals on same frequency one with phase a and other with phase b results in signal decomposed in DC components and other with signal having double frequency.

Haskell type that holds phases on multiple harmonics can be `Map Int (Complex Double)` Where `Int` represents harmonics and `Complex Double` size and phase of a signal at that harmonics frequency. In general `Num` class is needed for such type. That are function `+` `-` and `*`.

#### acyclic circuits

What remains for such system is phase rotation. When we delay signal using register, we need to tell register how to delay input spectrum.

If circuit is acyclic, single value wrapped in type `AnalyzerAcyclic` is enough for exact analysis. This represents type of input stream and is type used as input and output of circuit.

``````data AnalyzerAcyclic s =
AnalyzerAcyclic {unAnalyzerAcyclic :: (Maybe (s -> s) , s)}
``````

First type `Maybe (s -> s)` is spectrum transfer function. `s -> s` is function for rotating input used by `registerP` function is wrapped in `Maybe`, because instances of `AnalyzerAcyclic` for example `fromInteger` and `fromRational` are unable to provide better than value `Nothing`. For example function `(+)` requires forwarding valid transform function as output. Second type `s` is input spectrum for example `Map Int (Complex Double)` and represents amplitudes and phases on all harmonics frequencies.

#### cyclic circuits

Simple example of cyclic circuit would be

``````integrator sig = r where
r = registerP 0 r + sig
``````

registerP is polymorphic version of register called prepend from class Prepenable with origin from prevous post and lack of theoretical foundations. Some care is required to avoid bottom or infinite loop that would happen using `AnalyzerAcyclic`.

Current solution is that stream is used as input. In output stream we wait for values to converge. Type that works for our case is.

``````data Analyzer s = Analyzer {unAnalyzer :: ([Maybe (s -> s)] , Signal s)}
``````

First value `[Maybe (s -> s)]` is list of spectrum transfer functions, that is function that rotates input signal when register is reached. Second type `Signal s` is stream of spectrum. For `registryP` is required to retrieve spectrum transformation in breadth-first order. Traversing to spectrum rotate function `s -> s` in depth first order, would halt evaluation and would reach bottom.

For this type we need to implement `Ǹum` instance.

Example of `+` is.

``````da + db = FreqAn (zipWith (<|>) fa fb, liftA2 (+) a b) where
(fa,a) = unFreqAn da
(fb,b) = unFreqAn db
``````

That is, spectrum transfer function is generated by merging two spectrum transfer functions one from argument `da` and other from `db` input. Addition is done trough Applicative instance of underlaying input type that needs to be instance of `Applicative`.

### What next

Experimental library and some playground code in test.hs is available at github. It is not yet clear how to make `Functor` and `Applicative` instance of `Analyzer` and family. Also Prependable typclass as used here and previously to describe parallel circuits seems nice and useful, but has no theoretical foundations I am aware of and for extra only law it I came up with is broken in implementation of AnalyzerAcyclic. It is not clear what kind of nonlinear circuits beside frequency mixers are possible to analyze using such approach. There is missing bunch of utility functions and overall many questions remains open.

Fell free to reach me over git or irc at irc.freenode.com. I am hanging on channels #haskell and #clash-lang under nick ralu but you can also send mails on address starting with luka and ending with name of this domain.