Author Topic: Wild AC Tachometer  (Read 1016 times)

0 Members and 1 Guest are viewing this topic.

SparWeb

  • SuperHero Member
  • ******
  • Posts: 3219
  • Country: ca
    • Wind Turbine Project Field Notes
Wild AC Tachometer
« on: May 28, 2017, 10:47:11 PM »
Wild AC Tachometer (or "WACT" for short)

I came up with another way to make a tachometer for my wind turbine.  I think it is worth sharing because it measures wind turbine speed from the wild AC it spits out, without being fooled by noise, spikes, or waveform distortion which is inherent in wild AC when it is rectified to a battery.
I'm pleased with how steady the readings are, and also surprised by the rate the data can be collected - with an Arduino Mega the RPM can be sampled 20 times per second.

If you want to start at the beginning, you can read the following explanation - or just skip to the pictures to see what I've built!

Problem statement:

Previous electronic tachometers that I've built to measure RPM of my wind turbines have relied on these methods to detect the turbine speed:
a) read voltage on one wild AC line & count the pulses, or
b) read an encoding device attached to the turbine shaft & count pulses.

I've never been satisfied with either of these solutions, for the following reasons:

A) Reading an AC Line:
 - Noise on the wild AC is mistaken for signals
 - Filters built into the circuit work poorly at some RPM
 - Filters reduce the sensitivity at low RPM
 - Motor-conversion alternators are MUCH noisier than Axial Flux alternators


B) Reading a separate tachometer device like an encoder
 - The device must be mechanically driven by the generator,
 - The device must resist weather, vibration, heat and cold at the tower top for several years,
 - The device should not fail in a way that would damage the generator,
 - A signal wire must be run all the way up the tower.


Why reading the AC line didn't work:

I've never had any success doing this before.  The results always sucked. 
I tried several times to read RPM with a PIC microcontroller to measure pulses on an AC power line.
I built a PicLog from the Backshed, but the RPM was nearly useless, despite the filter and optoisolator included.
The fault lies in the AC coming out of my motor conversion.  There are a lot of spikes in it that trick the electronics.
The noise would make the measured RPM jump up and down so much I could never be sure what the true number really was!
I also spent a lot of time with LM2917 tacho chips and adding various filters, voltage dividers, capacitors on to the input line - without success.
Various approaches with the software to correct the output from the tacho chip could deal with some of it, some of the time... not reliably.


I only came to terms with the problem when I got a small oscilloscope to actually see the waveform.  Then things became clear. 
The basic problem is that the 3-phase wild AC is being rectified.  Switching pulses are as high as the power waveform.
At lower RPM, the switching pulse is quite distinct and quite separate from the power waveform, as you can see in the picture.
At high RPM, the switching pulse merges into the power wave, but here the wave is clipped by the battery voltage and there is a lot of ripple.
So in each power range, there are completely different sources of noise - filtering one noise doesn't filter the other noise.
Filtering both suppresses the whole signal!  Rectified wild AC is a horribly distorted waveform.

Here are some samples of the waveform I'm dealing with:

At cut-in in Star:


At 3 Amps in Star:


At 10 Amps in Jerry (individually rectified phases):


Why I won't use an encoder:

So this is not a new problem, and that's why most motors that need to have their speed controlled with feedback use encoder wheels and hall sensors
and other common devices to independently measure their speed.  I've bench-tested a couple of gadgets to do this in the past, but I never followed through on them.
To mount them to my generator shafts was easy - but I never hooked them up on the tower.  The extra drop cable in the tower was always a big drawback. 
My current setup, with a 7-wire jacketed cable for the AC power works really well, but it relies on the cable dropping directly through the axis of the tower.
To add another cable on one side of the main cable would add a nasty corkscrew twisting that currently isn't a problem with the setup I have.
That would solve a "nice to have" problem at the cost of a "need to have" cable.

I also considered an Xbee radio that could send the RPM signal wirelessly.  That, however, would require an Arduino up top the tower.  And that could need a battery...  Blah...


New solution:

I finally had a chance to think through the tachometer idea from a different point of view.  I asked myself a simple question:
   Why do I make the tachometer read only one of the phases, when there are three to use?

At the same time, I was looking at interrupts on the Arduino board.  An interrupt calls a separate function outside the main program loop.
I realized that if I have 3 interrupt pins on the board, the program could step from phase to phase, waiting for each phase before expecting the next. 
The rising pulse on each phase triggers one of the interrupts, which will change the state of a logic variable. 
By using the logic variable to control the flow of the program, I could write a program that always knows what state it's in.
That would get me away from analog or digital measurements of the pulse itself for program flow.  That's when I understood how the program would work:
   Once phase 1 crosses zero, it doesn't matter what the waveform looks like, because the program doesn't do anything yet. 
   It then waits for phase 2 to cross zero.  Once that happens, the logic variables are toggled, and nothing further happens until phase 3 crosses zero.
   After phase 3 crosses, then program flow returns to waiting for phase 1 to cross zero, and only then it knows that a cycle is complete.

It still requires a little electronic filtering before the digital input to the Arduino, but two resistors for a voltage divider and a diode for each phase will do.

Another thing I did was to write pseudocode before trying to write the code itself (my teachers from long ago would be so proud).
This helped a lot to figure out the program flow - even I was surprised.  I've posted the pseudocode separately to illustrate how I did that.
Writing pseudocode kept me from bogging down in the syntax of commands, and explained in plain language what I wanted the program to do.
If you read carefully, you will see that I didn't stick to the pseudo plan when I wrote the actual code - but I had my thoughts in order and that was the important thing.  I usually don't get a program to work this quickly.


Code: [Select]

/*  REQUIRES ATMEGA 2560 FOR 3 INTERRUPT PINS
 * 
 *  This program reads the state of 3 pins as interrupts in order to monitor
 *  their change in state sequentially.  By reading their state in sequence,
 *  the program will accurately measure the speed of a 3-phase motor or generator
 *  without caring if a brief noise pulse comes before for the main pulse.
 *  Assume that each of the 3 interrupt pins will be connected to a separate phase,
 *  and that a voltage divider will tie each pin to ground until the sine pulse is
 *  positive for each phase.  Also, the voltage divider conveniently requires that
 *  a threshold of voltage is passed before the  pin changes to a HIGH state.  The state
 *  of each phase is tracked with logical operators, toggled by each interrupt, rather
 *  than attempting to measure the state of the phases simultaneously.
 */

interrupt pin 1 = 18;    // Phase 1 monitoring pin
interrupt pin 2 = 19;    // Phase 2 monitoring pin
interrupt pin 3 = 20;    // Phase 3 monitoring pin

/* conversion factor microseconds into seconds
 * 1,000,000 microseconds per second
 * 60 seconds per minute
 * 4 poles -> _2_ pulses per phase per revolution
 */

// boolean a, b c
// logical values of the state of phases a, b, and c. These logic values are independent of the digital pin state. They are set and changed only when conditions are correct.

// variable 0 holds previous phase 1 time
// variable 1 holds current phase 1 time
// variable 2 holds the period between the current and the last phase 1 pulse
// variable 3 holds the speed of the machine


void setup() {
  // the on-board status pin setup up
  // initialize serial communications at 9600 bps
}

  /* PSEUDOCODE
   *  each interrupt routine that is called performs a specific task required during its part of the cycle
   *  Phase 1: record current time in "micros()"
   *  Phase 2: must pass through this phase before proceeding.  Don't care how long this takes   
   *  Phase 3: next pass through this phase before proceeding   Don't care how long this takes
   *  Phase 1: return to start.  speed = 1/Elapsed time.
   *            Elapsed time = (now) - (last phase 1 time)
   *  Each time entering the specific phase's interrupt, make sure to toggle the previous phases's state record.
   *  If any random phase is triggered, only when it is the next successive phase will the correct action
   *  occur, and a conditional statement can be written to detect the correct conditions.
   *  Use boolean operators to keep track of the states of each phase, ie. "boolean phase1, phase2, phase3;"
   */

void interrupt1() {
  /* routine for phase 1
   *    check first that phase 1 isn't already high,  1=low
   *    and that phase 3 is still high                3=high
   *    and phase 2 was already toggled low.          2=low
   *    Then toggle phase 1 high and phase 3 low.
   */
/* record the current time
* measure period between current time and previous time
* transfer value of current time in to previous time variable
* speed equals a constant divided by the period between pulses
*/
}

void interrupt2() {
  /* routine for phase 2
   *    check first that phase 2 isn't already high,    2=low
   *    and that phase 1 is still high                  1=high
   *    and phase 3 was already toggled low.            3=low
   *    Then toggle phase 2 high and phase 1 low.
   */
}

void interrupt3() {
  /* routine for phase 3
   *    check first that phase 3 isn't already high,    3=low
   *    and that phase 2 is still high                  2=high
   *    and phase 1 was already toggled low.            1=low
   *    Then toggle phase 3 high and phase 2 low.
   */
}

void loop() { 
/* trigger interrupt1
 * trigger interrupt2
 * trigger interrupt3
 *
 * Send motor speed to serial port
 *
 * resets after several second have passed with no data
/*
}



Hardware Notes:

This has to be built on an Arduino with at least 3 interrupt pins (Mega, Leonardo, Micro, or a DUE).  Luckily I still have a Mega.
When I started writing this code I reached for my little UNO first, only to discover that it has only 2 interrupts  :P


Working Code:

Code: [Select]

/*  REQUIRES ATMEGA 2560 FOR 3 INTERRUPT PINS! ! !
 * 
 *  This program reads the state of 3 pins as interrupts in order to monitor their change
 *  in state sequentially to measure the speed of a 3-phase motor or generator without
 *  mistaking brief noise pulses for the main pulses.
 *  Each of the 3 interrupt pins will be connected to a separate phase.
 *  A diode and voltage divider is required to tie each pin to ground until the sine
 *  pulse is positive for each phase. 
 *  The state of each phase is tracked with logical operators, toggled by each interrupt.
 */

#define STATUS_LED 13      // Declare that the on-board LED is a pin with a LED
const byte ledPin = 13;    // LED illuminates to show when something happens
const byte inPin1 = 18;    // Phase 1 monitoring pin
const byte inPin2 = 19;    // Phase 2 monitoring pin
const byte inPin3 = 20;    // Phase 3 monitoring pin

int i=0;                    // loop counter

const long konstant = 1000000*60*2;     /* conversion factor microseconds into seconds
                                        * 1,000,000 microseconds per second
                                        * 60 seconds per minute
                                        * 4 poles -> _2_ pulses per phase per revolution
                                        */

boolean a = false;         // logical values of the state of phases a, b, and c.
boolean b = false;         // these logic values are independent of the digital pin state.
boolean c = true;          // they are set and changed only when conditions are correct.

unsigned long time0 = 0.0;        // holds previous phase 1 time
unsigned long time1 = 0.0;        // holds current phase 1 time
unsigned long period = 0.0;       // holds the period between the current and the last phase 1 pulse.
unsigned long speedy = 0.0;       // holds the speed of the machine.

void setup() {
  pinMode(STATUS_LED,OUTPUT);             // the on-board status pin setup up
  pinMode(ledPin, OUTPUT);                // initialize the LED
  Serial.begin(9600);                     // initialize serial communications at 9600 bps
  digitalWrite(STATUS_LED, HIGH);         //
  delay(50);                              //
  digitalWrite(STATUS_LED, LOW);          // Flash the LED when starting
  delay(50);                              //
  digitalWrite(STATUS_LED, HIGH);         //
}

void interrupt1() {

  if (a== false && b == false && c == true) {       // if this pulse doesn't follow the interrupt 3 call, it won't do anything
    a=true;
    c=false;
    time1 = micros();             // get current time
    period = time1 - time0;       // Compare current to previous time, to get elapsed time
    time0 = time1;                // assign current time to previous time variable for use next cycle
  }
}
void interrupt2() {

  if (a== true && b == false && c == false) {       // if this pulse doesn't follow the interrupt 1 call, it won't do anything
    b=true;
    a=false;
  }
}

void interrupt3() {

  if (a== false && b == true && c == false) {       // if this pulse doesn't follow the interrupt 2 call, it won't do anything
    c=true;
    b=false;
  }
}

void loop() { 
  attachInterrupt(digitalPinToInterrupt(inPin1), interrupt1, RISING);      // trigger interrupt1
  attachInterrupt(digitalPinToInterrupt(inPin2), interrupt2, RISING);      // trigger interrupt2
  attachInterrupt(digitalPinToInterrupt(inPin3), interrupt3, RISING);      // trigger interrupt3

  if (period > 10 && period < 1000000) {   // period=0 when not set, or overflow when machine is not turning
    speedy = konstant/period;              // updated only when ready to send to serial output
    i=0;                                   // counter remains at 0 when data is valid
  } else {
    i++;                                   // counts the loops with no valid data
  }

  Serial.print("  speed= ");
  Serial.print(speedy);           // generator speed is displayed

/*  Serial.print(" time= ");
  Serial.print(time1);
  Serial.print("   period= ");    // for troubleshooting purposes only
  Serial.print(period);
  Serial.print("   a= ");         // for troubleshooting purposes only
  Serial.print(a);
  Serial.print("   b= ");         // for troubleshooting purposes only
  Serial.print(b);
  Serial.print("   c= ");         // for troubleshooting purposes only
  Serial.println(c);
*/

  if (i>20) {                     // resets after several second have passed with no data
    i = 0;
    time0 = 0;
    time1 = 0;
    period = 0;
    speedy = 0;
  }
}


I tested it last weekend, and got pretty clean results:



I've just added some averaging to smooth out the results a bit, but this basic program above gives good results without it.
The readings come as fast as the Arduino can loop.  The mega was spitting out 15-20 readings per second.
Ironically, the turbine only produces about 10Hz at cut-in, so many readings are duplicates!

I'm also pulling a LCD screen out of an old (abandoned) project to show output from this tachometer rather than sending out to my laptop.
When I find the app notes for communicating with the LCD, I'll add that to the program. 
I will follow up when I know for certain the Mega is suitable for this (but I strongly expect it is).
Later, I will slap together a shield for the Arduino and box it all up.
No one believes the theory except the one who developed it.  Everyone believes the experiment except the one who ran it.

System spec: 135w BP multicrystalline panels, regulated by Xantrex C40, DIY 8ft diameter wind turbine, regulated by Tri-Star TS60, 800AH x 24V AGM Battery, Xantrex SW4024

SparWeb

  • SuperHero Member
  • ******
  • Posts: 3219
  • Country: ca
    • Wind Turbine Project Field Notes
Re: Wild AC Tachometer
« Reply #1 on: May 28, 2017, 10:58:23 PM »
I meant to include a circuit diagram:

10520-0

This circuit is "as-tested" and it works.  Later, I noticed that it could be better.  The capacitor is completely unnecessary.

The two resistors making the voltage divider should be first, and the diode should be attached at the junction of the divider, not the other way around.
The voltage divider should be set up as "2k + 1K" to get a 3:1 ratio, to give the Arduino ~7V to work with on the digital interrupt (on a 24v system).
No one believes the theory except the one who developed it.  Everyone believes the experiment except the one who ran it.

System spec: 135w BP multicrystalline panels, regulated by Xantrex C40, DIY 8ft diameter wind turbine, regulated by Tri-Star TS60, 800AH x 24V AGM Battery, Xantrex SW4024

Bruce S

  • Global Moderator
  • Super Hero Member Plus
  • *****
  • Posts: 4515
  • Country: us
  • USA
Re: Wild AC Tachometer
« Reply #2 on: June 02, 2017, 06:35:57 PM »
SparWeb;
That coffee cup looks woefully low  :(
A kind word often goes unsaid BUT never goes unheard