I wanted To explain to students how a Lock-In amplifier works. The best way is to simulate the behaviour of one. However, in my program, I get unexpected behaviour, which I suspect has to do with numerics.
The way a Lock-In works is that you multiply a sine-wave signal (generator) that is noisy with another sine-wave (mixer) with the same frequency. This gives you a constant at half the amplitude plus one signal at double the frequency (addition of two sin-waves). You then filter this product signal with a low pass filter, which should give you the DC-signal without the noise, which corresponds to the quantity you are interested in. The filter should suppress signals at high frequencies, but it does not in my implementation.
(*frequency*)
υ := 100;
ϕ := 0;
A := 1;
period := 0.1;
step := 0.00001;
noiselevel := 1;
samrate := 100000;
generator[t_] := A*Cos[2*Pi* t *υ];
mixer[t_] := Cos[2 π t (υ + ϕ) ];
(*noisy data*)
dataprop := Table[RandomReal[NormalDistribution[generator[t], 1]], {t, 0, period,
step}]; ListPlot[dataprop]
(*generating a sine-wave table and mixing, eg. multiplying it*)
mixertable := Table[N[mixer[t]], {t, 0, period, step}];
muxi := dataprop*mixertable;
ListPlot[muxi]
(*the filter, a simple low pass one, the smaller a the stronger/slower the filter *)
a := 0.001;
filtered := RecurrenceTable[{smooth[i] ==
smooth[i - 1] + a*(muxi[[i]] - smooth[i - 1]), smooth[1] == muxi[[1]]},
smooth, {i, 1, Length[muxi]}];
ListPlot[filtered, PlotRange -> All]
In this plot you can see that despite the filter there is a periodic signal in the output of the filter at 2x the frequency. If you take the Fourier transform you can see the it is at 200Hz.
Periodogram[filtered, FourierParameters -> {1, -1},
SampleRate -> samrate, PlotRange -> {{0, 1000}, {0, 80}},
ScalingFunctions -> "dB"]
If you write the same code in Python the ripple at 200Hz is not there. See here same program in Python
muxi[[i]]
when I use it - instead useFoldList[#1 + a*(#2 - #1) &, First[muxi], muxi];
$\endgroup$Fold
are equivalent toExponentialMovingAverage[muxi, a]
. But I'd recommend usingLowpassFilter
instead. Also it makes sense that the wave would have a spike at 2x the frequency because $\cos^2(x) = (\cos (2 x)+1)/2$. You should account for this effect by writingSampleRate->samrate/2
in yourPeriodogram
. $\endgroup$FoldList[]
gets rid of the error. I believe thatExponentialMovingAverage[muxi,a]
is exactly the same filter. However, the oscillations in the output persist. I believe they should not be there, as in the Python code these oscillations are not there. I ended up trying the Python example, as I did not understand what is going on. $\endgroup$100
, the period there is1
, while you chooseperiod=0.1
. Just choose\[Upsilon] := 1000;
, the output of Mathematica will be similar to that of Python. BTW, you're generating the noisy data in an unusual way (it doesn't significantly influence the result though), how do you figure out this undocumented syntax ofRandomReal
(Seems to be equivalent toRandomVariate
)? $\endgroup$