Phase detector by using bitwise (^) XOR

I trying to read Power Factor that compare the signal input from voltage and current by using Bitwise XOR (^),
The result of program, I compare that to XOR component in ISIS Proteus
my Code

/*
  ReadAnalogVoltage
 Reads an analog input on pin 0, converts it to voltage, and prints the result to the serial monitor.
 Attach the center pin of a potentiometer to pin A0, and the outside pins to +5V and ground.
 
 This example code is in the public domain.
 */
#include <LiquidCrystal.h>

// initialize the library with the numbers of the interface pins
LiquidCrystal lcd(7, 6, 5, 4, 3, 2);
unsigned long a = 0;
unsigned long b = 0;
unsigned long c = 0;
// the setup routine runs once when you press reset:
void setup() {
  // initialize serial communication at 9600 bits per second:
  Serial.begin(9600);
  lcd.begin(16, 4);
  unsigned long a = 0;
  unsigned long b = 0;
  unsigned long c = 0;
  pinMode(8,OUTPUT);
  // Print a message to the LCD.
}

// the loop routine runs over and over again forever:
void loop() {
  // read the input on analog pin 0:
  int sensorVol = analogRead(A2);
  // Convert the analog reading (which goes from 0 - 1023) to a voltage (0 - 5V):
  float voltage = sensorVol ;
  if (195<voltage)
  { 
    a = 1;
  } 
  else { 
    a = 0;
  }
  // print out the value you read:
  int sensorAmp = analogRead(A3);
  // Convert the analog reading (which goes from 0 - 1023) to a voltage (0 - 5V):
  float current = sensorAmp ;
  if (515<current)
  { 
    b = 1;
  } 
  else { 
    b = 0;
  }
  // print out the value you read:

  c = a ^ b;
  if (c==1)
  {
    digitalWrite(8,HIGH);
  }
  else {
    digitalWrite(8,LOW);
  }
  Serial.println("current");
  Serial.println(current);
  Serial.println("voltage");
  Serial.println(voltage);
  lcd.setCursor(0,0);
  lcd.print("voltage =");
  lcd.print(voltage);
  lcd.setCursor(0,2);
  lcd.print("current =");
  lcd.print(current);
}

the problem is…

why the result is so different?
Did I miss something in calibration ? or somethings else?


XOR component show how it go
*blue = voltage
yellow = current
pink = XOR component output
green = Bitwise XOR output

the different between Bitwise (^) XOR with XOR component

my sketch in ISIS

void setup() {
  // initialize serial communication at 9600 bits per second:
  Serial.begin(9600);
  lcd.begin(16, 4);
  unsigned long a = 0;
  unsigned long b = 0;
  unsigned long c = 0;
  pinMode(8,OUTPUT);
  // Print a message to the LCD.
}

Since a, b, and c are already defined global variables and you don't use them in the setup() function, you shouldn't "re-declare" them in setup().

As for your problem, I think your code's logic is to blame. Although I'm familiar with AC circuit analysis (just finished the class this past semester :slight_smile: ), I don't know too much on how to actually measure power factor. Here is a link to a forum discussion where they answer your question. [PIC] - Power factor measurement using PIC18f4520 | Forum for Electronics

Based on this quote, I think you are missing some logic in your code:

Ninonic:

  1. measure voltage with one ADC input
  2. measure current with a second ADC input.
  3. XOR (use a logic gate such as 74LS86 or equivalent) the two waveforms, feed it through a low pass filter and measure the resulting voltage through a third ADC input.

As long as you 'square up' the voltage and current waveforms using an op-amp or comparator before feeding them to the XOR gate, it's output will be a pulse with width equal to the phase difference in the signals. If you filter it to find the average, you get an analog voltage proportional to the phase shift.

It isn't using the zero crossing method at all but it will allow you to measure V, I, apparent power and phase displacement using simple math.

Thanks for correction

I know the common way is using comparator to before feeding to XOR gate.
then using for my arduino input. I did that.

but, the result from component XOR gate as I expected (in simulation),
its HIGH(sometime negative HIGH) when a!=b, and LOW when a=b.
I just need fix or erase the negative one.

for reading power factor,
I can do that with calculation based the XOR input

but I looking for another method.
I making code that can work as comparator and XOR gate at once,
maybe I miss something in calibration or input? I still don't know yet

how make it happen?

Why not just use a couple comparators and an XOR gate? It would be a lot cheaper and simpler. Might even have a better frequency response than an Arduino.

I did. I 've been there. That not work for me. The voltage and current phase in come in same time, theres no different phase. even my mentor dunno how.
I already test, from raw voltage and current, its show the lagging.
but after trough comparator, the phase become one. dunno how, I follow the circuit design as many journal do.
I dunno why different.
So please...
maybe its time for code?

why cheaper and simpler ? the fact you buy component, make design, and so on...
why not just create the code?

I find the idea of using bitwise XOR in numeric values extraordinary - Oh I see: you aren't XORing numeric values, you are comparing booleans.

You know that an xor is equivalent to a boolean not-equals != ? Your code reduces down to:

// write high when either voltage or current but not both are > our check values
digitalWrite(8, (voltage>=195) != (current>=515));

ps: don't use a and b as variable names. Call 'em voltageHigh and currentHigh, or something.

pps: use a meaningful name for your 195 and 515 value with a const int declaration.

Thanks Sir Paul
That comment I waiting for

So I need to convert it to Boolean? but I think its hard. Dunno much
can we do XOR in numeric mode?

I change the variable like this

#include <LiquidCrystal.h>

// initialize the library with the numbers of the interface pins
LiquidCrystal lcd(7, 6, 5, 4, 3, 2);
int digVol = 0;
int digAmp = 0;
int pie    = 0;
// the setup routine runs once when you press reset:
void setup() {
  // initialize serial communication at 9600 bits per second:
  Serial.begin(9600);
  lcd.begin(16, 4);
   pinMode(8,OUTPUT);
  // Print a message to the LCD.
}

// the loop routine runs over and over again forever:
void loop() {
  // read the input on analog pin 2:
  int sensorVol = analogRead(A2);
  float voltage = sensorVol ;
  if (voltage>0.01)
  { 
    digVol = 1;
  } 
  else { 
    digVol = 0;
  }
   int sensorAmp = analogRead(A3);
 
  float current = sensorAmp ;
  if (current>515)
  { 
    digAmp = 1;
  } 
  else { 
    digAmp = 0;
  }
 
  pie = digVol ^ digAmp;
  if (pie==1)
  {
    digitalWrite(8,HIGH);
  }
  else {
    digitalWrite(8,LOW);
  }
  Serial.println("current");
  Serial.println(current);
  Serial.println("voltage");
  Serial.println(voltage);
  lcd.setCursor(0,0);
  lcd.print("voltage =");
  lcd.print(voltage);
  lcd.setCursor(0,2);
  lcd.print("current =");
  lcd.print(current);
}

Sir,
Bitwise XOR for Boolean ?
but my data in single number
0 and 1
thats XOR function should be work on that

(voltage>=195) != (current>=515));
because the voltage sensor start from 0,
I had it back to zero
and current sensor start from 2.5V which is around 510-515,
so thats why I need to cut half data from sensor current.

how it still not working?

So I try again, and over again,
I got the PF value
but, it still unstable

I set delay between voltage and current in 4.03013316ms
thats PF should be 0.3

the correct value

but sometimes miss

I am not sure it error from Bitwise (^) XOR or... somethings else?

someone please help mee... :confused: :confused:

Somebody help meee....

Your "circuit" has a fundamental problem. The current sensor would have an output signal connected to A3 that's centered at 2.5V. This is the zero crossing voltage level for the amps signal.

Your voltage signal connected to A2 shows a 1/2 wave rectified signal that's referenced to GND (0V) ... there is no zero crossing.

The voltage signal needs to be full wave centered at 2.5V, or you'll never be able to detect the phase interval between the 2 signals. Make sure the peaks are within the power rail voltages.

hmmm, could be
But, How can I do that? voltage that centered at 2.5V

I think the choice that I have...

  1. make voltage centered at 2.5 V
  2. do code something work that current sensor can center at 0V

I tried the second one, but bot perfect as planed.

Any idea how to center voltage at 2.5?

Suggestion for Option 1.

AC signal pk-pk connected to the 10K resistor must not be greater than ±10V max.

thanks for advice...
I tried, still not work properly...

I think still there something wrong with calibration... :C

I even use comparator, because the acs712 voltage too low, below 2.7V.

Beside, the peak to peak acs output 185mV/A. And my project more less 1A (so it around 2.315 - 2.685, with bold noise.
I think thats why...
I think comparator hard to sense the current value

I got an idea.
How to count in ms when voltage signal come, the count start
then when current signal come, the count stop

// global variable

const int Hz = 50;
const int T = (1000/Hz);
const float Pi = 3.14159; 
float P;
float PF = 0<PF<1;
int PFcas;
float duration ;

// loop
      duration = ? // count 
      P = (duration*2*Pi)/T;
      PF = cos(P);

that will be duration variable…
Is there someone can help with that code?

I still completely understand about counting

Ninonic:
thanks for advice...
I tried, still not work properly...

I think still there something wrong with calibration... :C

Did the voltage signal get centered at 2.5V?
Do you mean calibration of the ACS712?

Ninonic:
I even use comparator, because the acs712 voltage too low, below 2.7V.

Beside, the peak to peak acs output 185mV/A. And my project more less 1A (so it around 2.315 - 2.685, with bold noise.
I think thats why...
I think comparator hard to sense the current value

+1

The comparator's reference voltage would need to be set above the noise level of the signal or the noise will appear full swing at the output. The datasheet shows 21mV noise peak-peak.

Several more options you could try:

  1. Amplify the signal:

In the datasheet, Application #3 (page 12), if you replace the 3.3K with 12K, you'll get ± 2.22V/A. Now you could use a comparator or just connect directly to the analog input of the Arduino.

  1. Use a Current Transformer

With this, if you wrap 10 turns through the hole and use a 250Ω load resistor, you'll get a ± 1.25V AC signal on the output when there's 1A going through the wire that's wrapped through the hole (primary).

Note: The speed of reading an Analog input is about 100µs (10kHz). You have 2 of them, so now 5kHz for both readings. Your AC signal is 50Hz, so you'll only be able to take 100 readings per cycle and your phase resolution would only be ± 3.6 degrees. This is not allowing for additional code slowing down the loop.

Research using the Arduino's analog comparator and input capture to get high precision time interval readings for phase calculation.

dlloyd:
Did the voltage signal get centered at 2.5V?
Do you mean calibration of the ACS712?

when I did. Its all 2.5V. raw voltage sensor 3V half wave. So I connected like your design,its seems like it just fill the empty one.
yap. ACS712.
I use ACS module this one

so I can't modify the resistor :frowning:

But, I was looking someone calibrating ACS sensor to read RMS value, @elik745i. page 4. #48
the sensor runs correctly and smoothly.
[/url=http://forum.arduino.cc/index.php?topic=179541.15]this way[/url]
I wonder it can work with code method in previous code.

I think, we better use ACS than CT, because arduino operational Volt and Current small scale.
Beside using CT need to do reactifier before connected to arduino board.

Do you know how to
How to count in ms when voltage signal come, the count start
then when current signal come, the count stop

when I did. Its all 2.5V. raw voltage sensor 3V half wave. So I connected like your design,its seems like it just fill the empty one.

I guess you didn't remove the diode. The circuit I posted doesn't show any diode. Removing it should give you ±3V AC. Use a 10K series resistor (as shown in the diagram to protect the Arduino). The Arduino readings will be clipped at ± 2.5V ... this is OK because we're interested in the 2.5V crossing of the waveform, not the voltage measurement itself.

so I can't modify the resistor :frowning:

Nothing to modify. Application 3 shows an external op amp circuit to amplify the output signal.

But, I was looking someone calibrating ACS sensor to read RMS value, @elik745i. page 4. #48
the sensor runs correctly and smoothly.
I wonder it can work with code method in previous code.

Not sure where this is. I wouldn't bother with code until you get proper signals to work with.

I think, we better use ACS than CT, because arduino operational Volt and Current small scale.
Beside using CT need to do reactifier before connected to arduino board.

No rectifier diode needed. Use the same circuit as posted for the voltage, except additionally connect a 250Ω load resistor across the secondary.

Do you know how to
How to count in ms when voltage signal come, the count start
then when current signal come, the count stop

Yes, but why bother now if the signals aren't ready yet.
P.S. I think you mean µs because ms will give a lousy ±18 degrees phase resolution.

I forgot to mention, if you prefer to use 1/2 wave rectified signals referenced to 0V, then your original voltage circuit is OK, except I would connect the signal to a comparator to create a digital signal. The reference voltage could be adjusted for calibration. Note that you might be able to eliminate the diode and still get a pulse representing 1/2 cycle (this would be more accurate but depends on the comparator specifications).

The current signal could be fed into a second comparator with reference at 2.5V + 21mV noise offset + xxmV calibration. This would create your second digital signal.

Now you could use 2 digital inputs (i.e. interrupts INT0 and INT1) to record the timing between the signals.

What comparator(s) do you have?

I did like the design.

Is it like this?

but the value still unstable..