Author Topic: Homebrew Lock-In Amplifier  (Read 10332 times)

0 Members and 1 Guest are viewing this topic.

Offline RoGeorge

  • Super Contributor
  • ***
  • Posts: 6381
  • Country: ro
Re: Homebrew Lock-In Amplifier
« Reply #25 on: May 02, 2024, 06:08:17 am »
About experiments that can be performed, I always wanted to try this one, too.  ;D
Not to spy, but to see if it really is possible. 



First time seen such setup in a movie, with a surveillance van spying on some important figures with an infra-red laser, when somebody from the surveilled room sees the laser spot by looking through red wine.  I would like to see the eavesdropping scene again, to figure it if it was possible at all to hear dialogues from the glass vibrations of a window.  Anybody happens to know the title of that movie?



Back to LIA,

AD8422 amplifier ... to use it along with a microcontroller to make a milliohm meter

That would be a good start.  For PCB trace and finding short-circuited capacitors (MLCC that decouples the power traces often fails as a solid short-circuit, hard to detect since the power traces are thich, and often there are many capacitors in parallel), Jaromir's audible "Shorty" is a very useful tool (from a practical standpoint, not as an accurate miliohm-meter).



Somebody here added a digital display to it:  https://www.eevblog.com/forum/testgear/finding-short-on-motherboards-with-a-shorty-(with-display)/



If the LIA project is mostly to learn/experiment with electronics ideas, then the poly phase mixer (AKA N-path filter) can work too as a synchronous mixer, and might be easier to build:
N path filters: basics & demo - icdutwentenl



If you just need a LIA for physics experiments in general, then it might be cheaper to hunt for a second hand instrument made by Standford Research or by some other brand name.

Saying this because the analog part is hard to do in DIY regime, and even if you manage to somehow build one with similar performance as a commercial LIA, that build would cost you much more than a second hand LIA (aside from a serious time investment).
« Last Edit: May 02, 2024, 06:14:04 am by RoGeorge »
 

Offline zrq

  • Frequent Contributor
  • **
  • Posts: 295
  • Country: 00
Re: Homebrew Lock-In Amplifier
« Reply #26 on: May 02, 2024, 08:44:53 am »
Is this "listening device" idea can be achieved by a laser doppler vibrometer? The bistatic idea in the figure also looks plasuable. I was also interested in it but still, no time to look into it and form a project.
 

Offline PicuinoTopic starter

  • Frequent Contributor
  • **
  • Posts: 975
  • Country: 00
    • Picuino web
Re: Homebrew Lock-In Amplifier
« Reply #27 on: May 02, 2024, 09:27:51 am »
Also from Analog Devices:  AN-306, Synchronous System Measures \$\mu\$\$\Omega\$s
https://www.analog.com/media/en/technical-documentation/application-notes/AN-306.pdf
Something like that I want to do, but with a square signal coming from a microcontroller and the decoding done in the same microcontroller so that it can send the readings by UART to a PC.

The decoding I am preparing does the following:
 * Outputs a 1kHz output signal on one pin of the uC.
 * Takes 10000 ADC readings per second, synchronized with the output signal (5 readings per level).
 * Adds up all the ADC readings in an A register.
 * Adds or subtracts the ADC readings according to the output signal in a B register.
 * After 1024 output edges it averages the A register (average input level or DC signal) and averages the B register (reading of the input signal variation or resistance).
« Last Edit: May 02, 2024, 09:33:29 am by Picuino »
 

Offline Kleinstein

  • Super Contributor
  • ***
  • Posts: 14367
  • Country: de
Re: Homebrew Lock-In Amplifier
« Reply #28 on: May 02, 2024, 09:44:08 am »
For a µOhms measurement one usually wants a relatively low frequency. So not so much 1 kHz but more like 10 Hz. At 1 kHz one has a good chance to already get some effect from the inductance. One can separate it from the phase, but this requires the amplifier to not have extra phase shift.

For this application the digital version makes absolute sense.
 

Offline PicuinoTopic starter

  • Frequent Contributor
  • **
  • Posts: 975
  • Country: 00
    • Picuino web
Re: Homebrew Lock-In Amplifier
« Reply #29 on: May 02, 2024, 09:54:24 am »
Although the synchronization is a software problem, it should not be too complicated to change the working frequency and check the effect it has.

I am concerned about several effects:
 * That it does not measure the mains signal (50Hz or harmonics).
 * That it does not measure the 1kHz (or less) injected signal itself through the grounds or through induction on the test leads.
 * The test leads should be in 4-wire (Kelvin) configuration, of course, but there is always a small point where they should be joined and considering how sensitive the device can be I will have to be especially careful about this.

Until I assemble the prototype I cannot test and check these effects.
 

Offline PicuinoTopic starter

  • Frequent Contributor
  • **
  • Posts: 975
  • Country: 00
    • Picuino web
Re: Homebrew Lock-In Amplifier
« Reply #30 on: May 02, 2024, 10:01:13 am »
For a µOhms measurement one usually wants a relatively low frequency. So not so much 1 kHz but more like 10 Hz. At 1 kHz one has a good chance to already get some effect from the inductance. One can separate it from the phase, but this requires the amplifier to not have extra phase shift.

For this application the digital version makes absolute sense.

I could also add and subtract in another variable C the ADC measurement 90º out of phase with respect to the reference signal, in order to measure the self-inductance of the resistor, comparing both measurements (B without phase and C with 90º phase).

I leave it as an extension to the project.
 

Offline PicuinoTopic starter

  • Frequent Contributor
  • **
  • Posts: 975
  • Country: 00
    • Picuino web
Re: Homebrew Lock-In Amplifier
« Reply #31 on: May 02, 2024, 10:18:32 am »
RoGeorge:

Thanks for the links, I hadn't seen your post with the forum page change.
The idea I have is to experiment with the components and learn. Yes, for more serious experiments it is best to buy a second hand LIA.

The "Shorty" looks like quite a useful device, I didn't know it, thanks.
https://hackaday.io/project/3635-shorty-short-circuit-finder
https://www.eevblog.com/forum/testgear/finding-short-on-motherboards-with-a-shorty-(with-display)/

My idea is to be able to measure the milliohms with a numerical value. I want to use it for printed circuit boards and for screw connections (terminals). It may also be useful in other occasions.
My Agilent 34401A can do those measurements without a problem anyway, so measuring milliohms is not a real need. I want to experiment with the concept of synchronous measurement, which I have never used before.
« Last Edit: May 02, 2024, 10:37:35 am by Picuino »
 

Offline PicuinoTopic starter

  • Frequent Contributor
  • **
  • Posts: 975
  • Country: 00
    • Picuino web
Re: Homebrew Lock-In Amplifier
« Reply #32 on: May 02, 2024, 06:43:58 pm »
While the order for low noise amplifiers is coming in, I have been experimenting with a Microchip MCP6N11-10.
https://ww1.microchip.com/downloads/en/DeviceDoc/25073A.pdf

Attached is the schematic I have mounted on a prototyping board to measure small resistors.

The program for the Arduino nano is as follows:

Code: [Select]
/*

   Copyright 2024 Picuino

   Permission is hereby granted, free of charge, to any person obtaining a copy
   of this software and associated documentation files (the "Software"), to deal
   in the Software without restriction, including without limitation the rights
   to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
   copies of the Software, and to permit persons to whom the Software is
   furnished to do so, subject to the following conditions:

   The above copyright notice and this permission notice shall be included
   in all copies or substantial portions of the Software.

   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
   IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
   AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
   LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
   FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
   IN THE SOFTWARE.

*/

const int PIN_VDD_OPAMP = 6;
const int PIN_PWM_OUT = 3;
const int PIN_ANALOG = A0;

const int SAMPLES_PER_EDGE = 80;
const int EDGES_PER_MEASURE = 5000 / SAMPLES_PER_EDGE;

volatile unsigned int adc_value;
volatile unsigned char adc_on;
volatile long adc_sum;
volatile unsigned int adc_samples;
volatile unsigned char timer0_state;

void setup() {
  Serial.begin(9600);

  // Power up instrumentation amplifier
  pinMode(PIN_VDD_OPAMP, OUTPUT);
  digitalWrite(PIN_VDD_OPAMP, HIGH);

  // Set up output reference signal pin
  pinMode(PIN_PWM_OUT, OUTPUT);
  setup_timer0();

  // Set up ADC
  setup_adc();

  // Main Loop
  float resistance;
  adc_on = 0;
  adc_sum = 0;
  adc_samples = 0;
  timer0_state = 0;
  adc_on = 1;
  for (;;) {
    if (adc_samples > SAMPLES_PER_EDGE * EDGES_PER_MEASURE * 2) {
      adc_on = 0;
      if (adc_sum < 0)
        adc_sum = 0;
      resistance = adc_sum;
      resistance = resistance * (1.0 / (SAMPLES_PER_EDGE * EDGES_PER_MEASURE));
      Serial.println(resistance);
      adc_sum = 0;
      adc_samples = 0;
      timer0_state = 0;
      adc_on = 1;
    }
  }
}

void loop() {}

void setup_adc(void) {
  analogRead(PIN_ANALOG);
  cli(); //stop interrupts

  ADMUX = (1 << 6) | (0 << ADLAR);
  ADCSRA = (1 << ADEN) | (0 << ADSC) | (0 << ADATE) | (0 << ADIE) | (0b111);
  ADCSRB = 0x00;

  sei(); //allow interrupts
}


void setup_timer0(void) {
  cli(); //stop interrupts

  //set timer0 interrupt at 2kHz
  TCCR0A = 0; // set entire TCCR2A register to 0
  TCCR0B = 0; // same for TCCR2B
  TCNT0  = 0; //initialize counter value to 0
  // set compare match register
  OCR0A = 26; //  f = 16000000 / ((OCR0A + 1) * 64) = 9259 Hz
  // turn on CTC mode
  TCCR0A |= (1 << WGM01);
  // Set CS01 and CS00 bits for 64 prescaler
  TCCR0B |= (1 << CS01) | (1 << CS00);
  // enable timer compare interrupt
  TIMSK0 |= (1 << OCIE0A);

  sei(); //allow interrupts
}


ISR(TIMER0_COMPA_vect) {
  if (adc_on) {

    // ADC manage
    adc_value = (ADCL | (ADCH << 8));
    if (adc_samples > 0) {
      if (timer0_state < SAMPLES_PER_EDGE) {
        adc_sum -= adc_value;
      }
      else {
        adc_sum += adc_value;
      }
    }

    ADCSRA |= (1 << ADSC);  // ADC Start Conversion
    adc_samples++;
    delayMicroseconds(12);  // Wait for Sample and Hold

    // Update next state
    if (++timer0_state >= (SAMPLES_PER_EDGE * 2)) {
      timer0_state = 0;
    }

    // Update output reference signal
    if (timer0_state < SAMPLES_PER_EDGE) {
      PORTD |= (1 << PIN_PWM_OUT);
    }
    else {
      PORTD &= ~(1 << PIN_PWM_OUT);
    }
  }
}

The first problem I am encountering is that the output signal from the amplifier (Vout) has little noise but a lot of variation between high and low level.
On the oscilloscope I measure variations from 0.50V to 0.58V in the amplified square wave.

Attached is the wave of Vout.


Measures sended by Arduino Nano board (with a lot of noise):
Code: [Select]
113.42
113.01
113.09
113.11
107.85
114.78
115.18
115.32
109.24
107.46
109.21
112.78
107.72
109.01
113.22
107.68
109.41
113.01
113.54
113.30
113.22
107.67
109.30
113.46
113.24
113.34
113.62
113.48
113.36
113.14
113.08
107.76
114.96
114.58
115.14
115.06
115.22
114.90
115.05
114.92
114.90
« Last Edit: May 02, 2024, 06:51:57 pm by Picuino »
 

Offline PicuinoTopic starter

  • Frequent Contributor
  • **
  • Posts: 975
  • Country: 00
    • Picuino web
Re: Homebrew Lock-In Amplifier
« Reply #33 on: May 02, 2024, 07:07:16 pm »
Averaging input with the scope, the signal looks better.

 

Offline Kleinstein

  • Super Contributor
  • ***
  • Posts: 14367
  • Country: de
Re: Homebrew Lock-In Amplifier
« Reply #34 on: May 02, 2024, 07:19:19 pm »
The code may have a problem with identifying the output state for the last sample of one type. The ADC reading is done with the old settings and the check for the math is with the updates counter, so 1 reading that is used wrong.

With the current setting one a rather small part of the ADC range is actually used. One may wand some DC shift or AC coupling.
 

Offline PicuinoTopic starter

  • Frequent Contributor
  • **
  • Posts: 975
  • Country: 00
    • Picuino web
Re: Homebrew Lock-In Amplifier
« Reply #35 on: May 02, 2024, 08:15:45 pm »
New program with continuous sampling:

Code: [Select]
/*

   Copyright 2024 Picuino

   Permission is hereby granted, free of charge, to any person obtaining a copy
   of this software and associated documentation files (the "Software"), to deal
   in the Software without restriction, including without limitation the rights
   to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
   copies of the Software, and to permit persons to whom the Software is
   furnished to do so, subject to the following conditions:

   The above copyright notice and this permission notice shall be included
   in all copies or substantial portions of the Software.

   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
   IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
   AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
   LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
   FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
   IN THE SOFTWARE.

*/

const int PIN_VDD_OPAMP = 6;
const int PIN_PWM_OUT = 3;
const int PIN_ANALOG = A0;

const int SAMPLES_PER_EDGE = 80;
const int EDGES_PER_MEASURE = 5000 / SAMPLES_PER_EDGE;

volatile long adc_sum;
volatile long adc_result;
volatile unsigned int adc_value;
volatile unsigned int adc_samples;
volatile unsigned char timer0_state;
volatile unsigned char output_edge;
volatile unsigned char adc_measure_end;



void setup() {
  Serial.begin(9600);

  // Power up instrumentation amplifier
  pinMode(PIN_VDD_OPAMP, OUTPUT);
  digitalWrite(PIN_VDD_OPAMP, HIGH);

  // Set up output reference signal pin
  pinMode(PIN_PWM_OUT, OUTPUT);
  setup_timer0();

  // Set up ADC
  setup_adc();

  // Main Loop
  float resistance;
  adc_sum = 0;
  adc_samples = 0;
  timer0_state = 0;
  for (;;) {
    if (adc_measure_end == 1) {
      adc_measure_end = 0;
      resistance = adc_result;
      resistance = resistance * (1.0 / (SAMPLES_PER_EDGE * EDGES_PER_MEASURE));
      Serial.println(resistance);
    }
  }
}

void loop() {}

void setup_adc(void) {
  analogRead(PIN_ANALOG);
  cli(); //stop interrupts

  ADMUX = (1 << 6) | (0 << ADLAR);
  ADCSRA = (1 << ADEN) | (0 << ADSC) | (0 << ADATE) | (0 << ADIE) | (0b111);
  ADCSRB = 0x00;

  sei(); //allow interrupts
}


void setup_timer0(void) {
  cli(); //stop interrupts

  //set timer0 interrupt at 2kHz
  TCCR0A = 0; // set entire TCCR2A register to 0
  TCCR0B = 0; // same for TCCR2B
  TCNT0  = 0; //initialize counter value to 0
  // set compare match register
  OCR0A = 26; //  f = 16000000 / ((OCR0A + 1) * 64) = 9259 Hz
  // turn on CTC mode
  TCCR0A |= (1 << WGM01);
  // Set CS01 and CS00 bits for 64 prescaler
  TCCR0B |= (1 << CS01) | (1 << CS00);
  // enable timer compare interrupt
  TIMSK0 |= (1 << OCIE0A);

  sei(); //allow interrupts
}


ISR(TIMER0_COMPA_vect) {
  // ADC manage
  adc_value = (ADCL | (ADCH << 8));
  if (output_edge == 1) {
    adc_sum -= adc_value;
  }
  if (output_edge == 0) {
    adc_sum += adc_value;
  }

  ADCSRA |= (1 << ADSC);  // ADC Start Conversion
  adc_samples++;
  delayMicroseconds(12);  // Wait for Sample and Hold

  // Update next state
  if (++timer0_state >= (SAMPLES_PER_EDGE * 2)) {
    timer0_state = 0;
  }

  // Update output reference signal
  if (timer0_state < SAMPLES_PER_EDGE) {
    PORTD |= (1 << PIN_PWM_OUT);
    output_edge = 1;
  }
  else {
    PORTD &= ~(1 << PIN_PWM_OUT);
    output_edge = 0;
  }

  // Take one measure after several samples
  if (adc_samples > SAMPLES_PER_EDGE * EDGES_PER_MEASURE * 2) {
    adc_measure_end = 1;
    adc_result = adc_sum;
    adc_sum = 0;
    adc_samples = 0;
  }

}

Same error in the measurements:
Code: [Select]
112.91
113.61
112.85
112.79
112.99
113.02
112.92
112.65
112.78
112.89
113.14
112.81
112.90
112.59
112.80
112.54
112.44
112.39
112.34
112.19
112.12
111.70
111.89
111.71
112.10
111.82
111.44
111.78
111.46
111.78
112.02
112.03
111.91
112.08
112.20
111.95
112.28
112.41
112.53
112.73
112.37
112.36
112.54
112.75
112.59
112.38
112.94
113.09
112.98
112.76
113.23
112.77
113.00
112.72
112.96
113.23
112.65
112.76
112.94
112.90
113.11
113.01
112.76
112.87
112.77
112.61
112.98
112.77
112.94
113.08
112.88
113.07
113.01
113.13
112.89
112.93
112.65
113.11
113.20
112.97
113.52
113.30
113.30
113.43
113.32
113.28
113.13
113.18
113.41
113.34
113.38
113.09
113.43
113.25
113.19
112.89
113.00
113.11
113.27
113.19
113.12
113.22
113.20
112.81
113.31
112.92
113.22
 

Offline Kleinstein

  • Super Contributor
  • ***
  • Posts: 14367
  • Country: de
Re: Homebrew Lock-In Amplifier
« Reply #36 on: May 02, 2024, 08:26:15 pm »
The new data look a lot less noisy. Especially the consecutive readings are relatively similar. There is a chance to have some thermal variations if the actual signal or amplifier gain.
 

Offline PicuinoTopic starter

  • Frequent Contributor
  • **
  • Posts: 975
  • Country: 00
    • Picuino web
Re: Homebrew Lock-In Amplifier
« Reply #37 on: May 03, 2024, 04:23:12 pm »
I have made several changes to the software and have filtered with resistors and capacitors the MCP6N11 power supply trying to make the measurements more stable and they don't seem to improve anymore:

Code: [Select]
/*
   Copyright 2024 Picuino

   Permission is hereby granted, free of charge, to any person obtaining a copy
   of this software and associated documentation files (the "Software"), to deal
   in the Software without restriction, including without limitation the rights
   to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
   copies of the Software, and to permit persons to whom the Software is
   furnished to do so, subject to the following conditions:

   The above copyright notice and this permission notice shall be included
   in all copies or substantial portions of the Software.

   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
   IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
   AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
   LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
   FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
   IN THE SOFTWARE.
*/

const int PIN_PWM_OUT = 3;
const int PIN_ANALOG = A0;

const int SAMPLES_PER_EDGE = 80;
const int EDGES_PER_MEASURE = 5000 / SAMPLES_PER_EDGE;

volatile long adc_sum;
volatile unsigned int adc_enable;
volatile unsigned int adc_value;
volatile unsigned int adc_samples;
volatile unsigned char timer0_state;
volatile unsigned char output_level;
volatile unsigned char output_level_old;
volatile unsigned char adc_measure_end;


void setup() {
  Serial.begin(9600);

  // Set up output reference signal pin
  pinMode(PIN_PWM_OUT, OUTPUT);
  timer0_setup();

  // Set up ADC
  adc_setup();

  // Main Loop
  float resistance;
  adc_init();
  for (;;) {
    if (adc_measure_end == 1) {
      resistance = adc_sum;
      resistance = resistance * (1.0 / (SAMPLES_PER_EDGE * EDGES_PER_MEASURE));
      Serial.println(resistance);
      adc_init();
    }
  }
}

void loop() {}


void adc_init(void) {
  adc_measure_end = 0;
  adc_sum = 0;
  timer0_state = 0;
  adc_samples = 0;
  PORTD |= (1 << PIN_PWM_OUT);
  output_level = 1;
  output_level_old = 1;
  delayMicroseconds(200);
  adc_enable = 1;
}


void adc_setup(void) {
  analogRead(PIN_ANALOG);
  cli(); //stop interrupts

  ADMUX = (1 << 6) | (0 << ADLAR);
  ADCSRA = (1 << ADEN) | (0 << ADSC) | (0 << ADATE) | (0 << ADIE) | (0b111);
  ADCSRB = 0x00;

  sei(); //allow interrupts
}


void timer0_setup(void) {
  cli(); //stop interrupts

  //set timer0 interrupt at 2kHz
  TCCR0A = 0; // set entire TCCR2A register to 0
  TCCR0B = 0; // same for TCCR2B
  TCNT0  = 0; //initialize counter value to 0
  // set compare match register
  OCR0A = 26; //  f = 16000000 / ((OCR0A + 1) * 64) = 9259 Hz
  // turn on CTC mode
  TCCR0A |= (1 << WGM01);
  // Set CS01 and CS00 bits for 64 prescaler
  TCCR0B |= (1 << CS01) | (1 << CS00);
  // enable timer compare interrupt
  TIMSK0 |= (1 << OCIE0A);

  sei(); //allow interrupts
}


ISR(TIMER0_COMPA_vect) {

  if (adc_enable) {

    if (adc_samples) {
      // Read ADC measure
      adc_value = (ADCL | (ADCH << 8));

      // Add measure to accumulator
      if (output_level_old == 1) {
        adc_sum -= adc_value;
      }
      if (output_level_old == 0) {
        adc_sum += adc_value;
      }
    }

    // ADC Start Conversion
    ADCSRA |= (1 << ADSC);
    adc_samples++;
    delayMicroseconds(12);  // Wait for Sample and Hold
    output_level_old = output_level;

    // Update next state
    if (++timer0_state >= (SAMPLES_PER_EDGE * 2)) {
      timer0_state = 0;
    }

    // Update output reference signal
    if (timer0_state < SAMPLES_PER_EDGE) {
      PORTD |= (1 << PIN_PWM_OUT);
      output_level = 1;
    }
    else {
      PORTD &= ~(1 << PIN_PWM_OUT);
      output_level = 0;
    }

    // Take one measure after several samples
    if (adc_samples > SAMPLES_PER_EDGE * EDGES_PER_MEASURE * 2) {
      adc_measure_end = 1;
      adc_enable = 0;
    }
  }
}


Output measures:
Code: [Select]
84.22
84.49
84.40
84.42
84.47
84.18
84.47
84.45
84.26
84.09
84.23
84.36
83.79
84.15
83.90
84.02
83.97
84.12
84.11
83.96
83.67
84.02
84.06
84.05
84.36
83.81
83.97
83.95
83.90
83.93
84.06
83.98
83.81
84.08
83.78
83.95
83.70
83.55
83.75
83.99
83.78
83.83
83.71
83.64
83.53
83.67
83.67
83.73
83.44
83.67
83.65
83.80
83.46
83.63
83.67
83.30
83.47
83.51
83.80
83.43
83.64

The real resistance under test is, more or less, R_ut = 0.4 Ohms.

The signal in Vout have an amplitude of 430mV = 88 dots of ADC

 

Offline PicuinoTopic starter

  • Frequent Contributor
  • **
  • Posts: 975
  • Country: 00
    • Picuino web
Re: Homebrew Lock-In Amplifier
« Reply #38 on: May 03, 2024, 04:29:24 pm »
It seems that making many measurements simply removes some of the noise, but it is not able to give more resolution than the ADC itself would give with just a couple of measurements.
The principle of extracting more information buried in the noise doesn't seem to work in this circuit.
I would have to prototype with soldering to be 100% sure. But I don't think I would gain much. I would expect to get at least one decimal place more accuracy than the ADC itself gives.
 

Offline PicuinoTopic starter

  • Frequent Contributor
  • **
  • Posts: 975
  • Country: 00
    • Picuino web
Re: Homebrew Lock-In Amplifier
« Reply #39 on: May 03, 2024, 04:44:51 pm »
I can't find the “Shorty” software to study its operation.
The original link is broken:
+ https://hackaday.io/project/3635-shorty-short-circuit-finder
+ https://github.com/jaromir-sukuba/shorty/blob/master/fw/shorty.ino  (Link to firmware)

Where can I get it?
Can someone upload it?
 

Offline RoGeorge

  • Super Contributor
  • ***
  • Posts: 6381
  • Country: ro
Re: Homebrew Lock-In Amplifier
« Reply #40 on: May 03, 2024, 05:15:20 pm »
I've took a peek at the other shorty with display, from kripton2035 links/pages, has sources:
http://kripton2035.free.fr/Continuity%20Meters/continuity-short.html
http://kripton2035.free.fr/Resources/shorty.ino

Offline PicuinoTopic starter

  • Frequent Contributor
  • **
  • Posts: 975
  • Country: 00
    • Picuino web
Re: Homebrew Lock-In Amplifier
« Reply #41 on: May 03, 2024, 05:17:39 pm »
After checking that the signal coming out of the Arduino (D3) is quite noisy, I connected the output to a BC557 PNP transistor to turn resistor R1 on and off at Vcc.
The result is a signal on R1 with much less noise, but the amplified signal is still quite noisy.

The problem I think is in the 3.3V reference voltage. I will have to generate it myself from the outside, because the one the Arduino delivers, even filtering it, doesn't get rid of having enough noise.
« Last Edit: May 03, 2024, 05:21:23 pm by Picuino »
 

Offline PicuinoTopic starter

  • Frequent Contributor
  • **
  • Posts: 975
  • Country: 00
    • Picuino web
Re: Homebrew Lock-In Amplifier
« Reply #42 on: May 03, 2024, 05:19:22 pm »
I've took a peek at the other shorty with display, from kripton2035 links/pages, has sources:
http://kripton2035.free.fr/Continuity%20Meters/continuity-short.html
http://kripton2035.free.fr/Resources/shorty.ino

I'm going to include the program in a post, just in case:

Code: [Select]
#include <avr/io.h>
#include <util/delay.h>

#ifndef F_CPU
#define F_CPU 12000000UL
#endif
#define _BAUD   9600              // Baud rate (9600 is default)
#define _UBRR  (F_CPU/16)/_BAUD - 1 // Used for UBRRL and UBRRH


#define  BUZZER_PORT PORTD
#define  BUZZER_DDR DDRD
#define  BUZZER 6

#define LED_TIMER_ON  500
#define LED_TIMER_MAX  550

unsigned int adc_val;
#define AVERAGE_SIZE 5
unsigned int adc_val_avg[AVERAGE_SIZE], adc_val_acc;
unsigned char adc_val_avg_ptr, i, probe_state;
unsigned int led_timer, led_;
unsigned int probe_timer;

int main (void)
{
  UBRR0H = ((_UBRR) & 0xF00);         // define speed
  UBRR0L = (uint8_t) ((_UBRR) & 0xFF);   // for serial uart
  UCSR0B |= _BV(TXEN0);
  UCSR0B |= _BV(RXEN0);

  DDRD &= ~(1 << DDD3);            // input en D3 button
  DDRD |= (1 << DDD6);          // output on D6 buzzer
  PORTD |= (1 << PORTD3);
  DDRC |= (1 << DDC3);          // analog output 3 for pnp seeding
  DDRB |= (1 << DDC5);          // analog input 5 for adc sampling
  PORTC &= ~(1 << PORTC3);
  OCR0A = 120;
  TCCR0A = 0x42;
  TCCR0B = 0x05;
  ADCSRA = (1 << ADEN) | (1 << ADPS2) | (1 << ADPS0);
  ADMUX = 0x45;
  //  ADMUX |= (1 << ADLAR); // Left adjust ADC result to allow easy 8 bit reading

  probe_timer = 0;
  led_timer = 0;
  probe_state = 1;

  while (1)
  {
    //if probe is active, blink a LED
    led_timer++;
    if ((led_timer > LED_TIMER_ON) & (probe_state == 1))
      PORTB |= (1 << 5);
    else
      PORTB &= ~(1 << 5);
    if (led_timer > LED_TIMER_MAX)
      led_timer = 0;

    //now decide, if the probe wasn't inactive for too long
    probe_timer++;
    if (probe_timer > 15000)
    {
      if (probe_state == 1)
        probe_state = 0;
    }

    //inactive probe code
    if (probe_state == 0)
    {
      PORTC |= (1 << PORTC3);      // change A3=1
      DDRD &= ~(1 << DDD6);     // stop buzzer D6
      _delay_ms(1);
      if ((PIND & (0x08)) == 0) // check D3 button state
      {
        probe_state = 1;     // reactivate device if button is pressed
        probe_timer = 0;
      }
    }

    //active probe code
    if (probe_state == 1)
    {
      PORTC &= ~(1 << PORTC3);    // turns off A3=0
      _delay_ms(1);

      //take adc sample
      ADCSRA |= (1 << ADSC);        // Start conversion
      while (ADCSRA & (1 << ADSC)); // wait for conversion to complete
      adc_val = ADCW;          // ADCL reads only the low byte (8bit) of the ADC conversion result and ADCH reads only the High byte.
      // ADC & ADCW are indeed the same

      //take value and put it into floating average
      adc_val_avg[adc_val_avg_ptr++] = adc_val;
      if (adc_val_avg_ptr > AVERAGE_SIZE) adc_val_avg_ptr = 0;
      adc_val_acc = 0;
      for (i = 0; i < AVERAGE_SIZE; i++)
        adc_val_acc = adc_val_acc + adc_val_avg[i];
      adc_val_acc = adc_val_acc / 20;
      adc_val = adc_val_acc;

      //decide what to do
      if (adc_val > 200) adc_val = 200;
      adc_val = adc_val + 2;
      if (adc_val < 200)
      {
        OCR0A = adc_val;       // The Output Compare Register A contains an 8-bit value that is continuously compared with the counter value (TCNT0)
        DDRD |= (1 << DDD6);      // turns on buzzer D6
        probe_timer = 0;
      }
      else
      {
        DDRD &= ~(1 << DDD6);     // turns off buzzer D6
      }                   // DDRD is the direction register for Port D (Arduino digital pins 0-7)
    }


  }

}
/*

  void usart_tx_b(uint8_t data)
  {
  while (!(UCSR0A & _BV(UDRE0)));
  UDR0 = data;
  }

  void usart_tx_hexa (uint8_t value)
  {
  uint8_t temp;
  temp = value;
  usart_tx_b('0');
  usart_tx_b('x');
  temp = ((temp>>4)&0x0F);
  if (temp<10) temp = temp + '0';
  else temp = temp + 'A'- 10;
  usart_tx_b(temp);
  temp = value;
  temp = ((temp>>0)&0x0F);
  if (temp<10) temp = temp + '0';
  else temp = temp + 'A' - 10;
  usart_tx_b(temp);
  usart_tx_b(' ');
  }
*/
 

Offline RoGeorge

  • Super Contributor
  • ***
  • Posts: 6381
  • Country: ro
Re: Homebrew Lock-In Amplifier
« Reply #43 on: May 03, 2024, 05:36:48 pm »
The problem I think is in the 3.3V reference voltage.

I don't recall AVR chips to have a 3.3V reference, so I guess the 3.3V reference is in fact the MCU Vcc.  Have you double check with the MCU datasheet, if it really has a 3.3V reference?

If your Arduino board is with a classic ATmega48, that MCU has an internal bandgap Vref.  Try using the 1.1V range (full scale) for the ADC.  That will use the internal Vref instead of Vcc as Vref.



I've tried to look at your source code, but when I've seen that 1 page of license written half in CAPS LOCK, i've give up and didn't read the code at all.  ;D

Offline Kleinstein

  • Super Contributor
  • ***
  • Posts: 14367
  • Country: de
Re: Homebrew Lock-In Amplifier
« Reply #44 on: May 03, 2024, 06:10:26 pm »
For a resistance measurement the current source / driving resistor should use the same reference voltage as the ADC. So in this case likely the supply.
 

Offline PicuinoTopic starter

  • Frequent Contributor
  • **
  • Posts: 975
  • Country: 00
    • Picuino web
Re: Homebrew Lock-In Amplifier
« Reply #45 on: May 03, 2024, 06:11:00 pm »
The 3.3 volt reference comes from an LDO regulator on the Arduino Nano board itself.
I replaced it with a follower op amp that amplifies a 4 volt resistive divider. It has much less noise than the Arduino's 3.3V reference, but the readings still vary much more than I expected.

The problem is that the amplified signal Vout has a lot of variation. The oscilloscope with 16-sample average input gives the following Vout values for the resistor I am testing now: from 187mV to 197mV amplitude.
 

Offline PicuinoTopic starter

  • Frequent Contributor
  • **
  • Posts: 975
  • Country: 00
    • Picuino web
Re: Homebrew Lock-In Amplifier
« Reply #46 on: May 03, 2024, 06:15:15 pm »
For a resistance measurement the current source / driving resistor should use the same reference voltage as the ADC. So in this case likely the supply.

Yes, I am using the 5V coming from a lab power supply to power the amplifier, the resistor R1 and the internal voltage reference of the ADC.
 

Offline PicuinoTopic starter

  • Frequent Contributor
  • **
  • Posts: 975
  • Country: 00
    • Picuino web
Re: Homebrew Lock-In Amplifier
« Reply #47 on: May 04, 2024, 08:49:47 am »
I replaced the MCP6N11 amplifier with a better one that I found in my SMD component book, the AD8220.
The results have improved.

Output measurements:
Code: [Select]
21.20
21.22
20.96
20.99
21.17
21.10
21.08
21.07
21.02
21.02
21.12
20.97
21.18
21.10
21.09
21.13
21.04
21.06
21.15
21.21
21.01
21.20
21.30
21.06
21.28
21.16
21.13
21.00
21.04
21.15
21.17
21.02
21.09
20.94
21.12
21.18
20.95
21.01
21.09
21.15
21.11
21.08
21.02
21.03
21.16
21.05
21.07
21.02
21.16
21.02
21.22
21.10
21.08
20.99
21.11
20.97
21.12
20.97
21.17
21.06
21.09
21.10
21.04
20.97
21.18
21.07
21.02
21.10
21.05
21.08
21.19
21.07
21.09
20.95
21.15
21.02
21.13
21.00
21.01
21.11
21.16
21.05
21.09
21.10
21.14
21.08
21.04
21.06
21.00
21.20
21.09
21.02
21.07
21.10
21.04
21.00
21.03
21.15
21.20
21.08
20.97
21.03
20.95
21.14
21.09
21.02
21.05
21.01
21.04
20.97
20.99
21.03
20.97
21.07
21.08
21.16
21.08
20.97
20.93
21.08
21.10
21.02
21.14
20.99
21.00
21.13
21.12
21.12
21.09
21.16
21.15
21.15
21.16
21.09
21.12
21.01
21.12
20.95
21.21
21.13
21.08
21.04
21.06
21.20
21.13
21.07
21.10
21.06
21.22
21.14
21.09
21.10
21.05
20.93
21.16
21.16
21.11
21.12
21.19
21.05
21.12
21.04
21.08
20.93
21.07
21.08
21.00
20.97
21.17
21.03
21.11
20.92
21.11
21.11
21.10
21.04
21.11
21.05
20.98
21.27
21.14
21.15
21.08
21.00
21.07
21.21
21.01
21.01
21.06
21.05
21.10
21.18
21.05
21.16
21.08
21.16
21.08
21.13
21.22
21.11
21.08
21.13
21.01
21.18
21.11
21.02
20.97
21.09
21.01
21.22
21.10
21.08
21.04

I have added a calibration value to the program so that the results are measured in milliohms. In this case it is measuring about 20 milliohms from a small wire about 20cm long.


Arduino code:
Code: [Select]
/*
   Copyright 2024 Picuino

   Permission is hereby granted, free of charge, to any person obtaining a copy
   of this software and associated documentation files (the "Software"), to deal
   in the Software without restriction, including without limitation the rights
   to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
   copies of the Software, and to permit persons to whom the Software is
   furnished to do so, subject to the following conditions:

   The above copyright notice and this permission notice shall be included
   in all copies or substantial portions of the Software.

   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
   IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
   AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
   LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
   FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
   IN THE SOFTWARE.
*/

const int PIN_PWM_OUT = 3;
const int PIN_ANALOG = A0;

const int SAMPLES_PER_EDGE = 80;
const int EDGES_PER_MEASURE = 5000 / SAMPLES_PER_EDGE;
const float BOARD_CALIBRATION = 4.0;

volatile long adc_sum;
volatile unsigned int adc_enable;
volatile unsigned int adc_value;
volatile unsigned int adc_samples;
volatile unsigned char timer0_state;
volatile unsigned char output_level;
volatile unsigned char output_level_old;
volatile unsigned char adc_measure_end;


void setup() {
  Serial.begin(9600);

  // Set up output reference signal pin
  pinMode(PIN_PWM_OUT, OUTPUT);
  timer0_setup();

  // Set up ADC
  adc_setup();

  // Main Loop
  float resistance;
  adc_init();
  for (;;) {
    if (adc_measure_end == 1) {
      resistance = adc_sum;
      resistance = resistance * (BOARD_CALIBRATION / (SAMPLES_PER_EDGE * EDGES_PER_MEASURE));
      Serial.println(resistance);
      adc_init();
    }
  }
}

void loop() {}


void adc_init(void) {
  adc_measure_end = 0;
  adc_sum = 0;
  timer0_state = 0;
  adc_samples = 0;
  PORTD |= (1 << PIN_PWM_OUT);
  output_level = 1;
  output_level_old = 1;
  delayMicroseconds(200);
  adc_enable = 1;
}


void adc_setup(void) {
  analogRead(PIN_ANALOG);
  cli(); //stop interrupts

  ADMUX = (1 << 6) | (0 << ADLAR);
  ADCSRA = (1 << ADEN) | (0 << ADSC) | (0 << ADATE) | (0 << ADIE) | (0b111);
  ADCSRB = 0x00;

  sei(); //allow interrupts
}


void timer0_setup(void) {
  cli(); //stop interrupts

  //set timer0 interrupt at 2kHz
  TCCR0A = 0; // set entire TCCR2A register to 0
  TCCR0B = 0; // same for TCCR2B
  TCNT0  = 0; //initialize counter value to 0
  // set compare match register
  OCR0A = 26; //  f = 16000000 / ((OCR0A + 1) * 64) = 9259 Hz
  // turn on CTC mode
  TCCR0A |= (1 << WGM01);
  // Set CS01 and CS00 bits for 64 prescaler
  TCCR0B |= (1 << CS01) | (1 << CS00);
  // enable timer compare interrupt
  TIMSK0 |= (1 << OCIE0A);

  sei(); //allow interrupts
}


ISR(TIMER0_COMPA_vect) {

  if (adc_enable) {

    if (adc_samples) {
      // Read ADC measure
      adc_value = (ADCL | (ADCH << 8));

      // Add measure to accumulator
      if (output_level_old == 1) {
        adc_sum -= adc_value;
      }
      if (output_level_old == 0) {
        adc_sum += adc_value;
      }
    }

    // ADC Start Conversion
    ADCSRA |= (1 << ADSC);
    adc_samples++;
    delayMicroseconds(12);  // Wait for Sample and Hold
    output_level_old = output_level;

    // Update next state
    if (++timer0_state >= (SAMPLES_PER_EDGE * 2)) {
      timer0_state = 0;
    }

    // Update output reference signal
    if (timer0_state < SAMPLES_PER_EDGE) {
      PORTD |= (1 << PIN_PWM_OUT);
      output_level = 1;
    }
    else {
      PORTD &= ~(1 << PIN_PWM_OUT);
      output_level = 0;
    }

    // Take one measure after several samples
    if (adc_samples > SAMPLES_PER_EDGE * EDGES_PER_MEASURE * 2) {
      adc_measure_end = 1;
      adc_enable = 0;
    }
  }
}
« Last Edit: May 04, 2024, 08:52:44 am by Picuino »
 

Offline Sariel

  • Contributor
  • Posts: 34
  • Country: il
Re: Homebrew Lock-In Amplifier
« Reply #48 on: May 04, 2024, 11:38:31 am »
I made a very nice Lock in amplifier based on AD630.

A short time ago, I actually posted a LinkedIn post about this with some results:

https://www.linkedin.com/posts/sariel-hodisan-792363120_lock-in-amplifiers-lias-are-incredibly-activity-7180141558162178049-_iK3?utm_source=share&utm_medium=member_android
 

Offline PicuinoTopic starter

  • Frequent Contributor
  • **
  • Posts: 975
  • Country: 00
    • Picuino web
Re: Homebrew Lock-In Amplifier
« Reply #49 on: May 04, 2024, 08:53:30 pm »
I have corrected a software problem that caused some ADC conversions to be lost. The ADC conversion now starts at the beginning of the interrupt routine so that there are no delays with overlapping ADC conversions.
It is tested and works better than before.

Arduino program Version 1.0:
Code: [Select]
/*
   Version 1.0 (04/05/2024)

   Copyright 2024 Picuino

   Permission is hereby granted, free of charge, to any person obtaining a copy
   of this software and associated documentation files (the "Software"), to deal
   in the Software without restriction, including without limitation the rights
   to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
   copies of the Software, and to permit persons to whom the Software is
   furnished to do so, subject to the following conditions:

   The above copyright notice and this permission notice shall be included
   in all copies or substantial portions of the Software.

   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
   IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
   AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
   LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
   FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
   IN THE SOFTWARE.
*/

const int PIN_PWM_OUT = 3;
const int PIN_ANALOG = A0;

#define CLK_BOARD  16000000
#define UART_BAUDS  9600
#define TIMER0_PRESET 26        // Must be >= 26
#define TIMER0_FREQ  (CLK_BOARD / (((TIMER0_PRESET) + 1) * 64))

const int SAMPLES_PER_LEVEL = 20;
const int LEVELS_PER_MEASURE = TIMER0_FREQ / (SAMPLES_PER_LEVEL * 2);
const float BOARD_CALIBRATION = 4.0;

volatile long adc_sum;
volatile unsigned int adc_enable;
volatile unsigned int adc_value;
volatile unsigned int adc_samples;
volatile unsigned int timer0_state;
volatile unsigned char output_level;
volatile unsigned char output_level_old;
volatile unsigned char adc_measure_end;


void setup() {
  Serial.begin(UART_BAUDS);

  // Set up output reference signal pin
  pinMode(PIN_PWM_OUT, OUTPUT);

  // Set up peripherals
  timer0_setup();
  adc_setup();

  // Main Loop
  float resistance;
  adc_init();
  for (;;) {
    if (adc_measure_end == 1) {
      resistance = adc_sum;
      resistance = resistance * (BOARD_CALIBRATION / (1.0 * SAMPLES_PER_LEVEL * LEVELS_PER_MEASURE));
      Serial.println(resistance);
      adc_init();
    }
  }
}

void loop() {}


void adc_init(void) {
  adc_measure_end = 0;
  adc_sum = 0;
  timer0_state = 0;
  adc_samples = 0;
  PORTD |= (1 << PIN_PWM_OUT);
  output_level = 1;
  output_level_old = 1;
  delayMicroseconds(200);
  adc_enable = 1;
}


void adc_setup(void) {
  analogRead(PIN_ANALOG);
  cli(); //stop interrupts

  ADMUX = (1 << 6) | (0 << ADLAR);
  ADCSRA = (1 << ADEN) | (0 << ADSC) | (0 << ADATE) | (0 << ADIE) | (0b111);
  ADCSRB = 0x00;

  sei(); //allow interrupts
}


void timer0_setup(void) {
  cli(); //stop interrupts

  //set timer0 interrupt at 2kHz
  TCCR0A = 0; // set entire TCCR2A register to 0
  TCCR0B = 0; // same for TCCR2B
  TCNT0  = 0; //initialize counter value to 0
  // set compare match register
  OCR0A = TIMER0_PRESET;
  // turn on CTC mode
  TCCR0A |= (1 << WGM01);
  // Set CS01 and CS00 bits for 64 prescaler
  TCCR0B |= (1 << CS01) | (1 << CS00);
  // enable timer compare interrupt
  TIMSK0 |= (1 << OCIE0A);

  sei(); //allow interrupts
}


ISR(TIMER0_COMPA_vect) {

  if (adc_enable) {

    // ADC Start Conversion
    ADCSRA |= (1 << ADSC);
    adc_samples++;
    delayMicroseconds(15);  // Wait for Sample and Hold

    // Read and accumulate old ADC value
    if (adc_samples) {
      // Read ADC old measure
      adc_value = ADCW;

      // Add measure to accumulator
      if (output_level_old == 1) {
        adc_sum -= adc_value;
      }
      if (output_level_old == 0) {
        adc_sum += adc_value;
      }
    }

    // Update next state
    if (++timer0_state >= (SAMPLES_PER_LEVEL * 2)) {
      timer0_state = 0;
    }

    // Update output reference signal
    output_level_old = output_level;
    if (timer0_state < SAMPLES_PER_LEVEL) {
      PORTD |= (1 << PIN_PWM_OUT);
      output_level = 1;
    }
    else {
      PORTD &= ~(1 << PIN_PWM_OUT);
      output_level = 0;
    }

    // Take one measure after several samples
    if (adc_samples > SAMPLES_PER_LEVEL * LEVELS_PER_MEASURE * 2) {
      adc_measure_end = 1;
      adc_enable = 0;
    }
  }
}


Output measures:
Code: [Select]
22.57
22.48
22.52
22.50
22.43
22.49
22.40
22.41
22.54
22.35
22.38
22.54
22.53
22.51
22.40
22.35
22.40
22.45
22.48
22.52
22.53
22.44
22.51
22.40
22.41
22.47
22.42
22.53
22.48
22.30
22.35
22.49
22.42
22.41
22.52
22.41
22.35
22.33
22.36
22.38
22.37
22.46
22.49
22.47
22.41
22.38
22.41
22.43
22.55
22.32
22.39
22.46
22.19
22.48
22.34
22.36
22.40
22.37
22.40
22.45

I think that this time I have managed to recover part of the signal “buried” in the noise.


Attached: Vout
« Last Edit: May 04, 2024, 08:58:09 pm by Picuino »
 


Share me

Digg  Facebook  SlashDot  Delicious  Technorati  Twitter  Google  Yahoo
Smf