Wind sensor project progress

Hello all,

I am working on a system that will collect wind speed and direction from an older Raymarine ST60 style sender. The reasons for using this sender are varied, but one good reason is that they are extremely robust, giving 20 years or more of service without problems.

Thanks to the help from this forum I have:

a) learned how to convert the rather "soft" signal from the speed sensor into something easier to read. I did this using an LM393 voltage comparator to get a nice strong logic level signal.

b) learned how to use interupts on the ESP32 to detect the falling edge of the incoming wave form and use this to calculate the incoming frequency.

The Raymarine sensor also gives direction, using variable voltages representing sine wave coordinates on the x and y axis, this part of the project is not included here as it was easy enough and mainly involved a few simple maths functions.

Now I have been running some tests on the sensor by putting on a pole on the roof of the car, well forward in clear air, and getting some speed vs frequency data. I will need a calm day for good tests, and tomorrow looks good. In the interim I have some decent data up to 60 km/h, but I noticed some odd results which I'd like to share, along with the code, for comments.

At this stage the data is probably good enough for my purposes, but I would be interested to hear any theories on why I am getting different results from the two methods of calculating the frequency.

Thanks to all for the help so far.

Matt



#define RXPIN 18

// pulse count and average pulse width time

volatile unsigned long pulses = 0;
volatile float AverageInterval = 0;

//variables to keep track of the timing of interupt from signal drop

unsigned long WaveFallTime = 0;  
unsigned long LastWaveFallTime = 0; 


    
// interrupt handler - note pulse width in microseconds
void IRAM_ATTR handleInterrupt2() {
  
  unsigned long CurrentTimer = micros();
  static unsigned long Interval1, Interval2, Interval3, Interval4, Interval5 = 0;
  static unsigned long LastTimer = 0;

  // debounce the incoming signal
  WaveFallTime = millis();
  if (WaveFallTime - LastWaveFallTime > 10){

    //Roll the intervals
    Interval5 = Interval4;
    Interval4 = Interval3;
    Interval3 = Interval2;
    Interval2 = Interval1;
    Interval1 = (CurrentTimer - LastTimer)/4;
  
    AverageInterval = (Interval1 + Interval2 + Interval3 + Interval4 + Interval5) / 5.0;
    
    pulses++;                     
    LastTimer = CurrentTimer;
    LastWaveFallTime = WaveFallTime;
  }
  
}

void setup() {
  Serial.begin(115200);
  pinMode(RXPIN, INPUT_PULLUP);
  attachInterrupt(digitalPinToInterrupt(RXPIN), handleInterrupt2, FALLING);
}

// display pulse/second and calculate pulse width in microseconds
void loop() {
  static unsigned long LoopTimer = millis();
  float CalcFrequency = 0;
  
  // after 10 seconds print average pulse width time
  if (millis() - LoopTimer > 3000) {
 

    // Two pulses per revolution, so divide by 6 for three second interval
    CalcFrequency = pulses / 6.0 ;
   
    if (AverageInterval > 0) {
      // convert from milliseconds per cycle to cycles per second (Hz)
      AverageInterval = 100000 / AverageInterval ;
    }

    //Show frequency calculated from the last five cycle intervals.
    Serial.print(AverageInterval, 4);
  
    Serial.print(", ");

    //Show frequency calculated from counting number of pulses in three seconds.
    Serial.println(CalcFrequency, 4);
    
    pulses = 0;                                   // reset pulse count
    LoopTimer += 3000;
  }
}

Results of a five minute drive, with speeds mostly at 60 km/h but also some slower patches for roundabouts and intersections, plus a few moments stationary.

0.5306, 0.8333
0.6202, 0.6667
0.5320, 0.6667
0.6927, 1.0000
0.6626, 0.8333
0.5561, 0.5000
0.4341, 0.6667
0.3814, 0.3333
0.8237, 1.0000
1.3559, 1.8333
1.5219, 1.8333
1.6193, 1.5000
2.8543, 3.3333
3.8621, 4.5000
4.2116, 4.6667
1.7420, 2.8333
1.3625, 1.6667
0.8677, 1.1667
0.7058, 0.8333
0.8782, 1.1667
0.9709, 1.1667
0.8454, 1.0000
1.2409, 1.3333
3.6097, 4.0000
2.4811, 3.8333
1.4041, 2.0000
2.0490, 2.1667
3.0562, 3.1667
3.2802, 4.1667
2.7059, 3.6667
3.6209, 3.8333
2.5272, 3.8333
1.3675, 2.0000
0.9381, 1.1667
4.5261, 4.0000
6.1464, 6.8333
9.3291, 9.8333
10.7940, 12.1667
10.2836, 13.3333
11.1364, 13.5000
11.3773, 14.0000
11.7354, 15.0000
12.8202, 15.6667
12.8853, 16.0000
12.3317, 15.5000
13.8282, 16.5000
12.3244, 16.8333
12.3888, 16.0000
12.7353, 15.8333
12.5135, 15.8333
12.3277, 15.6667
9.3463, 13.6667
8.1833, 10.8333
6.3455, 8.5000
5.5032, 7.6667
4.5603, 6.0000
5.5252, 6.6667
7.1521, 9.0000
7.9266, 10.3333
8.8752, 10.8333
8.3156, 11.0000
8.0088, 10.8333
10.2665, 12.0000
11.9221, 14.5000
10.6492, 14.8333
10.4306, 13.5000
9.7500, 12.8333
10.6281, 13.5000
10.5695, 12.8333
10.8871, 13.0000
10.5845, 15.0000
10.7673, 14.5000
11.6004, 14.0000
11.3317, 14.8333
12.0111, 14.5000
13.3819, 15.5000
14.6434, 18.0000
13.4156, 17.6667
12.7126, 16.0000
12.9843, 16.5000
12.0934, 14.6667
11.8596, 16.1667
12.6772, 14.3333
11.1408, 15.1667
12.2225, 14.0000
12.2726, 15.6667
11.4587, 15.3333
12.6183, 14.5000
11.9323, 14.8333
12.1969, 15.3333
12.2829, 15.6667
14.6041, 17.1667
13.4221, 16.6667
11.3179, 15.8333
12.1652, 14.3333
12.4963, 14.8333
11.7975, 14.1667
11.5099, 14.1667
13.9817, 16.1667
13.2233, 18.1667
13.7227, 16.3333
15.7154, 18.3333
12.1898, 17.8333
10.0837, 13.5000
5.4702, 8.1667
2.9483, 5.3333
3.0036, 3.3333
2.6684, 3.6667
1.7504, 2.5000
1.1796, 1.5000
1.4226, 1.8333
1.2968, 1.3333
2.2249, 2.1667
3.0464, 3.1667
5.1479, 5.8333
4.3756, 5.3333
1.5912, 2.6667
1.1653, 1.5000
2.9574, 2.1667
6.7875, 7.5000
8.4154, 10.1667
11.6236, 12.8333
12.3375, 15.8333
14.0797, 16.1667
13.9895, 17.3333
13.1089, 16.1667
13.1413, 16.6667
13.2922, 16.1667
12.5729, 16.3333
14.4776, 17.5000
13.8677, 16.8333
13.0086, 16.8333
13.1923, 17.0000
15.6367, 17.8333
14.3773, 19.1667
14.8818, 17.8333
13.7832, 17.1667
13.1372, 17.1667
12.4863, 16.3333
13.1544, 16.3333
13.4745, 16.0000
13.8309, 16.8333
14.2972, 18.0000
14.0865, 17.3333
13.0637, 17.0000
14.5904, 17.0000
13.0976, 17.5000
11.5586, 15.3333
13.3248, 16.5000
13.7563, 17.1667
14.2029, 17.1667
14.2935, 17.8333
15.1455, 18.3333
16.0560, 19.8333
16.1431, 20.0000
14.8849, 19.1667
15.4031, 19.0000
15.1980, 18.8333
15.0304, 19.0000
13.7605, 18.0000
14.1836, 18.0000
14.7850, 18.1667
12.9410, 17.6667
10.9599, 15.5000
8.4522, 11.5000
7.6252, 9.6667
8.4955, 10.1667
10.4859, 11.0000
9.2866, 10.5000
11.2296, 12.8333
11.9600, 14.5000
12.3545, 15.3333
13.0202, 16.3333
12.3971, 15.8333
12.3411, 16.0000
13.0392, 16.1667
11.9175, 15.8333
11.6063, 14.8333
11.7658, 14.6667
12.0831, 15.5000
12.6807, 15.8333
11.4840, 16.0000
9.1777, 13.1667
9.1434, 11.8333
5.8247, 8.0000
5.9316, 7.5000
6.5143, 7.6667
6.6825, 8.5000
7.2272, 9.1667
5.7900, 8.3333
5.2160, 6.8333
3.6176, 5.5000
4.6977, 4.8333
5.2846, 6.1667
4.4044, 6.6667
2.0181, 3.5000

Please note that the above data does not include acutal car speeds. This will be manually recorded by my passenger tomorrow when we do the still air testing. As nice as it would be, it was a bit complex to interface the gps puck into this project.

You should format data on the forum like a program.

chart

That looks nice. But it hides the numbers and I think they may hold a clue to what is going on.

3 seconds or 10 seconds?

Is denouncing the incoming signal destroying the collected data? Is the signal from a stationary coil with a rotating magnetic field? Or is there switch contacts involved?

There is clearly some noise, but its interesting that CalcFrequency is around 1.25 times AverageInterval.
image

Ooops, threes seconds, not 10. Old comment hasn’t been updated.

// convert from milliseconds per cycle to cycles per second (Hz)
AverageInterval = 100000 / AverageInterval ;

I think that you should store the value in another variable, e.g.: frequency. Beside using the same var with two different meanings, here it's dangerous because your interrupt could trigger in the middle and overwrite it again.
And you mention milliseconds in the comment, then why 100000 instead of 1000? or maybe 1000000.

    // Two pulses per revolution, so divide by 6 for three second interval
    CalcFrequency = pulses / 6.0 ;

But if the interrupt triggers with the falling edge only, shouldn't it be one pulse per revolution?
And you shouldn't need the debounce in the interrupt, I think, if the signal is a clean square wave from the comparator.

Interval1 = (CurrentTimer - LastTimer)/4;

Why do you divide it by 4? you could keep the microseconds until the last convertion, for simplicity.

So, it turns out the lm393 will faithfully reproduce the same mess being produced by the sensor. I THOUGHT the signal would be clean but it turned out to be pretty messy. Quite a few grey hairs before I figured out what was going on.

John, yes I found the same correlation using Excel. (old school). That's one of the reasons I included the actual numbers.

But your graph shows that it kinda stablises as the frequency increasese. Interesting....

Gromit1, a few things to cover.

The simplest first... the sensor produces TWO pulses per revolution. Hence the divisor.

I'm trying to think how your interupt triggering a change could be a problem, and also how another variable might solve the problem.... TBH, I can't see that one yet.

The milliseconds conversion has me worried... I'll look into why the heck I added the zero, and, more importantly, why it hasn't shown up in the final output. Surely I should have a ratio of 10 to 1 in the two outputs.... odd...

Your data from calcFrequency looks odd - few significant digits and lots of similar results. This apparently because you're simply dividing the pulse count by six. The count is integer, so the result/6 doesn't give much variation.

By contrast, the other method measures multiple time intervals and averages them. I'd expect more significant figures and hopefully better accuracy.

Rather than test in a car, I'd use a pulse generator (or make a basic one one using an Arduino) until you can see what your calcs are doing.

What I mean is that in between the next lines the interrupt could be executed:

      // convert from milliseconds per cycle to cycles per second (Hz)
      AverageInterval = 100000 / AverageInterval ;
    }
    //Show frequency calculated from the last five cycle intervals.
    Serial.print(AverageInterval, 4);

So, when you are in the last line, AverageInterval could have been modified again by the interrupt.
Probably the chances are small, because the frequency is very low and the loop is faster in comparison. But it will happen.

Beside that, there are some things not clear to me in the code, probably because I don't understand it correctly.
My main concern is the results you get. If I understand right you measure the frequency in two ways (correct me if I'm wrong):

  • AverageInterval: You calculate the time between pulses and average them, so you have the period. Then in the loop you invert it and adjust to seconds, so you have the frequency of the pulses.
  • pulses: You count the pulses. Then in the setup you correct to revolutions (2 pulses per revolution) and divide by 3 seconds (of the loop period). So you get the revolutions per second, that is the frequency, but of the revolutions.

And you print both.

So the value in one column should be exactly double than the value in the other (if I don't miss anything with the conversions). Correct? But this is not what you get.
If this is the case, there are other topics that could produce the discrepancies. For example the way that you count the 3 seconds in the loop.

And as commented by wildbill, to test and fine tune the system, it would be easier if you generate and inject a pulse with another arduino. Or install it in a manual wheel or something like that. To save patrol and tires :wink:

Hi, @gilow

Can you please post a copy of your circuit, a picture of a hand drawn circuit in jpg, png?
Hand drawn and photographed is perfectly acceptable.
Please include ALL hardware, power supplies, component names and pin labels.

Please not a cut and paste Fritzy.

How have you got the anemometer wired to the controller?

How long is the wire from anemometer to controller, have you tried an external pullup resistor?

Can you please post some images of your project?
So we can see your component layout.

What model Arduino are you using?

Thanks.. Tom.. :grinning: :+1: :coffee: :australia:

Then perhaps your debouncing isnt as effective as it should be.
I'm a bit out of my depth here so maybe someone will be able to put me right; Can the ISR get interrupted?
The ISR calculates BOTH the Average Interval and the pulses. So they SHOULD both give exactly the same results provided your later calculations are correct.
Generally CalcFrequency (based on pulses) is high, so it looks as if there are additional pulses being counted.

Would that be explained by poor debouncing?

What electrical contacts require denouncing? It appears to me that magnets and a Hall effect device are used to create the output pulses. It seems to me that the debouncing is ignoring valid pulses and completely invalidates the data collection.

Are you sure that the wind speed transducer is still functioning? The Raymarine Wind Transducer has 12V power input and comes from the factory with either a 30m or 50m cable between the transducer and the head unit. Nothing about this indicates to me that the output signal requires amplification for 5V detection within 10 feet of the transducer. Have you checked the output pulses with 12V supply voltage? Seems to me that a resistor divider circuit should be more appropriate than an amplifier to interface it to an Arduino.