Tag Archives: wind meter

Ultrasonic Anemometer Part 15: A new attempt

It’s been about one and a half years since I started out with my ultrasonic anemometer project. Like others before me I had to notice that this a much more demanding project than it appears to be at first. After countless hours of development and testing I have built this Arduino shield. It worked but the reliability of the measurements was never what I had aimed for. The problem was mainly how to figure out the absolute phase of the received signal. So the measurements were always precise – but sometimes off by a full wavelength.  Then I was more or less inactive for most of 2015, mainly due to personal reasons. So the project was kind of stuck but i kept (and keep) getting a lot of encouraging feedback from you folks. I came up with new circuit ideas and decided to pretty much start with an entirely new design and to re-think each and every design choice I had made back then.

20160224_Projekte_074

I will now outline and explain my new design for the send/receive circuit. So the board we are looking at today will handle the signal routing from the microcontroller to the individual transducers and from the transducers back to the amplifier where it is cleaned-up and amplified. There’s the circuit explained step by step.

20160224_Projekte_054

Powerful 12V drive

My last design drove the transducers from a 74HC126 line driver / buffer. This chip has tri-state outputs which made it easy to switch to receive mode by releasing the respective transducer. It also has a strong (for a logic IC) output drive of up to 125mA to switch the capacitive load that the ultrasonic transducers present.

Unfortunately, the drivers only provided a 5V amplitude. Even worse, a more contemporary design would probably operate from a voltage of only 3.3 volts potentially making things worse in the future. So I decided to use a pair of Texas Instrument LM5111 Mosfet drivers. They can handle up to 18 volts so I can run them at a 12 volt input voltage directly. Mostet drivers are designed to drive large capacitative loads so they typically have powerful outputs. Specifically, the LM5111 can sink and source 5 and 3 amps, respectively. Thats more than any logic chip could ever provide. They also share a industry standard pin-out so they are easy to replace should the LM5111 not be readily available from your preferred supplier.

20160225_Projekte_083

Discrete Mosfet Switches

The downside of using a Mosfet driver is that they lack the handy tri-state output. So I had to find another way to release the transducers for receive mode. Readily available  integrated switches and multiplexers don’t have the low Rds-on that we need here. And they are definitely not happy if you’re trying to pass 5 amps through them. So I decided to use a discrete p-channel Mosfet for each transducer. With the gate at -5V the Mosfets conduct in the 0 to 12V range of the driving signal with a on-resistance of far below 1 ohm. So the  strong drive of the LM5111 is not forfeited. With the gate at +5V the Mosfet is not conductive for signals a few volts around ground. So the receiving transducer can swing freely, unaffected by the LM5111.

Op-Amp Amplifier and Filter

The last design used a tuned two-stage common emitter amplifier. I found the design quite beautiful with nice biasing and everything but there were severe drawbacks. Mainly, the LC tank had to be tuned carefully to have it’s center frequency at 40kHz. Coils especially have large tolerances, plus/minus 20% is quite typical. This makes it at least difficult to produce any quantity of these things efficiently. It also takes some test equipment to see if your resonant frequency is correct so the design is not really suitable if you want to distribute it as a kit.

So this design uses a dual op amp at its center. I’ve decided to use a Texas Instrument LMC6482. This is an affordable precision OpAmp with rail-to-rail inputs and outputs that can run from a wide range of supply voltages. One of its main advantages for this application is its slew rate of 1.3 volts per microsecond. This is not especially much or especially little. But it’s just right for us. And this is why: A 40kHz signal with a peak-to-peak amplitude of 10 volts needs a maximum slew rate of 1.25 V/us. So 1.3 volts is enough when operating from a +/- 5V supply. And because it is just enough it will quite effectively block any high frequency noise/spikes that might be present at the input. This is a trick I’ve learned from Horowitz & Hill’s classic Art of Electronics. It’s my first time to use it so I’m exited to see how it works.

For now, the gain of the amplifier is controlled via a pot. Future designs will probably have a fixed gain once I’ve figured out how much gain we need.

20160224_Projekte_071

Active Bandpass Filter

Just in case the slew rate limitation of the op amp isn’t enough to get a nice, clean output signal I have planned ahead and used the second op amp from the dual LMC6482 for an active band pass filter.

I’ve played around with an Excel spreadsheet and LT Spice for a few hours trying to find suitable values for the various resistors and capacitors. I’ll do some more experimenting once I can test the results on the real circuit. So don’t pay too much attention to the compoent values of this filter for now.

20160225_Projekte_085

Signal Routing via 74HC4052 Dual 4-Channel Multiplexer

This is something that hasn’t changed much. The 74HC4052 has already been part of my last design. I’m now using two of them, one for transmitting and one for receiving.

The first half of the transmitting multiplexer  (IC2 in the schematic) takes the PWM signal from the microcontroller and sends it to the correct Mosfet driver according to the axis and direction signals that control which transducer is sending and receiving. The second half of that IC releases the receiving transducer located opposite of the transmitting one. It does so by providing +5V to the corresponding p-channel mosfet. Pull-down resistors to the -5V rail ensure that the mosfets are conducting when not actively turned off. The +5V release signal can be controlled from a microcontroller pin. Not sure if we need this functionality so a future version might just connect this signal directly to the positive rail.

The first half of the receiving multiplexer (IC1 in the schematic) routes the signal from the receiving transducer to the amplifier input. Note that there are 10k pull-down resistors on the floating leg of the transducers so the received signal is centered around ground. In order to avoid cross-talk, the second half of IC1 actively grounds the transmitting transducer’s signal. In order to make this possible, there are 10k resistors in the signal path before the multiplexer. Given the very hight input impedance of the op amp this should not have a negative effect.

20160225_Projekte_079

Power Supply

This circuit runs from a 12V input voltage that is directly used for the mosfet drivers. For everything else, a linear regulator generates a +5V rail. An ICL7660 inverts this voltage to generate a -5V rail. The multiplexers and the op amp then run from this +/- 5 volt supply. This is somewhat of a complication compared to the sleek plus-five-volt-only approach that I took with the Arduino shield. But this gives us a much stronger 12V drive on the transducers even if a future design will run on +/- 3.3 volts. And the split supply allow for easy control of the discrete p-channel mosfet switches and ground referenced signals in the receiving circuit.

20160224_Projekte_070

On-board Microcontroller

I’ve included a PIC16F1936 on the board. No, I don’t have any plans to use a PIC16 in my final design. I just thought it is convenient to generate the singals necessary for testing right on the board. I do consider using a dedicated on board microcontroller in my final design. I see several advantages of doing so. The design would no longer be Arduino specific. You could still interface it to an Arduino using a  standard I2C or SPI interface. But you could also interface it to a Raspberry Pi or just about anything else. That would make it much more flexible and versatile. And even if you interface it to an Arduino the Arduino is free to focus on other things than handling the technical details of running the wind meter. With the shield one had to pay close attention not to upset the timing by running other code. So a design with an on-board chip would be easier to use as well.  Cost would not really be an issue since powerful microcontrollers are available for around 2$ even in modest quantities.  Feel free to share your thoughts on this. I’m currently looking at different architectures but no decision has been made yet.

This is it for now. In my next post I’ll share my test results with this circuit. The Eagle files and PDFs are available as a download on the project overview page.  As always I very much appreciate your comments and suggestions.

Arduino Ultrasonic 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: https://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 (https://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: https://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: https://soldernerd.com/2015/02/17/arduino-ultrasionic-anemometer-part-14-wind-tunnel-testing/

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: https://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: https://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: https://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: https://soldernerd.com/2014/11/30/arduino-ultrasonic-anemometer-part-11-testing-the-new-hardware/

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: https://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: https://soldernerd.com/2014/11/25/arduino-ultrasonic-anemometer-part-9-a-new-hardware/

Arduino Ultrasonic Anemometer Part 7: Basic software

Today I’ll tell you how I got started with my software. If you’re new to my blog you might want to click here for an overview over my arduino-based wind meter project: https://soldernerd.com/arduino-ultrasonic-anemometer/

The first thing we’ll need to archive is to send a series of pulses at 40kHz which is the frequency the ultrasonic transducers work. They must be as precise and repeatable as possible since all our measurements depend on them. Any jitter and the like will affect our measurements. And the duty cycle should be 50%. So you really want to do them in hardware. The Atmega328 comes with a single 16-bit counter/timer (Timer/Counter1) as well as two 8-bit counters (Timer/Counter 0 and 2). We’ll need the 16-bit resolution so the choice is clear: Timer1.

Timer1_output
Sending pulses using timer/counter1

Well yes, you could easily use one of the 8-bit counters to generate your pulses but you’ll still need timer1 for measurement. I’ve decided to do everything with just one timer so it’s going to be timer1.

How many pulses we should send is not so clear. I’m working with 15 pulses which works quite well but I’m not claiming it’s an optimal choice. But it is short enough to make sure we’ve stopped transmitting before the first sound waves reach the opposite transducer, even with heavy tail wind.

Since we have such strict requirements for our pulses, we can’t rely on any of those convenient high-level functions to set up our timer but have to study the Atmega328 datasheet and do it ourselfs.

This is what I have done:

pinMode(10, OUTPUT);
TCCR1A = 0b00100011;
TCCR1B = 0b11011001;
OCR1AH = 0x01;
OCR1AL = 0x8F;
OCR1BH = 0x00;
OCR1BL = 0xC7;

This is a short explanation of what it does: Set pin 10 as an output. Arduino pin10 is pin16 of the Atmega328. And that’s the pin connected to the output B of timer1. That’s line 1.

I then set up counter1 in FastPWM mode running at the full system clock frequency of 16MHz. Output B (that’s our pin 10 on the arduino) is set high when the counter starts at zero. It will be cleared (i.e. set low) when the timer reaches the value in output compare register B (OCR1B). The counter will be reset when (i.e.it will start at zero again) when it reaches the value in couput compare register A (OCR1A). I also enable an interrupt for when the timer overflows. More on that later. That’s lines 2 and 3.

Then comes the part where I actually set duty cycle and pulse with. I do that by setting the output compare registers. OCR1AH and OCR1AB are the high and low bytes of register OCR1A. So the final value in that register is 0x018F which equals to 399. That means counter 1 will count from 0 up to 399 before it starts again. That’s 400 steps. And here’s the math: The timer runs at 16MHz, our counter will overflow every 400 cycles. 16000000 / 400 = 40000. That’s exactly the 40kHz we’re looking for. The duty cycle is set to half that time by setting OCR1B to 199 or 0x00C7.

That’s it. We have a perfect PWM signal at exactly 40kHz and 50% duty cycle. Look at the screenshot above to convince you that this is exactly what we are getting.

But so far, the pulses go on forever. What we need is a way to turn the output signal off after 15 (say) pulses. One way of doing that is to count the pulses and turn the output off once the 15 pulses have been sent. That’s what the interrupt at overflow is used for.

In that ISR (interrupt service routine) I increment the variable pulse_count. Once pulse_count reaches 15 I know that all the pulses have been sent and turn the output off: TCCR1A = 0b00000011; The timer/counter will continue to run but the PWM output has been turned off.

For debugging/monitoring purposes, I set pin A5 high at the beginning of the ISR and low at the end. So I can tell when (and how long) the ISR is running by monitoring pin A5. Here’s what I get:

Timer1_overflows
Pulses sent (yellow) and time spent in timer interrupts (blue)

The yellow signal is the PWM output (pin10) as before. The blue line shows the time spent handling the interrupt. I could then continue counting without sending any pulses and turn the output back on when I reach 80 for example. And at the very beginning that’s exactly what I did. But then the microcontroller has to handle an interrupt every 25us (microseconds) even when not sending pulses. That’s quite wasteful so I set a longer time period by increasing the OCR1A and OCR1B registers seen above.

Actually, I’m using this interrupt to do some other things as well such as setting Axis and Direction as well as the Mute signal and some other housekeeping. That wide blue pulse you see at the left side of the screenshot above does most of that, that’s why it is so wide.

TimerInterrupt
Time consumed handling a regular timer overflow interrupt

Speaking of time consumed handling interrupts. It’s quite significant as you can see here: About 5 microseconds for a normal (just counting) interrupt. That’s 20% of CPU time while sending pulses (5us every 25us). That’s muuuch more than I ever imagined it to be. That’s about 80 instructions. I’m writing in C so I’ll have to check the assember code produced by the compiler to see what’s going on.

Click here for the next post of this series: https://soldernerd.com/2014/11/23/arduino-ultrasonic-anemometer-part-8-more-software/

Arduino Ultrasonic Anemometer Part 6: Mechanical design

If you’ve read through my previous posts of this series you know that here is an Arduino and two home-made PCBs together with 4 transducers waiting to work together as an ultrasonic wind meter. If you haven’t you may click here for an overview of posts on my anemometer project: https://soldernerd.com/arduino-ultrasonic-anemometer/https://soldernerd.com/2014/11/19/arduino-ultrasonic-anemometer-part-6-mechanical-design/

20141003_200928
Milling the base plate.

For this wind meter to work, the four transducers need to be held in place somehow. Even during testing and development I wanted some reliable mechanical setup so that I don’t need to worry about it all the time. For this prototype I don’t need anything waterproof that I can put outside for a prolonged period of time. Anyway it will be sitting on my bench most of the time so wood works just fine for me.

Here two videos of the CNC milling machine at work:

The transducers are 16mm in diameter. 16mm plastic pipes are readily available from hardware stores. They are intended for electrical wiring so you also get matching angles and the like. So I got myself 8 90-degree angles and a 2m pipe from a local hardware store. I think I’ve mentioned before that I want the transducers to sit in a 20cm distance so make the wind meter rather compact.

20141008_195838
More CNC milling.

I’ve just recently attended a CNC machining course at the Zurich Fab Lab (http://zurich.fablab.ch/) so I decided to do my first CNC milling project and use my newly aquired knowledge to make a wooden base to hold the plastic tubes (and PCBs) in place.

20141006_221337
Mounting the PCBs. Still using my Arduino Mega here.

I’ve used some left over 18mm melamine-coated multiplex. It’s extremely sturdy and has a nice smooth surface. I ran my first tests with a Arduino Mega so that’s what you see above but I’ve replaced that with a Uno by now. So all the software development will take place on an Arduino Uno and its Atmega328.

20141016_180424
My prototype sitting on the bench

Besides the two boards you already know, there is a 2×16 characters LCD. I thought it would be nice to have a display connected to the Arduino when writing the software. Just to see what you’re doing. An easy way to drop some debugging output and of course display the measurements once we are ready to actually run this thing.

20141016_180446
View from above

There is a little PCB attached to the LCD display. It mainly holds a trimmer to adjust the contrast as well as a resistor for the backlight LED. Since I had to make a board anyway I also included a 10uF plus 100nF ceramic capacitor as well as a protection diode.

20141016_180502
Lots of wires to connect everything

As you can see from the photos above, there are definitely more and longer wires than necessary. But for a prototype I’m always reluctant to soldering things and cutting wires to their minimal or optimal length. I like to be able to just unplug a board and do some changes to it.

When I started writing my software I didn’t have a clue which signal will be on which pin. I just plugged them in as I went along. And I changed it several times until I was finally happy with it. So I do need some flexibility. But it also makes the setup a bit of a mess I must admit.

Ok, the hardware is working now. Time to write some software and see if we get it all up and running. See you next time.

Click here: https://soldernerd.com/2014/11/21/arduino-ultrasonic-anemometer-part-7-basic-software/

Arduino Ultrasonic Anemometer Part 5: Testing the digital board

In the last post I went through the analog board and showed what I had to do to get it working properly. Today I’ll do the same whith the digital board. Click here for an overview over this series of posts on the anemometer project: https://soldernerd.com/arduino-ultrasonic-anemometer/

_MG_1021
The corrected digital board

So I plugged in the board for the first time and everything looked fine. The power LED came on, both the +5V and -5V rails worked as expected. But not everything worked that well.

I’ve explained in a previous post how the Arduino can control the direction by means of two lines: Axis and Direction. Here’s the meaning of these signals (L=low, H=high):

Axis=L, Direction=L -> North to South

Axis=L, Direction=H -> South to North

Axis=H, Direction=L -> East to West

Axis=H, Direction=H -> West to East

The first thing these two signals do is to control 74HC139 address decoder. The 139’s enable signal is grounded so its outputs are always on. Depending on Axis and Direction the 139 turns exactly one of the signals North_EN, South_EN, East_EN and West_EN on. EN stands for enable. As the bar over the signal name indicates, these are active-low signals. So zero volts means on and 5V means off. Each of these enable signals is connected to an LED. The other side of the LEDs is connected (via a resistor of course) to +5V so the LED is on when the signal is on despite the fact that it is active low. This part also worked.

Then we have two 74HC368 hex inverters. If you look at the 368s data sheet you’ll notice that it consists of 6 inverting buffers. But there are only two enable signals. As with most enable signals, these too are active-low. One enable signal controls 4 of the inverting buffers while the other one controls only 2. For us, this doesn’t matter since we need a total of 4 groups (one for each transducer) of 2 buffers each (one for each transducer pin). So we’ll only use two buffers of each group no matter if there are four.

Each group is controlled by one of the enable signals coming from the 139. The North_EN signal enables the buffers of the group connected to the North transducers and so forth. So exactly one group of buffers is on at any given time. That’s the transducer that is transmitting. All 4 buffer groups are connected to the same PWM signal (named Signal on the schematic) coming from the Arduino. But since only one buffer group is on, only that transducer is actually sending. The other buffer outputs are off and their transducer pins can float freely. Notice how the PWM signal is connected to the input of only one of the buffers in each group. The output of that buffer ist then connected a transducer pin as well as to the input of a second buffer. So one pins of the transmitting transducer are always in opposite states. When the first one is high, the second one is low and vice versa. There were no surprises here, everything worked as expected.

AxisDirection
How Axis and Direction control the 74HC139

Here’s a little visualization of the 74HC139 in action. Note the glitches in the West_EN and East_EN signals. The Arduino can’t change both Axis and Direction perfectly simultaneously, there will always be at least one clock cycle in between the two commands. That’s why those glitches happen. But Axis and Direction are changed between measurements so nothing interesting is going on anyway. No need to worry about this here.

But then there is the task of selecting the right signal to listen to. And that’s where I’ve messed up just about everything. I guess I just wanted to build my first prototype as soon as possible and didn’t double-check everything as I should have. I probably also tried to be clever and use as few signals as possible and chose my inputs so that it simplifies the physical routing on the PCB. Anyway, I ended up with a design that doesn’t work. So if you want to build this circuit, look at the RevB board and schematics where I’ve corrected the mistakes.

As explained before, there are three 74HC4052 multiplexers to eliminate crosstalk. Like the 139, the 4052s are controlled by Axis and direction. But watch out: You need to select the transducer opposite from the one that is transmitting. So for example Axis=L and Direction=L means North to South. North_EN is low so the North buffer group is on and so North is transmitting. That means we have to chose the South transducer for receiving. Nothing complicated, really. But you have to concentrate and think carefully about which transducer has to connected to which of inputs. There are multiple solutions that work but many more that don’t.

My working solution is as follows: IC5 selects between North and East. So North is connected to input 1 while East is connected to input 3. When we want to listen to North, East is idle and vice versa. That’s why we get rid of crosstalk. The negative output of IC5 is grounded, the positive one is named NorthEast and routed to IC6. The second multiplexer, IC7 selects between South on input 0 and West on input 2. Again, the negative output is grounded and the positive output named SouthWest is connected to IC6. IC6 then only has the simple task of choosing between SouthWest and NorthEast. That’s why I only needed my Direction signal to control this multiplexer. The other address input can be left grounded.

I didn’t bother building another board so I’ve just used some pieces of wire to correct my mistakes. The corrected circuit is equivalent to what you see on the RevB schematic and works flawlessly.

This was definitely not my most interesting post so far. Lots of text and much in the way of photos or screenshots. Analog circuits are usually more fun to work with I find. Next time I’ll connect the Arduino to my two boards and show you how they perform. There will be some photos and screen shots again, promise.

Click here for the next post: https://soldernerd.com/2014/11/19/arduino-ultrasonic-anemometer-part-6-mechanical-design/

Arduino Ultrasonic Anemometer Part 4: Testing the analog board

In this post I will go through the testing of the analog circuit and what I had to do to make it work properly. Click here for an overview over this series of posts on the anemometer project: https://soldernerd.com/arduino-ultrasonic-anemometer/

20140930_223552
A first, basic test setup.

Ok, so the the analog board is finally ready and all the components have been soldered into place. Time to see if it works as expected. My test setup looked as follows: I’ve programmed an Arduino (a Mega as you can see in the background, I didn’t have a Uno at that time but it doesn’t matter for what I’m doing here) to output 15 pulses at 40kHz from one of its pins (followed by a break of a few milliseconds). That pin was connected to one of the pins of a transducer while the other transducer pin was grounded. A second transducer was placed accross from the first one in a 20cm distance. That’s the distance/size I’m planning to use in the final design as it keeps the wind meter nice and compact. One pin of that second transducer was grounded while the other one was connected to the amplifier input of the analog board. So there are only 2 transducers at this time. One constantly transmitting, the other constantly receiving. Software is also minimal. Keep it simple for now, we’re just trying out the analog circuit.

Amplifier

send_receive
Transmitted signal and amplifier in- and output.

Here we have the transmitted signal in red at the bottom left, together with the amplifier input (yellow), output of the first stage (green) and output of the second stage (purple). On the positive side, the received signal (amplifier input) is quite strong, around 350mV peak-to-peak. But the amplifier is barely working. At the output of the second stage we want a signal in the range of 5V pp but we get just a bit more than 700mV. We’re using a two-stage tuned amplifier and only double the signal amplitude. That’s hopeless.

As I’ve said in part 3, the root cause for this is my poor choice for the inductor/capacitor combination. 47uH or 330nF at 40kHz only give an impedance of 12 Ohms. Even with a decent Q-factor the impedance across the LC tank will never be high enough. I’d rather use something like 1mH / 15nF or 470uH / 33nF as as Carl did. But I didn’t have a inductor like that at hand so I had to change some other components to fix it.

First I changed the bypass capacitors (C5 and C10) from 100nF to 1uF. That makes the emitter ‘more grounded’ at signal frequencies (4 ohms instead of 40 ohms if you do the math). That did help but was not enough to save the show.

I then changed the emitter resistors (R8 and R13) from 330 ohms to only 47 ohms. The logic behind this is simple: The voltage across the LC tank is too small because the impedance is too low. Voltage is current times resistance (or impedance). I can’t change the impedance because I don’t have a suitable inductor so I have to increase the current. Changing the base resistors does just that.

Now I have plenty of gain at the price of a much-higher-than-planned quiescent current. Actually, gain was even a bit too high so I put in 15 ohms for R7 and R12 to slightly reducing the gain. Power consumption is not really a concern in this prototype so we’re fine for now. But if you’re going to build your own, use a big enough inductor in the first place and you won’t have to jerk up the current just to squeeze out enough gain.

amplifier_400us
Amplifier after fixing the gain

Amplifier input (yellow), output of the second stage(green) and output of the second stage (purple). Note the different scales of 200mV, 1V and 2V per division. As you can see, the gain’s fine now. We’re getting a bit more than 4 Volts of amplitude peak-to-peak which is just what we need.

amplifier_20us
Close-up of the amplifier signals

You can also see how much cleaner the output is compared to the input. The yellow signal has picked up quite a bit of noise gut the purple signal looks perfectly clean. That’s the benefit we get from the narrow bandwidth of the tuned amplifier. And that’s why you don’t want to just use an op-amp.

Envelope detector

Let’s turn to the envelope detector now. Fortunately this part worked right from the start but that doesn’t mean it can’t be improved. I’ve used a voltage divider of 1M and 47k (R14 and R15) to get a voltage of 2.2 Volts which just about compensates for the drop over the schottky diode D1. Maybe I’ll use an identical diode in my next design to get a voltage exactly one diode drop above ground.

lowpass_filter
Envelope before and after smoothing

Here we see the transmitted signal (red) together with the amplifier output (purple), the output of the diode / input of the low-pass filter (green) and the filter output (yellow). Note how the filter makes the stairs in the green signal disapear. That’s exactly its purpose.

I found the envelope to be a bit slow so I’ve changed the resistors R16 and R17 from 47k to 22k. Together with the 1nF caps (C15 and C16) that gives a -3db point of 7.2kHz. That makes the envelope quite a bit faster which means the rising edge will also be steeper. That makes it easier to precisely trigger on it, provided it is still smooth. Obviously you have to strike some balance here. Not sure if my values now are perfect but they definitely do work ok.

One problem I’ve encountered is that I get some nasty oscillations in the envelope if I turn up the gain too high (via the pot R1). Making the envelope faster has made it even worse. I’m not quite sure why that is. It’s my first time to work with a VCVS (voltage controlled voltage source) circuit such as this active filter. I might use two stages of simple op-amp buffers and RC filters in my next design. That means I’ll need an extra op amp but anyway. For now, I just have to be modest with the gain setting and everything is fine.

envelope_detect_500us
Envelope detector in action

This screenshot shows the envelope detector in action: Transmitted signal (red), amplifier output (purple), envelope (yellow) and output of the envelope detector (green). Note that this screenshot was taken before the changed cutoff frequency of the filter. The yellow curve is very smooth but doesn’t track the purple amplifier output very well. That’s why I thought it was a bit slow.

envelope_detect_100us
Close-up of the envelope detector triggering on the rising edge of the envelope

The green signal is the output of the comparator which is also the output of our envelope detector. It will be connected to the Arduino where it will trigger an interrupt and serve as a coarse measurement of the time-of-flight.

Zero-crossing detector

My zero-crossing detector is extremely simple. I set the inverting input of the comparator to half the supply rail by means of R23 and R24. The 100nF cap across R24 (C21) makes sure it stays there and doesn’t swing around itself. I bias the amplifier output to the very same 2.5 volts so I really trigger exactly when the sine wave crosses zero. R22 makes sure the non-inverting input to the comparator can swing freely and the input impedance is reasonably high.

zero_crossing_200us
Zero-crossing detector

Here we see the output of the amplifier / input to the zero-crossing detector (purple) together with the zero-crossing detector output. Everything seems to work fine. As expected, the detector also triggers on very small signals and potentially noise but that should not pose a problem.

zero_crossing_10us
Close-up of the zero-crossing detector input and output

These are the same two signals watched a bit more closely. You might notice that there is quite a bit of time delay from the actual zero-crossing to where the green signal changes. This won’t be a problem as long as the delay is constant but I’m planning to use a faster comparator in my next design. This one has a propagation delay of 8us according to its data sheet. You can get others that are two orders of magnitude faster for nearly the same price such as the MCP6561R with a propagation delay of only 80ns.

Temperature measurement

No surprises here. The output of the LM35 is 10mV per degree centigrade as expected and is amplified by a factor of 4.3 by the op amp. Can’t quite remember why I chose only 4.3, I might change that to 11 by changing R25 to 10k.

Next time I’ll go through the same kind of stuff for the digital circuit. Click here: https://soldernerd.com/2014/11/18/arduino-ultrasonic-anemometer-part-5-testing-the-digital-board/