Tag Archives: ultrasonic anemometer

Arduino Ultrasionic Anemometer Part 14: Wind Tunnel Testing

It’s been a while since I posted the last update on the anemometer project. The reason for this is that I’m struggling with the aerodynamical design.

By the way: Click here for an overview over the ultrasonic anemometer project: http://soldernerd.com/arduino-ultrasonic-anemometer/

For my very first tests I had misappropriated my wife’s hair dryer to generate some wind. Of course the results wereneither reliable nor repeatable so I built myself this ghetto wind tunnel:

_MG_1235

It’s basically a 120x120mm square tube, made of cardboard and about 1.4m in lenght.

_MG_1239

It’s powered by a powerful 120mm size brushless fan drawing some 2.25 amps at 12 volts. I don’t know about the air throughput but it generates a loooot of wind for a fan this size.

_MG_1240

The legs put it at the right height for the anemometer prototype. There are two holes at the bottom through which the anemometer’s arms can be inserted. The transducers are then nicely centered inside the cardboard tube.

_MG_1242

I can regulate the fan speed using a simple LM317-based regulator. It might look familiar to some of you, it has it’s own post here: http://soldernerd.com/2014/11/10/variable-voltage-power-supply-using-a-lm317/

Unfortunately, the LM317 is only good up to 1.5A so I have to connect the fan directly to my 12V supply in order to run the fan at maximum speed.

As you know, the main indicator of wind speed is the phase shift between the transmitted and received signal. The distance is 0.21m and speed of sound is approximately 340m/s so with no wind, the signal travels about 618us. Signal frequency is 40kHz so one full wave corresponds to 25us. So a full wave (or a phase shift of 360 degrees) translates to a wind speed of around 14m/s or 50km/h.

Note that we usually calculate the difference in phase shift measured forth and back.In that case, the signal already repeats at half that wind speed or 7m/s.

Now my impression was that I don’t get nearly as much phase shift as I should. What makes this difficult is that I don’t know the true wind speed so maybe the wind is just not as strong as I think it is.

I went back and checked my code but didn’t find any bugs there. So I attached the scope to the transducers and looked at the signals directly. And the scope confirmed what I saw on the LCD display. So if there’s a good news it’s that both the electronics as well as the code seem to do what they should: They faithfully report what they get from the ultrasonic transducers. So maybe it’s just the physical design of my prototype that poses too much resistance to the wind and therefore causing too much of a dead wind effect.

I have done some more testing and will follow up on this shortly. Maybe some of you have a piece of advise for me…

Arduino Ultrasonic Anemometer Part 13: Arduino library finally ready

It’s been a while since the last post of this series. As so often, the task turned out to be more demanding than I first thought. And then I was also entirely new to assembly language, got distracted by my Inductance Meter Project (http://soldernerd.com/2014/12/14/arduino-based-inductance-meter/) and went on a skiing holiday. But finally, the promised library is ready.

If you’re new to my Arduino-based ultrasonic wind meter project, you might want to click here for an overview: http://soldernerd.com/arduino-ultrasonic-anemometer/. This is also where you find all the various downloads, including the new library.

Using the new library is easy:

#include <anemometer.h>
extern volatile anemometerResults_t *anemometerCalculationSet;
extern volatile uint8_t anemometerStatus;

anemometerSetup();

You can then access the results as follows (replace NORTH_TO_SOUTH with SOUTH_TO_NORTH, EAST_TO_WEST or WEST_TO_EAST as needed):

anemometerCalculationSet[NORTH_TO_SOUTH].timeOfFlight
anemometerCalculationSet[NORTH_TO_SOUTH].sine
anemometerCalculationSet[SOUTH_TO_NORTH].cosine

I’ll go through the meaning and usage of these one by one:

anemometerSetup()

This function has to be called once before the anemometer can be used:

void setup()
{
  anemometerSetup();
}

anemometerStatus

anemometerStatus notifies your when a new set of measurements has been completed and is ready to use. Every time a new set is ready, anemometerStatus will be set to 1. You have to set it back to 0 once you’re done with your calculations.

if(anemometerStatus==1)
{
   /* use the results */
   anemometerStatus = 0;
}

A new set of results is made available exactly every 250ms or 4 times a second.

anemometerCalculationSet

anemometerCalculationSet is a pointer to the ready-to-use results.

Internally, the library uses a ping-pong buffer. Every time a new set of results becomes available, anemometerCalculationSet is updated to point to the last completed set of results.

The result set pointed to by anemometerCalculationSet is a

anemometerResults_t anemometerResults[4];

where anemometerResults_t is a struct defined as

typedef struct
{
  uint32_t timeOfFlight;
  int16_t sine;
  int16_t cosine;
} anemometerResults_t;

The following #defines may be used as array subscripts:

 #define NORTH_TO_SOUTH 0
#define EAST_TO_WEST 1
#define SOUTH_TO_NORTH 2
#define WEST_TO_EAST 3

timeOfFlight

This is easy to understand. It is the time it takes for the envelope detector to trigger. It is averaged over 32 measurements. Reference point is the rising edge of the first pulse sent. The unit is nanoseconds (ns).

timeOfFlight
Time of flight explained graphically

sine, cosine

sine and cosine indicate the phase shift between the transmitted and the received signal.

This was by far the most challenging part of library. For each of the 32 measurements, 4 rising and 4 falling edged of the zero-crossing detector are evaluated. So the phase shift indicated by sine and cosine is an average over 256 measurements. But phase shifts wrap around, casually speaking.  A phase shift of 359 degrees is almost the same as phase shift of 1 degree. The average should be zero degrees, not 180. Now you could try to solve the problem by constraining your phase shift to the range of -180 to +180 degrees. But that only moves the problem to the other side of the circle: -179 and +179 degrees are almost the same and their average should be 180 degrees, not zero.

I spent quite some time thinking about this and came up with increasingly complex alogrithms that still failed when some unlucky combination of angles was encountered. Remember, we are trying to average n (currently n=256) angles, not only 2.

But of course, many people smarter than me have encountered the problem before and have come up with a perfectly elegant solution: If phi is your phase shift, then calculate sine(phi) and cosine(phi). Sum up all the sines and all the cosines. Then use the arctangent function to convert the summed sines and cosines back to an (averaged) angle. [If wordpress had something like LATEX support, one could state this as a nice-looking formula]

So there is an elegant solution. But there’s also a tight time budget: The zero-crossing detector triggeres every 12.5 microseconds (us). In order to not miss the next zero crossing, we need to calculate both sine and cosine and add them to their respective sum in less time than that. And then there is some overhead like context switching. Plus we also have to do some  housekeeping during that time.

sine and cosine are expensive functions, even more so on a 8bit microcontroller. So the only way was using a lookup table. With this approach I managed to stay within budget (around 10.8us). Besides, missing the next edge is not the end of the world – the edge after that is almost as good.

captureInterrupts
Zero-crossing interrupts are just fast enough not to miss the next edge

So we now have summed sine and cosine values – how do we use them?

atan2(cosine, .sine) gives you the phase shift in radians. Multiply this by (180/PI) if you prefer degrees. My preferred approach is:

(12500.0/PI) * atan2(cosine, sine)

This also gives you the phase shift but with nanoseconds (ns) as unit which makes it directly comparable to the timeOfFlight which is also in ns.

temperature()

There’s also another function returning the temperature. It returns a int16_t containing the temperature in 0.01 degrees centigrade. So if the temperature is 23.45 degrees, it will return 2345.

It’s currently implemented using floating-point math and does not account for the sensor’s (slightly) non-linear nature. It’s there mainly as a placeholder. I’m planning to implement it properly using a lookup-table with interpolation which will make it much faster and will allow it to include the non-linear effects.

Arduino Sketch

The .zip file with the library also includes a very basic arduino sketch using that library. I’m still evaluating what is the best way to calculate the actual wind speed and direction taking into account issues  such as calibration and the like.

But my preliminary results look quite promising and I’m confident that most if not all the heavy lifting has been done.

As always, I highly appreciate any feedback and suggestions. Click here for the next post on this project: http://soldernerd.com/2015/02/17/arduino-ultrasionic-anemometer-part-14-wind-tunnel-testing/

Arduino Ultrasonic Anemometer Part 12: Working on an Arduino library

This is just a very brief update on what I’ve been working on the last few days. By now, this blog has caught up with where the project currently stands so the blog posts won’t be quite as frequent as they used to be. When I just started this series I had already worked on this my wind meter project for two months so I had plenty of material I only had to post.

_MG_1080
Arduino Ultrasonic Anemometer Shield waiting for software

By the way: If you’re new to my Arduino-based ultrasonic wind meter project, you might want to click here for an overview: http://soldernerd.com/arduino-ultrasonic-anemometer/

As you can see in my last post, all the hardware is working really beautifully now so I can focus entirely on the software. So far, the software was really basic, just enough to show the hardware is working. That’s changing now. I’m working on a library to handle all the low level stuff, like setting up Timer1 and handling the interrupts.

One advantage of putting all that stuff in a library is that I can write in native assembler (as opposed to inline assember which I find a pain in the arse). Not everything will be written in assember. But the two I interrupt service routines (ISRs) will be. Everything else will be regular C code I guess. told you in an earlier post that my ISRs were surprisingly slow: around 5us for the most trivial tasks. The TIMER1_COMPB ISR is now re-written in assember and performs about four times faster. For simple tasks, the interrupts take only around 1.2us now.

It took a while but it’s finally ready. Click here for the next post: http://soldernerd.com/2015/01/01/arduino-ultrasonic-anemometer-part-13-arduino-library-finally-ready/

Arduino Ultrasonic Anemometer Part 11: Testing the new hardware

Today I’ll go through each part of my new Arduino shield to see if it performs as expected.

If you’re new to my Arduino-based ultrasonic wind meter project, you might want to click here for an overview: http://soldernerd.com/arduino-ultrasonic-anemometer/

When I first powered on the new shield, only two out of the four transducers worked. As it turned out, I had two different Direction signals on my schematic: one named DIR and one named DIRECTION. They should be one and the same signal but Eagle had no way of knowing about that so they ended up unconnected on the board as well. But luckily it was easy to fix with a piece of wire. After that, the circuit was quite ok. This was the first impression (with some comments of mine):

Shield_overview_01
Overview of the circuit when first powered on

But let’s go through it step by step.

Amplifier

This was the main design flaw of the first version. Yes, it eventually worked but drew much more current than necessary. This one got the gain right the first time as can be seen from the screenshot above. Output amplitude was about 5.6V pp and the signal looked nice an clean.

So all I had to do was to tune the LC tanks to get them to resonate at 40kHz. The inductor has a 20 or even 30 percent tolerance rating and I can’t  measure it. So I had to start somewhere, see how it performs and adjust it from there. I started with a 15nF cap and used a signal generator to find the resonance frequency for each amplifier stage.

AmpStage1_before
Amplifier stage 1 in resonance at 40.98kHz

 

AmpStage2_before
Amplifier stage 2 in resonance at 38.78kHz

At resonance, the phase shift is exactly 180 degrees. Maximizing gain should give the same result but I found it easier to look at the phase shift. Above you see two screenshots: one with the first amplifier stage in resonance at 40.98kHz and one with the second stage in resonance at 38.78kHz.

From that you can calculate how much more or less capacitance you need. It took me 3 attempts to get it really right but the final result looks like this:

AmplifierAfter_200mV
After some LC-tank tweeking the resonant frequency is at 40kHz now

Both stages are perfectly at resonance at 40kHz.

About the biasing: I’ve removed the 10k speed-up resistors R6 and R11. I guess they were unnecessary to start with and they lowered imput impedance too much. I noticed by the fact that there was a noticable voltage drop across the 100k biasing resistors R3 and R4. So while the emitter of the biasing transistor pairs was precisely 1V above ground as intended (I measured 1.015V), the actual amplifier’s darlington pair had it’s emitter only about 0.85V above ground. Not at all what I was looking for.

With the two resistors removed everything is fine. 1V emitter voltage for each of the four darlington pairs. And no measurable voltage drop accross the 100k resistors.

Zero Crossing Detector

ZCD_01
Zero crossing detector at work

I had changed the comparator to a much faster type and this is the result.  Now it triggers exactly at the zero crossing, without any noticable delay.

ZCD_03
Close up of the ZCD: Now it really triggers at the zero crossing

Before it triggered nowhere near the actual zero crossing because it always lagged behind so much. Now this problem is gone and the edges of the ZCD output are very clean and steep. If you zoom in even more you’ll see that  rise and fall times are only around 20ns and there is no overshoot and ringing.

ZCD_04
ZCD: Nice, clean, fast edge

No excuses for the Arduino to not trigger accurately on them.

Envelope detector

EnvelopeDetector_01
The envelope before and after smoothing

I had changed the envelope circuit quite a bit. It has now two op-amp buffered low-pass filters. And this is what I get before the first stage (yellow), after the first stage (pink) and the final envelope (blue).

EnvelopeDetector_02
Envelope smoothing close-up

The first buffer has a gain of 2.5 set by the 15k and 10k resistors (R9 and R10). This has caused the op-amp to rail before the maximum amplitude was reached. I thought about reducing the gain but then decided to leave it as it is.

It doesn’t matter if we cut off the top of the envelope. All we care about is the rising edge, this is what we trigger on. We don’t care what happens after that. So the high gain gives us some more resolution in the area that we care about.

EnvelopeDetector_03
Capturing the rising edge of the envelope

I’m using the same fast comparator for the envelope detector as for the ZCD. And it works just as perfectly here. Above you see how it generates a perfectly clean output signal (pink) when the envelpe (blue) crosses the threshold (yellow).

As you can see, there is still a small amount of ripple in the envelope. I have set the -3db points of the filters quite a bit higher than in the first version: 15k plus 1nF results in about 10.6kHz. So I’m smoothing the envelope quite a bit less than I used to.

I might try increasing the 100k resistor at the input to maybe 150k. That would result in less saw-toothing at the filter input (ENV1 above). But for now I leave it as it is.

Signal routing / multiplexer

I’m now using the second, otherwise unused half of the 74HC4052 to route the PWM signal to the right buffer of the 74HC126. This works flawlessly.

What doesn’t work is routing the pre-biased received signals to the amplifier. Well, the signal does get to the amplifier but look at the shape of the amplifier input (yellow signal) in the overview screenshot at the very top. It gets pulled down to zero every time I change the input channel.

So I had to change that back to how it was in the first version. The unbiased signal goes through the multiplexer and  gets capacitively coupled into the amplifier where it is biased to the right level. But this time I don’t have the -5V supply at the multiplexer any more.

Multiplexer_200mV
An unbiased 200mV signal passes the multiplexer without problem

Here I’m again using a signal generator to generate an unbiased sine wave with 200mV amplitude pp which is applied at the multiplexer input. As you can see above, it reaches the amplifier input in perfect condition.

Multiplexer_minus300mV 2
Biased to -300mV it still works

Even when I biased it to -300mV it passed almost unattenuated. Only when I increased the biasing to -700mV, the amplitude was cut in half:

Multiplexer_minus700mV
At -700mV biasing we lose half the signal amplitude

So I’ve replaced the four capacitors at the multiplexer inputs (C16, C24, C25, C26) with zero-ohms resistors and placed one of them at between the multiplexer and the amplifier input. For this second part I had to do a bit of surgery on the board but nothing major.

Now the amplifier input looks ok:

Shield_overview_02
Amplifier input looks ok now

Crosstalk / Mute signal

I’ve eliminated two of the three multiplexers in this design and was prepared to get quite a bit of cross-talk because of that. This is why I planned ahead and included a mute signal that lets me mute both the amplifier input and output.

Crosstalk_02
Not much of a cross-talk problem

As it turned out, there was not much of a crosstalk problem. Yes, the received signal does pick up some (around 100mV pp) of noise from the transmitted signal but it doesn’t do much harm.

Crosstalk_01
Cross-talk zoomed in

Most of the noise is high frequency spikes and they don’t make it trough the amplifier. Apart from that: We are never transmitting and receiving at the same time. Note that the screenshots above are with the mute signal disabled. So I probabely won’t use that mute functionality going forward. One singal less to worry about. And if I change my mind the circuit is still there.

Temperature sensor / Voltage reference

Not much of a surprise here. I’ve measured the voltage reference output at 2.4989 volts, very close to the rated 2.5V and well within specs.

The temperature sensor also works like advertised. But It seems to be significantly (several degrees) warmer than ambient. I’ve used a thermocouple to measure the temperature of the sensor and the board around it and really found it to be several degrees warmer.

I have placed it a bit close to the LED which heats it up a bit. The orange LED I’ve used turned out to be very efficient so it was very bright with the 330 ohms resistor. I’ve changed that resistor to 1k now and the LED is still quite bright and only consumes a third of the power. But it didn’t help much as far as the temperature sensor is concerned.

Seems the heat is not mainly coming from the LED. Which brings us to the next topic.

Power consumption

I’ve measured the current (at 12V) the arduino was pulling at its DC plug. Since the Arduino is using a linear regulator, current should be independant of input voltage. Anything above 5V is just disposed as heat.

These are my results:

  • Arduino + shield + display: 67.3mA
  • Arduino + shield: 61.0mA
  • Arduino only: 52.4mA

So the display is pulling 6.3mA and the shield another 8.6mA. Most of the current is used by the Arduino itself.

The power consumption of the shield makes sense: Every darlington pair is pulling 1mA, the LED uses about 3mA. Makes 7mA so far which leaves 1.6mA for everything else.

The Arduino is using quite a bit more power than I thought. At 12V this makes about 0.6 watts. Which is probably what’s heating up our shield and the temperature sensor with it.

Summary

I’m quite happy with the new shield. After a bit of soldering everything is working fine. So from now on, this will mainly be a software project. Here’s an update on that: http://soldernerd.com/2014/12/04/arduino-ultrasonic-anemometer-part-12-working-on-an-arduino-library/

Arduino Ultrasonic Anemometer Part 10: Arduino Shield Ready

_MG_1081
A world’s first: Ultrasonic Anemometer Shield for Arduino Uno

I’m happy to announce that my new Arduino wind meter shield is ready. I had posted the design as well as a photo or two of the naked board in my last post but now I’ve placed and soldered all the numerous components and it’s ready to go.

Click here for an overview over this series of posts on the Arduino Ultrasonic Anemometer: http://soldernerd.com/arduino-ultrasonic-anemometer/

_MG_1088
Looking pretty. Any good? Don’t know yet.

So now all my custom hardware boils down to this easy-to-use Arduino UNO shield. Just stack it on top of your Arduino,  attach four ultrasonic transducers and you’re ready to go.

_MG_1090
Bottom side

I have high expectations for this shield and hope I won’t be disappointed. I’ll check on the weekend when I’ll first power it up and see if it’s any good. I’ll let you know.

_MG_1084
Straight from above

Click here to see how the new shield perfoms: http://soldernerd.com/2014/11/30/arduino-ultrasonic-anemometer-part-11-testing-the-new-hardware/

Arduino Ultrasonic Anemometer Part 9: A new hardware

My first wind meter prototype is kind of working. The software will need improvement to make this wind meter into something really useful. But both hardware and software are basically functional and can be built up upon.

If you’re new here, you might want to check out the overview over this series of posts on the arduino-based ultrasonic anemometer: http://soldernerd.com/arduino-ultrasonic-anemometer/.

_MG_1007
The new ultrasonic wind meter Arduino shield

The next thing I will do is re-design the entire hardware. Instead of two distinct boards with wires all over the place I will design a single, standard-sized Arduino Shield that can be stacked on an Arduino Uno. Just like any of those commercially available shields that add motor control, Ethernet or whatever. That will make the whole setup much smaller and simpler. And I hope this will also make it easier for others (like you?) who want to build their own.

This re-design is what I’m going to talk about today so I guess there won’t be much in the way of photos, just some schematics and board layouts. And I’ll put all the Eagle files on the overview page as a zip download. Here’s what I’ve changed and why:

Power supply

The first version used the (unregulated) Vin of the Arduino so it had a linear 5V regulator of its own. On top of that there was also a flying capacitor type inverter to generate a -5V rail for the analog multiplexer. Both of these chips have been eliminated. I’m now using the the 5V rail straight from the Arduino, there is just a 100uF tantal input cap. The -5V is no longer needed by the multiplexer. I’ll later explain why.

Signal routing / pulse generation / drive

The drivers are entirely new: I’ve replaced the two 74HC368 inverters with a single 74HC126 non-inverting line driver / buffer. It has four 3-state buffers, one for each transducer. The negative pin of each transducer is simply grounded in the new design. That costs us half the signal amplitude but simplifies things greatly. And our two-stage amplifier should have more than enough gain to make up for that.

As suggested earlier, there is only a single 74HC4052 left (instead of 3). We will get some crosstalk issues but we’re always transmitting or receiving, never both at the same time. Plus, the tuned amplifier filters out most of that high frequency stuff (such as square waves). And we have the option to mute the amplifier, this time both at the input as well as on the output. Not sure if we’ll need it, I’ll check once everything else is working.

Permanently grounding the negative pin of the transducers means we only have four signals to worry about. So I’m only using half of the 4052 to chose exactly one of the four signals. Y0, Y1, Y2, Y3 as inputs from the four transducers and Y as output that goes to the amplifier.

But why don’t I need the -5V anymore? Here is why. In my first design I routed the signal from the transducers straight through the 4052. Because this signal swings around ground, it will be negative half of the time and positive the other half. So I needed both a negative and a positive supply. Later, that signal was capacitively coupled into the amplifier where it was biased so somewhere around 2.3 volts. Now I already do the biasing before the 4052. So the signal will be positive at all times and hence there’s no longer a need for a negative voltage. I find this a really elegant solution, I just hope it will work 😉

There is still an Axis and Direction signal controlling a 74HC139 encoder generating the enable signals for the transducer drivers / output buffers. I had LEDs on these enable signals in the first version, these are no longer present. The software changes the axis/direction every 2ms so you won’t be able to see anything now.

The 74HC126 has active high enable signals (as opposed to the 125 which is otherwise identical). Since all but one enable signals are high, only one transducer can float freely. That’s our receiving transducer. That also means that the other 3 transducers are actively driven so only one of them must receive the PWM signal.

This is how I’ve solved this: As I said, I only used half of the 4052 for the tranducer signals. So the other half can be used to route the PWM signal from the Arduino to the correct output buffer. So the signal from the Arduino is connected to the input X and the outputs X0, X1, X2, X3 carry the signal to the different gates of the 74HC126. There is one potential problem: The outputs that are not selected are floating freely so there are 10k pull-down resistors on X0, X1, X2 and X3.

So from the 8 large ICs on the first version, only 3 are left. That saves plenty of board space so we can fit our circuit on a standard sized Arduino shield.

_MG_1008
Same board from the other side

Amplifier

The basic design with two stages of tuned common emitter amplifiers with NPN darlington pairs has worked well so I’ll stick to that.

The main shortcoming of my first version was the 47uH plus 330nF LC tank (see part 4) so I’m changing that to 1mH plus 15.82nF. Same resonant frequency but much higher impedance. The inductor I’ve chosen has a dc resistance of a bit more than 16 ohms which will give a Q-factor of around 15 – comfortable for our application.

The main change is the biasing. A wind meter will be deployed outside so it is likely to see great variation in temperature. So the biasing of our amplifier and thus the quiscent current need to be stable over a wide temperature range. Two things make this a difficult task here: First, we’re using darlington pairs which means twice the variation in base-emitter drop. Second, our rather low operating voltage of 5 volts.

A common solution for difficult biasing situations is the use of a matched transistor to generate the base biasing voltage. And that’s what I’ll do here. Each stage has an additional darlington pair with collector and base connected for this purpose. So the collector will always be 2 diode drops (around 1.3V at room temperature) above its emitter. I want the emitter to sit 1V above ground and 1mA of quiscent current. So I add a 1k emitter resistor and a 2.7k collector resistor and get just that.

Base emitter drop will change by about -2mV per degree per transistor. So for a 50 degree increase in change in temperature, the drop accross our darlington pair will change from 1.3V to 1.1V – quite substantial. But quiscent current will only increase to 1.054mA and the emitter will then sit 1.054V above ground. A 5.4% variation for a 50 degree change in temperature. Not bad at all I think.

The last change to the amplifier is that I’ve put the gain limitting resistors (R7 and R12) in series with only the bypass caps (C5 and C10).  This will let me change the gain without affecting biasing which is given by R8 and R13.

Zero Crossing Detector (ZCD)

Almost no change here. I’ve only changed my comparator to be a Microchip MCP6561R. It has a worst-case propagation delay of only 80ns which is 100 times faster than the one I used last time. And it’s still cheap: CHF 0.43 at Farnell if you buy 10.

Envelope Detector

I told you earlier that I had some trouble with my last envelope detector which utilized a VCVS active low-pass filter. If I turned up the gain too much I got wild output swings. I found a screen shot of that:

send_receive2
Envelope going wild

Green is the amplifier output. We’re trying to get the envelope of that. But look what happens to the pink line when I turn up the gain. Nothing to do with an envelope. And I would like even more gain to make the envelope use (almost) all of the 0…5 volts range.

I haven’t really understood why that is. Suggestions anyone? The only thing I can think of is the rather narrow gain-bandwidth product of the op amp, 600kHz if I remember correctly.

So I’m using two op-amp buffers, each followed by a normal RC low-pass filter. So I can set any gain I want for the two buffers without affecting the signal shape. As an added benefit, I can now look at the signal after each buffer / filter. I’ve also changed the op-amps to be Microchip MCP601R. Less precise (we don’t need precision here) but fast (2.8MHz) and cheaper.

At the very input of the envelope detector I’m now using a second (not really matched but same type) diode (D2) to produce a bias voltage just a diode drop above ground to precisely compensate for the rectifying diode (D1) of the envelope detector.

The comparator at the output is now a MCP6561R as for the ZCD. Not that we need the speed here, just to use the same type.

Temperature measurement

Everything new here. LMT86 as a temperature sensor. Cheap, works from -50 to +150 degrees centigrade and is accurate to 0.4 degrees. Its output is between 1.5 and 2.5volts over the temperature of interest. It comes in a SC-70 package. That’s a bit small but still hand-solderable without problem.

There is no more op-amp to scale it up but I’ve added a rather precise 2.5V voltage reference, the ADR361. Quite an overkill maybe but I thought if you are measuring wind speed you are likely to also measure things like humidity, pressure, light intensity or something like that. So with the anemometer shield you get a precise and stable reference for all your measurements.

Summary

As you can see, I ended up changing quite a lot. When laying out the board I was surprised how easily everything fitted in. Not only did the fewer logic ICs save space themselves, it also greatly simplified signal routing. As you can see from the photos, I’ve already made a board. All the components have arrived as well so I’m ready to go ahead and build it up. I’m really looking forward to seeing how it will perform. I just hope everything works as planned.

All the board and schematic PDFs as well as the Eagle files can be found on the overview page as a .zip file: http://soldernerd.com/arduino-ultrasonic-anemometer/

That’s it for now, click here for the finished shield: http://soldernerd.com/2014/11/28/arduino-ultrasonic-anemometer-part-10-arduino-shield-ready/

Arduino Ultrasonic Anemometer Part 8: More Software

In my last post I talked about how to get the Arduino to output bursts of 40kHz pulses. Today I’ll go through the rest of the software so by the end of this post we’ll have a very rudimentary but working sketch for our ultrasonic wind meter.

Click here for an overview over this series of posts on the Arduino Ultrasonic Anemometer: http://soldernerd.com/arduino-ultrasonic-anemometer/

overview2_1ms
Overview over one round of measurements, i.e. each direction is measured once in turn.

If you’ve read part 7 of this series you will have noticed that all the key tasks are handled not in the main code but in interrupt service routines (ISRs). That’s fairly typical for an application like this one.

In this project, there are 2 ISRs:

  • TIMER1_COMPB Interrupt: It is triggered by Timer/Counter1. It sends 15 PWM pulses every 2ms and takes care of the Axis, Direction and Mute signals. Named TMR_INT on the screen shots in this post. This is what I’ve covered last time.
  • TIMER1_CAPT Interrupt: This is where all the measurement takes place. It is triggered by the envelope detector and zero-crossing detectcor. It reads the current value of Timer/Counter1. Named CAPT_INT on the screen shots in this post. This is what I’ve covered last time. This is mainly what I’ll be covering today.

The basic Idea of the software is as follows:

  1. Every measurement takes 2ms. It takes 375us (15 times 25us) to send the pulses plus 500us – 1500us for the pulses to arrive (assuming very extreme wind situations). So 2ms gives us plenty of time to finish our measurement.
  2. Shortly after sending the pulses we start listening and wait for the envelope detector to trigger TIMER1_CAPT interrupt. We save the current value of timer1, this is our coarse measurement of time-of-flight. We then set up interrupts to capture a rising edge of our zero-crossing detector (ZCD).
  3. A rising edge of our ZCD triggers TIMER_CAPT interrupt. We save the current value of timer1 and set up interrupts to capture a falling edge of the ZCD.
  4. A falling edge of our ZCD triggers TIMER_CAPT interrupt. We save the current value of timer1 and set up interrupts to capture a rising edge of the ZCD.
  5. Repeat steps 3 and 4 until we’ve captured 8 rising and 8 falling edges. Averaging these will give us a very precise measurement of the phase shift.
  6. After every measurement we change the direction we measure:  N->S, E->W, S->N, W->E, …
  7. We measure each direction 32 times until we calculate the actual wind speed. So one full measurement will take 4 x 32 x 2ms = 256ms. So we take about 4 measurements per second.
overview2_172us
Overview over a single measuement

The screen shot above shows how a measuement proceeds: AXIS and DIRECTION are set depending on the direction to be measured. MUTE is driven high and 15 PWM pulses are sent. TMR_INT  triggers after every pulse in order to count them. After a short break, TMR_INT triggers again and turns MUTE off again. Eventually, the envelope detector (ENV_DETCT) triggers CAPT_INT. Shortly afterwards, CAPT_INT is triggered 16 more times by the zero-crossing detector (ZCD).

overview2_35us
Close-up of the actual measurement.

There are 2 sets of variables to save all the measurements from the envelope and zero-crossing detector: At any point in time, one is in use by the ongoing measurements, i.e. they’re being updated. The other set represents the last set of measurements and is static. This second set can be used by software in our main loop to calculate the wind speed and direction. As I’ve said, capturing one set of measurements takes 256ms. So we also have 256ms to do all the calculations, send data (via USB or whatever), write the new measurement to the display, do some data logging or whatever else we have in mind. There is likely to be some floating-point math, square roots and tigonometric functions going to be needed to arrive at the wind speed and direction but 256ms should be pretty comfortable even for that.

overview2_8ms
A long series of measuements. Look at the cursors: It takes about 25ms to do our calculations.

This is what I’ve tried to show in the screenshot above: There is a signal named CALC which is driven high when a new set of measuements becomes available and driven low when the calculations are finished. So this signal shows you how much time the Arduino’s Atmega328 spends processing the data and writing to the display. As you can see, it’s less than 25ms so there is ample of room for more complex calculations or other tasks. We’ll definitely need some of that head room since the calculations performed so far are really just the bare minimum.

There definitely is still a lot to be improved, mainly how the raw measurements are evaluated to get the actual wind speed. But what’s more important to me at this time is that the basic idea/setup works. With no wind, my measuements fluctuate somewhere between plus/minus 0.3 meters per second without having done any calibration. It also reacts nicely when I blow a bit of air towards it.

I’ve changed the pinout many times while developing this software but I’m confident that I won’t have to change the pinout any more. So my plan is to now build version 2 of the hardware first. The entire setup will be much less complex (and prone to errors) without all the lose wires going back and forth between the different boards. Then, with the updated and hopefully final (or nearly final) hardware I’ll go ahead and finish the software.

Speaking of software: You can download the Arduino sketch from the overview page where you also find the Eagle files for both boards: http://soldernerd.com/arduino-ultrasonic-anemometer/. I’ll make it a habit to post all the download material for this project on the overview page so people don’t need to go through all the posts trying to find a certain file.

That’s it for today, continue here to my next post of this series: http://soldernerd.com/2014/11/25/arduino-ultrasonic-anemometer-part-9-a-new-hardware/