Generate a stereo-FM multiplex waveform with Python and AWG

Generating more complex arbitrary waveform files for modern test equipment doesn’t have to be difficult. For a recent project, I needed a stereo-FM multiplex (MPX) signal containing two different tones in the left and right stereo audio channels. This article is going to show how to generate such a MPX signal for Siglent SGD-series arbitrary waveform generators with Python and PyVISA.

General Overview

The way stereo-FM works is both simple and sophisticated at the same time. First, sum and a difference signals of the left and right audio channels are created. The sum signal ensures backward compatibility with legacy mono FM receivers. A double sideband signal centered around 38 kHz is generated using the difference signal and a 38 kHz carrier. Lastly, a 19 kHz pilot tone, that is phase coherent to the 38 kHz carrier used in the previous step, is added to the previous 2 signals with a relative amplitude of 10 %. All three signals are then transmitted together using FM modulation. This is a short and simplified explanation. For a better explanation, feel free to watch my YouTube video on the theory of FM stereo multiplexing [1].

My goal was to generate a valid MPX signal containing a 700 Hz tone in the left audio channel and a 2200 Hz tone in the right audio channel. On the hardware side I settled on using my Siglent SDG1032X arbitrary waveform generator (AWG). On the software side, I decided on using Python with PyVISA and NI-VISA. The latter two offer a very convenient way of communicating with the AWG via Ethernet.

Stereo-FM multiplex signal generation with SDG1032X and Python

Stereo-FM multiplex signal generation with SDG1032X and Python

Waveform Math

The first step was to figure out how to generate the necessary datapoints for the MPX signal. In order to achieve this, equations describing all components of the final signal in a mathematical form needed to be formulated. For the sum signal, the DSB modulated difference signal and the 19 kHz pilot tone, the equations are as follows:

Equation for the sum (L+R) signal:
Sum = sin(700 \omega t)+sin(2200 \omega t)

Equation for the difference (L-R) double sideband signal with 38 kHz carrier:
Diff= sin(38000 \omega t) \cdot (sin(700 \omega t)-sin(2200 \omega t))

Equation for the 19 kHz pilot tone:
Pilot = 0.1 \cdot sin(19000 \omega t)

Where ω in this case is a normalization factor to convert the frequencies from cycles per second to radians per sample. Time – expressed as sample number – is represented as t. For the Python / SDG combination, the normalization factor ω is π divided by twice the sample rate. Since the sum, DSB modulated difference and pilot tone signal are simply added together, the overall equation for the desired MPX signal can be written as follows:

sin(700 \omega t)+sin(2200 \omega t) + sin(38000 \omega t) \cdot (sin(700 \omega t)-sin(2200 \omega t)) + 0.1 \cdot sin(19000 \omega t)

Note that this equation will return a maximum value of 2.1 and a minimum value of -2.1. So when scaling this equation to the desired maximum amplitude, the amplitude values needs to be multiplied by the inverse of 2.1, or multiplied by about 0.47.

Python implementation

The entire Python code, along with other Python / PyVISA example scripts, is available from my SIGLENT GitHub repository [2].

The Python code needs to create an array of 16384 points filled with waveform data according to the aforementioned equations. While the following code snippet may not be the prettiest, it works:

# Create an empty array with 16384 points
WAVE = np.arange(0, 0xfffe, 1);

# Sample Rate in S/s
SAMPLE_RATE = 1638400

# Calculate factor for normalized frequency
F_FACTOR = (np.pi/(2*SAMPLE_RATE))

# Fill the waveform array with data
for n in range(len(WAVE)):

  # Amplitude (MAX 32767 on SDG1032X)
  Amplitude = 32767
  WAVE[n] = 0.47*Amplitude*(np.sin(700*F_FACTOR*n)+np.sin(2200*F_FACTOR*n)+0.1*np.sin(19000*F_FACTOR*n)+np.sin(38000*F_FACTOR*n)*(np.sin(700*F_FACTOR*n)-np.sin(2200*F_FACTOR*n)))

The generated waveform data is then sent to the SDG using the write_binary_values of the PyVISA package and the necessary SCPI commands. This of course requires the PyVISA package and the NI-VISA API to be installed and that a connection to the device has been established.

# Write Waveform to Device
# Note: byte order = little-endian!
device.write_binary_values('C1:WVDT WVNM,STEREO_MPX,FREQ,100.0,TYPE,8,AMPL,1.0,OFST,0.0,PHASE,0.0,WAVEDATA,', WAVE, datatype='i', is_big_endian=False)

That’s it! The entire code can be downloaded from GitHub [2].

Results

After executing the Python code and sending the generated waveform to the SDG1032X, the MPX signal is generated as intended. Since only two distinct tones are being generated, the corresponding spectral components and their relative amplitudes can clearly be observed if viewed in the frequency domain:

Frequency domain view of generated MPX signal

Frequency domain view of generated MPX signal

And just for completeness, here’s the same signal in the time domain:

Time domain view of generated MPX signal

Time domain view of generated MPX signal

Conclusions

In essence, it could be said that as long as an equation for a waveform can be formulated, it is rather simple to generate arbitrary waveform files to ones heart’s content. Of course there are some limitations to this. In this case mostly the relatively small 16384 possible points. Nonetheless, the framework of the Python code provided offers great versatility for the quick implementation of arbitrary waveforms. Just adapt the line beginning with “WAVE[n] =” to implement your own waveforms. The GitHb repository contains a few more simplistic examples as well.

Links and Sources:

[1] BalticLab (2016): Stereo Multiplexing for FM Transmission | Theory

[2] AI5GW (2022): Python code examples for SIGLENT equipment

 

SITOR-B / NAVTEX Test Signal Generation

This article shows how to generate valid NAVTEX message bitstream using an Arduino. The Arduino implements proper CCIR476 character encoding, SITOR-B forward error correction, synchronization and phasing signals. An entry-level function generator is then used as a FSK modulator on 518 kHz where it can be received by a NAVTEX receiver.

UPDATE: There also is a German version of this article available on my German blog: SITOR-B / NAVTEX Testsignal mit Arduino und Funktionsgenerator erzeugen

General Overview

Originally, I wanted to show how to repair a “NAV4 Navtex” NAVTEX receiver by ICS Electronics that’s been sitting in my junk box for a while now. But the repair turned out to be rather boring. After realigning the filters of the input stage, the receiver came back to life. During testing, another problem emerged though. NAVTEX stations transmit on a fixed schedule. Therefore, I had to wait for 4 hours between tests in order to wait for the next transmission from the Deutsche Wetterdienst (DWD). Since I had previously generated avionics related test signals (e.g. ILS Localizer / Glide Slope Test Signal Generation at home), I decided to dive into the maritime world of radio communication and try so find an easy way to generate valid NAVTEX signal myself.

NAV4 Navtex by ICS Electronics

NAV4 Navtex by ICS Electronics

NAVTEX (NAVigational TEleX) is a radioteletype service used in the maritime world to distribute navigational and meteorological warnings and forecasts. Even though the system is quite old, the International Convention for the Safety of Life at Sea (SOLAS) still requires certein vessels to be equipped with NAVTEX receivers. The system transmits CCIR476 encoded characters at a rate of 100 baud on 518 Khz or 490 kHz using Frequency-shift keying (FSK). The NAVTEX message format is layered on top of SITOR (SImplex Teletype Over Radio) mode B. Since SITOR-B uses basic forward error correction (FEC), NAVTEX messages are somewhat robust to interference and in weak signal situations.

CCIR476 Character Encoding

CCIR476 is a 7-bit character encoding similar to 5-bit Baudot code. In a valid character, exactly 4 of the 7 bits are ‘1’. Therefore, it is possible to perform a basic error detection on the receiver side. CCIR476 encoding is used for SITOR and AMTOR (Amateur Teleprinting Over Radio) transmissions. AMTOR is basically just the amateur radio equivalent of SITOR. Since there are Arduino libraries for all kinds of amateur radio relatet protocols, I was very confident that there would be a CCIR476 encoding library. But I was wrong. That was bad news, because it meant more legwork for me. But there is good news for everyone who might want to use a CCIR476 encoding / decoding library as well: My CCIR476 library for Arduino [1] is now available through the Arduino library manager or directly from the GitHub repository [2].

CCIR476 encoding / decoding library available from the Arduino library manager

CCIR476 encoding / decoding library available from the Arduino library manager

CCIR476, just like Baudot code, uses two different character tables. One for letters and one for figures. Control characters are transmitted to switch between letters and figures mode. Having two look-up tables for ASCII characters and returning the corresponding CCIR476 character is an easy task. The library keeps track of whether or not the passed ASCII character is in the letters or figures table and provides a feedback function to detect mode changes in order to transmit the necessary control characters.

SITOR-B / NAVTEX Protocol

The International Telecommunication Union (ITU) is a good place to find specifications of communication protocols. On their website I found the ITU recommendation M.476-5 titled “Direct-printing telegraph equipment in the maritime mobile service” [3].

The TL;DR summary of the document comes down to two important points: Transmissions are initiated by sending the Phasing Signal 1 & 2 alternatingly. Every character is transmitted twice with 4 other characters in between. Transmissions are terminated by sending the phasing signal 1 three times in a row as “end of emission signal”.

The document describes the FEC implementation as follows:

The station sending in the collective or in the selective B-mode (CBSS or SBSS) emits each character twice: the first transmission (DX) of a specific character is followed by the transmission of four other characters, after which the retransmission (RX) of the first character takes place, allowing for timediversity reception at 280 ms time space;

Translated to the Arduino program, a transmit buffer was used to implement the FEC according to the specifications. The relevant code looks like this:

void SITOR_Transmit_FEC(byte SYM)
{      
     Transmit_SYMBOL(SYMBOL_BUFFER_1);
     SYMBOL_BUFFER_1 = SYMBOL_BUFFER_2;
     SYMBOL_BUFFER_2 = SYMBOL_BUFFER_3;
     SYMBOL_BUFFER_3 = SYM;  
     Transmit_SYMBOL(SYMBOL_BUFFER_3);  
}

Besides fulfilling the requirements of the SITOR-B protocol, there are also NAVTEX specific protocol demands. NAVTEX requires any message to be initiated by transmitting the characters “ZCZC” and to be terminated by the characters “NNNN”. After the initiating “ZCZC” characters, a 4-character “header” is transmitted. The header contains a transmitter identity character, a subject indicator character and two message serial number characters. My example code uses “SA00”, whereas “S” stands for the DWD transmitter in Pinneberg Germany, the “A” identifies the message as a navigational warning and the “00” is the serial number of the message.

Test Setup and Results

The example sketch was compiled and flashed to an Arduino Uno. When power is applied to the Arduino, it outputs a CCIR476 encoded bitstream using the SITOR-B / NAVTEX protocol at the correct rate of 100 baud on digital pin 2.

NAVTEX bitstream output on digital pin 2 of the Arduino

NAVTEX bitstream output on digital pin 2 of the Arduino

The bitstream from the Arduino Uno was then connected to the “Aux In/Out” connector of a Siglent 1032X function generator. The function generator was set to a frequency of 517.915 kHz. The inbuilt FSK modulation feature was enabled, the modulation source set to “External” and the FSK hop frequency set to 518.085 kHz.

Siglent 1032X used as FSK modulator for SITOR-B / NAVTEX test signal generation

Siglent 1032X used as FSK modulator for SITOR-B / NAVTEX test signal generation

After resetting the Arduino Uno it didn’t take long until the “SBY” LED of the Navtex receiver started blinking. Shortly afterwards, the thermal printer of the receiver came to life and printed the transmitted test message without errors.

The NAVTEX test signal was successfully received on a NAV4 Navtex receiver

The NAVTEX test signal was successfully received on a NAV4 Navtex receiver

Bonus Material

Even though FSK modulation functionality is fairly standard on modern function generators, a SI5351A clock generator breakout board was also tested successfully for the 518 kHz FSK signal generation. The source code for the SI5351A based version is also included in the CCIR476 library example folder. It can also be found here.

There also is a short video of the test setup. And yes, the video was recorded with a potato, so enjoy:

Conclusions

This project proves that sometimes it is quite educating to invest several days of work in order to avoid waiting for 4 hours. If I would have just waited the 4 hours, I wouldn’t have learned much about CCIR476, SITOR-B and NAVTEX. Neither would I have learned about the process of writing and submitting own libraries to the Arduino library index. Sometimes impatience leads down very interesting roads.

Maybe this project will inspire some people to conduct their own SITOR-B or AMTOR experiments. Or at least inspire to experiment with using a simple Arduino as bitstream generator for test signal generation in general.

Links and Sources:

[1] CCIR476 Arduino library, GitHub: https://github.com/AI5GW/CCIR476

[2] CCIR476 Arduino library, arduino.cc: https://www.arduino.cc/

[3] ITU recommendation M.476-5, ITU: https://www.itu.int/

 

VHF LDMOS Power Amplifier Experiments

The NXP MRF101 series high ruggedness N-channel Enhancement-mode lateral MOSFETs promise over 100 Watt CW output power and slightly over 20 dB gain from 1.8 MHz all the way up to 250 MHz. Their mismatch insensitivity for a VSWR of greater than 65:1 without significant device degradation makes these devices extremely interesting for amateur radio operators. While there a plenty of designs for the HF + 6m Bands on the internet, I wanted to see what it takes to use them on the 2m VHF band.

LDMOS VHF Power Amplifier Prototype

LDMOS VHF Power Amplifier Prototype

General Overview

For this experiment a single MRF101AN was used. The MRF101AN is suitable for single band PAs on the 6m (50 MHz), 4m (70 MHz) and possibly 1.25m (222 MHz) band. Operation on the VHF broadcast band (88 – 108 MHz) may also be an interesting application for some people. The 2m band (144 – 148 MHz) was selected for initial prototyping and proof of concept. For no other reason than that it seemed the most interesing to me.

The target was an input VSWR of less than 2:1 over the whole frequency range of 144 to 148 MHz. The quiescent current was set to 100 mA as per the datasheet recommendation. The biasing voltage was supplied to the gate via a resistor. From an AC standpoint, the resistor is connected to ground through a capacitor and is part of the input matching network. This is a common technique used in power MOSFET RF design.

Input / Output Impedance Matching

The first step was to match the input impedance of the MRF101AN to the desired 50 Ohms input impedance. According to the datasheet, the input impedance looking into the gate of the MRF101AN should be around 6.2 – j10.2 [1]. A strong capacitive reactance was to be expected given the relatively high frequencies and an input capacitance of 149 pF. The output impedance is given as 9.9 – j5.9. Therefore, it wouldn’t really be possible to use simple broadband transformers for the input / output matching. Since the desired frequency range of operation isn’t very broadband, this isn’t much of a problem.

I elected to use a simple L-Network for the impedance matching. I recommend reading my article on L-Network impedance matching [2]. It should be noted that for reasons of stability, the input of a power MOSFET should never be matched directly to 50 Ohms. The common design practice is to load the gate with a resistor and then match that to 50 Ohms. The output of a power MOSFET on the other hand can be matched directly to 50 Ohms.

The free software SimSmith was used to simulate different component values and simulate their behaviour over the desired frequency range of operation [3]. After trying different component values, I came up with suitable component values for the input matching:

SimSmith simulation of the MRF101AN input L-Network

SimSmith simulation of the MRF101AN input L-Network

When these values were tested, nothing seemed to work as intended though. This was no surprise since the prototype was built Manhattan-style. Building a circuit like this Manhattan-style is probably not the most wise design choice. But it certainly is possible. It should be noted that the prototype had a tendency to oscillate between 160 – 170 MHz. The oscillations seized once a bare copper board was placed between the gate and drain sides of the MRF101AN. Additionally, the amount of parasitic reactances threw of my matching circuits. It was apparent that the series inducor was too large. So I grabbed the next smaller size adjustable inductor I had in my parts collection. Now they’re likely too low, but this is just a proof-of-concept protoype. As long as the general circuit works, the exact component values can be adjusted once a proper PCB is designed.

This is the schematic of the “final” prototyping circuit that I used for my tests:

Schematic of the LDMOS VHF Power Amplifier Prototype

Schematic of the LDMOS VHF Power Amplifier Prototype

MRF101_AN_VHF_Amplifier_Schematic.pdf

Test Results

All simulation and guesswork asided, what really counts is results. Not much effort was put into the testing of the circuit. Just enough to be assured that a PCB with this general topology can be designed and ordered for fürther component value optimization. No tests for linearity and efficiency where performed. For all tests, the quiescent current was set to 100 mA. The prototype was supplied with 50 Volts DC. The output was properly terminated with a 50 Ohm dummyload. A large heatsink made sure that the MRF101AN stayed within its permissible operating temperature range.

The input VSWR of the power amplifier prototype was measured using a properly calibrated Nano VNA. As expected, the input VSWR isn’t perfect. But it is within the design criteria of less than 2:1 over the whole band:

Measured input VSWR of the MRF101AN LDMOS VHF Power Amplifier Prototype

Measured input VSWR of the MRF101AN LDMOS VHF Power Amplifier Prototype

The actual complex input impedance was also measured using the same set-up:

Measured complex impedance of the MRF101AN LDMOS VHF Power Amplifier Prototype

Measured complex impedance of the MRF101AN LDMOS VHF Power Amplifier Prototype

To test the output power of the power amplifier, a simple FM transceiver delivering about 1 Watt of RF power was connected directly to the input of the MRF101AN power amplifier prototype board. A Siglent SDS1202X-E was used to look at the resulting output waveform from the dummyload through a 1:100 oscilloscope probe.

VHF (144-148 MHz) LDMOS Power Amplifier Prototype Test

VHF (144-148 MHz) LDMOS Power Amplifier Prototype Test

The resulting measurements would – if true – indicate that an output power of a little over 100 Watts was indeed achieved:

Output of the MRF101AN LDMOS VHF Power Amplifier Prototype

Output of the MRF101AN LDMOS VHF Power Amplifier Prototype

However, the results should be interpreted very sceptically. The measured output waveform appears to be very sinusoidal. But in reality, the signal likely looks very distorted. While the L-Network on the output of the amplifier certainly has a low-pass filter characteristic, not much harmonic suppression canbe expected by it. The oscilloscopes maximum bandwidth of 200 MHz makes it impossible to visialize any harmonic components of the signal. Therefore, the displayed waveform and indicated RMS voltage needs to be interpreted very carefully.

Additionally, the input current into the amplifier prototype was only around 2.3 A. That equates to 115 W DC input power. Assuming 100 Watts of RF output power, the resulting efficiency would be around 87 %. While such an efficiency would surely be impressive for such a simple set-up, it is also highly doubtful. Nonetheless, the dummyload gets noticeably warmer after just a few seconds of full power output.

Conclusions

The results are promising enough to design a PCB layout and continue testing this set-up. Expect a follow-up on this topic.

Also, I would like to get some feedback on whether or not a 4m-Band linear amplifier kit would be of interest for the amateur radio community?

Links and Sources:

[1] MRF101AN / MRF101BN Datasheet, NXP: https://www.nxp.com/

[2] L-Network impedance matching https://baltic-lab.com

[3] SimSMith, Ward Harriman, AE6TY http://www.ae6ty.com/

 

ICS501 / ICS501 VHF Experiments

The ICS501 / ICS511 from Renesas are easy to use, fully integrated clock multipliers for output frequencies up to 200 MHz. What makes them particuarly interesting is the integrated crystal oscillator circuit and ability to produce some fractional multiples, such as 6.25 or 2.5. So let’s find out if they’re interesting for the hobbyist who wants to generate clock signals in the VHF range.

General Overview

Both the ICS501 and ICS511 are not designed for radio frequency applications. Therefore, they put out square wave signals and the examples given in the datasheets are targeted at typical clock frequencies used in the world of digital electronics. But that doesn’t mean we can’t use them. The two different chips vary in some ways. The IC501 is able to generate multiples of 2, 3.125, 4, 5, 5.3125, 6, 6.25 and 8 for output frequencies up to 160 MHz [1]. The ICS511 has multiplication factors of 2, 2.5, 3, 3.333, 4, 5, 5.333, 6 and 8 up to 200 MHz [2].

I was interested in how these ICs behave with 50 Ohm loads and sources. The nominal output impedance is given in the datasheets as 20 Ohms. In my experiments, however, no apparent signal degradation was observed when using the ICS501 / ICS511 to drive a 50 Ohm load. Unfortunately, the datasheets do not contain any information about the devices input impedance. But it can be assumed that it is rather high. I had no problems feeding a 4 Vpp AC coupled signal directly into the clock input pins of both chips. The chips also didn’t seem to care whether they were supplied a square wave or a sinusoidal waveform. They were happy with either.

Test Circuit

To make my experiments easier, I designed a small PCB with edge mount SMA connectors for clock input and output. I also included footprints for a HC-49 type crystal and corresponding load capacitors. The two solder jumpers can be used to set a fixed clock multiplication factor. The larger through-hole pads that can be seen in the pictures are reserved for future experiments where I will try to use a varicap diode to frequency modulate the output signal. Spoiler alert: Narrow-Band FM using a varicap is possible!

Homebrew breakout board for ICS501 / ICS511 clock multiplier experiments

Homebrew breakout board for ICS501 / ICS511 clock multiplier experiments.

The PCB design contains a lot of design errors. But I already designed a Revision 0.2 PCB and send the files of for production. In its present condition, the circuit looks something like this (click to enlarge):

Schematic of the quick and dirty ICS501 breakout board

Schematic of the quick and dirty ICS501 breakout board

Test Results

All tests were performed using the ICS501 because I didn’t have any ICS511 in stock. The output signal was fed into a Siglent SDS1202X-E oscilloscope through a 50 Ohm termination resistor.

ICS501 output signal, 7 MHz input clock, multiplication factor 6, 42 MHz output signal

ICS501 output signal, 7 MHz input clock, multiplication factor 6, 42 MHz output signal

The integrated crystal oscillator works well to generate a 144 MHz signal from a 24 MHz crystal. I did not add any load capacitors on the PCB because the internal 12 pF (Source: [ 1], page 3) were sufficient to sustain a reliable oscillation. Frequency accuracy was not important for this test anyway. Note that the now more sinusoidal looking waveform is merely a limitation of my test equipment. The oscilloscope simply doesn’t have enough bandwidth to process the Fourier components (odd-integer harmonic multiples) that give a square wave its shape.

ICS501 output signal, 24 MHz crystal, multiplication factor 6, 144 MHz output signal

ICS501 output signal, 24 MHz crystal, multiplication factor 6, 144 MHz output signal

Next, I wanted to try what happens if the ICS501 is driven beyond its alleged maximum output frequency of 160 MHz. I was honestly not very surprised to see that the 30 MHz input signal was multiplied to 180 MHz effortlessly.

ICS501 output signal, 30 MHz input clock, multiplication factor 6, 180 MHz output signal

ICS501 output signal, 30 MHz input clock, multiplication factor 6, 180 MHz output signal

The next thing I was interested in was the output spectrum. A 15.1 MHz input signal was multiplied by 6 to generate a 90.6 MHz signal in the FM broadcast band.

ICS501 output spectrum, 15.1 MHz input clock, 90.6 MHz output. Horizontal scale: 2 MHz / division, vertical scale: 20 dB / division

ICS501 output spectrum, 15.1 MHz input clock, 90.6 MHz output. Horizontal scale: 2 MHz / division, vertical scale: 20 dB / division

In the center of the picture we can see the wanted 90.6 MHz signal. But various other peaks spaced a little over 3 MHz from the carrier are also visible. These peaks are calles reference spurs. Their spacing corresponds to the internal frequency used by the phase frequency detector (PFD) inside the ICS501. The exact spacing of these spurs is likely to be 3.02 MHz (input clock divided by 5). The 3.02 MHz is then used by the PFD to lock onto the output signal divided by 30 (90.6 MHz / 30 = 3.02 MHz) to this internal reference frequency. Reference spurs are faily typical for PLL circuits. But nothing to worry about, we can filter those.

If we look at a broader range of the spectrum, more spurs become visible:

ICS501 output spectrum, 15.1 MHz input clock, 90.6 MHz output. Horizontal scale: 10 MHz / division, vertical scale: 20 dB / division

ICS501 output spectrum, 15.1 MHz input clock, 90.6 MHz output. Horizontal scale: 10 MHz / division, vertical scale: 20 dB / division

Besides the aforementioned PFD reference spurs repeating every 3.02 MHz, we can now clearly see even stronger spurs spaced 15.1 MHz on either side of the desired 90.6 MHz center. This is simply leakage of our original 15.1 MHz reference signal.

Conclusions

Altogether I am quite happy with the results so far. These ICs might be a simple solution for generating frequencies in the VHF range from fairly low frequency oscillators, VFOs and standard crystals. Cascading two ICS501 / 511 opens even more possibilities. Especially with standard crystals, the fractional multiplier settings open a foolproof and inexpensive way of generating frequencies that otherwise would require more complicated PLL circuits.

Another interesting application would be to generate extremely accurate clock signals from a standard 10 MHz precision reference source (OCXO, GPSDO, etc.). Stay tuned for more experiments.

NOTE: The ICS501 is considered obsolete / not recommended for new design and chip availability can not be guaranteed. But there appears to be plenty of stock available from large distributors. Certainly enough for the average hobbyist.

Links and Sources:

[1] ICS501 Datasheet, Renesas Wikipedia: https://www.renesas.com/

[2] ICS511 Datasheet, Renesas Wikipedia: https://www.renesas.com/

 

Arduino |Automatically Save Variables to EEPROM on Power-Down

A recurring challenge for Arduino projects is that variables are volatile and will be lost completely unless previously stored to some sort of non-volatile storage such as de inbuilt EEPROM. This article shows a minimalistic approach to detect sudden loss of power and automatically store a variable to an EEPROM adress.

First I should mention that this approach of course also works for other type of storage devices, such an external SD-Card. The simple solution I used in this 12V application is a 2-stage voltage regulator set-up and a power-sense input tied to an interrupt. The first stage gets the input voltage down to 9V. A voltage devider on the 9V rail supplies a steady high signal to PIN 3 of the Arduino Nano as long as a power source is connected to the circuit. As soon as this sense-input falls low, an Interrupt Service Routine (ISR) is triggered that stores the variable to a pre-defined adress of the EEPROM. The second stage consists out of two 7805 type voltage regulators. One for the Arduino Nano and one for all periphial devices such as the LC-Display. The Arduino`s 5 Volt supply voltage is tied to a 1F supercapacitor. This guarantees that the Arduino has enough power available to safely detect the missing supply voltage on the 9V rail and store the example variable to the EEPROM.

The whole Setup looks something like this:

Crude test setup with 1F supercapacitor

Crude test setup with 1F supercapacitor

#include <EEPROM.h>

// Some Variable 
int SomeVariable;
// Pin to be used as power-down sense
int PWR_DWN_PIN = 3;
// The EEPROM address to be used
int EE_ADDR = 10;

void setup() {
  // Retrieve last stored value of SomeVariable from EEPROM
  EEPROM.get(EE_ADDR, SomeVariable);
  // Set-up Interrupt Service Routine
  attachInterrupt(digitalPinToInterrupt(PWR_DWN_PIN), PWR_DWN_ISR,FALLING);
}

void loop() {
  // Do something cool
  }

// This Interrupt Service Routine will get called on power-down
void PWR_DWN_ISR () {
    // Push SomeVariable to the EEPROM
    EEPROM.put(EE_ADDR, SomeVariable);
    
}

This Setup works very well. How long the supercapacitor can power the Arduino and whether or not you even need a separate supply rail for periphials depends on the current demand of your circuit. So here`s some math.

The charge of a capacitor is defined as follows:

Q = It

Q = charge of capacitor in Coulomb
I = Current in Amps
t = time in Seconds

So if we re-arrange the equation we could wrongly assume that if we divide Q by the current demand of our device, we will get the expected runtime in seconds. But we need to take into consideration that the Arduino does not work all the way down to 0 Volts. We need to define a lower voltage limit and divide the change of charge by the current draw of your device. But how do we get Q to begin with? The charge of a capacitor Q can also be expressed by the following Formula:

Q = CV

C = Capacitance in Farads
V = Voltage in Volts

So we can combine the two formulas in a way that we can calculate the time (t) if we know the capacitance of the supercapacitor, the expected current draw of the device and the maximum permissible change in voltage.

t = \frac{\Delta VC}{I}

So for my example I am allowing the 5 Volts to drop to 4 Volts, I am assuming 100 mA max. current and the supercap has a capacity of exactly 1F.

t = \frac{(5V - 4V) 1}{0.1A} = 10 s

10 seconds should be plenty of time to store a variable (or a few more) to the EEPROM. This approach works very well so far. A possible improvement, if needed, migth be to implement a change interrupt trigger instead of a falling edge trigger and re-initialize periphials on power-up if needed (e.g. LCD). This becomes necessary if power is reconnected during a time where the Arduino is still running but periphials where already shut-down. In that case they need a clean initialization before they will function properly.

 

Diamex Prog-S2 | Arduino IDE

The Diamex Prog-S2 is an universal USB ISP programmer vor various microcontrollers including Atmel AVRs. This article shows how to integrate the programmer into the Arduino IDE

There are a few articles on the web that talk about the Diamex Prog-S2 and Arduino. But it seemed to me like they were either outdated or faulty.

To get the Arduino IDE to talk to the Arduino IDE, simply add the following lines to the programmers.txt file in the Arduino IDE program folder:

diamexavr.name=DIAMEX-AVR
diamexavr.communication=serial
diamexavr.protocol=stk500v2
diamexavr.program.tool=avrdude
diamexavr.program.extra_params=-P{serial.port} -F

After restarting the Arduino IDE, the Prog-S2 should appear in the programmers list as “DIAMEX-AVR”.

The Diamex Prog-S2 appears in the programmer list after updating the programmers file.

The Diamex Prog-S2 appears in the programmer list after updating the programmers file.

Please don’t forget that you still need to select the proper COM-Port in order to use the Prog-S2 properly. Most importantly, you will have to use the “Upload using programmer” option to upload a Sketch to an Atmel AVR / Arduino chip using the Diamex Prog-S2.

 

Automated Forward Gain Measurement

This article is going to take you into the world of automation. Using MATLAB and commercial off-the-shelf bits and pieces, this article will show how to measure the forward gain of a RF device.

For a long time now I had a bunch of Mini Circuits portable test equipment bits and pieces sitting around. S signal generator, a switch matrix and power sensors. These devices aren’t made for manual operation as they feature no direct way of manipulating the instrument’s state without software. They’re made for automation. And as such i thought an automation example would be in order. Like in the last article, we’re going to have a look at a practical example again. So here are the parameters:

For my passive secondary surveillance receiver at 1090 MHz I am using a Mini Circuits VBFZ-1065 filter [1] and a ZKL-2 amplifier [2]. The filter’s datasheet lists a passband of 980 – 1150 MHz and a 20 dB bandwidth of 630 – 1800 MHz. But let’s see if we can verify the data using an automated test setup.

Measuring the forward gain is quite simple. Simply apply a signal of known amplitude and known frequency to the device under test, measure the output power and compare. Let’s say we apply a 1090 MHz signal with an amplitude of -30 dBm to an amplifier and measure 0 dBm out, we know the forward gain at this exact frequency is 30 dB. So a minimalistic automated setup could consist of just the signal generator as source and the power meter as sink. But we want more than that. Clearly both the generator and the power sensor have certain nonlinearities when it comes to sourcing and measuring a specific amplitude accurately. But these nonlinearities are deterministic and close to constant. Therefore, we can measure the nonlinearities and apply correction factors to our final measurement.

Test setup on the bench

Test setup on the bench

To facilitate this calibration mode, I included the switch matrix. The matrix can switch the source and power sensor directly into each other via a straight through cable jumper or it can switch both to the device under test ports. The following closeup may help understand what I am talking about:

Closeup of the test setup

Closeup of the test setup

All we need now is MATLAB code. The code’s job in plain english is as follows: Switch the matrix to straight through connection, sweep the system, normalize to intended power level, store normalized values as calibration factors, display cal factors, switch to device under test, sweep system, normalize to calibration values, display sweep results relative to desired output power.

Now in MATLAB speak:


% Connect to PWR Sensor
pm1 = NET.addAssembly('C:\Users\Sebastian\Desktop\MC\mcl_pm64.dll')
obja=mcl_pm64.usb_pm
obja.Open_AnySensor

% Connect to Switch
switch1 = NET.addAssembly('C:\Users\Sebastian\Desktop\MC\mcl_RF_Switch_Controller64.dll')
objc = mcl_RF_Switch_Controller64.USB_RF_SwitchBox
objc.Connect

% Connect to Sig Gen
gen1 = NET.addAssembly('C:\Users\Sebastian\Desktop\MC\mcl_gen64.dll')
objb = mcl_gen64.usb_gen
objb.Connect

% Switch to Cal Bridge
% 0 = Straight Through, 3 = Through DUT
% objc.Set_SwitchesPort(0)

%% Sweep System

% Drive Level in dBm
Power = -30
% Start Frequency in MHz
Fstart = 700
%Step Size in MHz
StepSize = 2.5
%Step Count
Steps = 400

%% Acquire Calibration Values
% Switch to Through Connection
objc.Set_SwitchesPort(0)
% Enable RF
objb.SetPowerON
% Sweep
for C = 1:Steps

% Calculate Frequency
F = Fstart + (StepSize*(C-1));
% Set Frequency and Power
objb.SetFreqAndPower(F,Power,0)
% Allow some settling time
pause(0.25);
% Read Power
PWR=obja.ReadPower
PWR=round(10*PWR)/10
% Write result into Array
A(:,C) = PWR
end
objb.SetPowerOFF

% Normalize
for Count=1:length(A)
A(:,Count)=A(:,Count)-Power;
end
CalValues = A

power = A

% Make Frequency Scale
freq = linspace(Fstart,F,length(A))
% Plot
figure;
plot(freq,power)

%% Acquire Real Values
% Switch to Through Connection
objc.Set_SwitchesPort(3)
% Enable RF
objb.SetPowerON
% Sweep
for C = 1:Steps

% Calculate Frequency
F = Fstart + (StepSize*(C-1));
% Set Frequency and Power
objb.SetFreqAndPower(F,Power,0)
% Allow some settling time
pause(0.25);
% Read Power
PWR=obja.ReadPower
PWR=round(10*PWR)/10
% Write result into Array
Real(:,C) = PWR
end
objb.SetPowerOFF

% Normalize
for Count=1:length(Real)
Real(:,Count)=Real(:,Count)-CalValues(:,Count)-Power;
end

power = Real

% Make Frequency Scale
freq = linspace(Fstart,F,length(Real))
% Plot
figure(2);
plot(freq,power)

%% END

% Disconenct all Devices
obja.Disconnect
objb.Disconnect
objc.Disconnect

You can download the MATLAB file here: MC_Forward_Gain.m

The code was assembled using the various programming examples Mini Circuits offers for download on their website [3]. The overall process to interact with this type of portable test gear is to call a Dynamic Link Library (DLL) and call predefined functions from inside the DLL. The DLLs can be downloaded from the previous link location also.

The result for my setup with the VBFZ-1065+ and the ZKL-2 looks something like this:

Forward Gain Measurement

Forward Gain Measurement

And the forward gain only looks as follows:

Forward gain of the filter and amplifier combo

Forward gain of the filter and amplifier combo

Links and Sources:

[1] VBFZ-1065+, Mini Circuits: https://www.minicircuits.com/pdfs/VBFZ-1065+.pdf

[2] ZKL-2, Mini Circuits: http://www.minicircuits.com/pdfs/ZKL-2.pdf

[3] ZKL-2, Mini Circuits: http://www.minicircuits.com/support/software_download.html

 

Thermal Design Basics | Practical Example

Thermal design is one of those things engineers don’t really learn in school and hobbyists often don’t even think about. This article is going to show some basic math with a practical example.

One of my portable police scanners has an external 6V jack. To use it in my car I used my standard linear voltage regulator board and a high quality ST L7806 voltage regulator to get the ~13.8V of the car down to 6V. Maximum observed current of the scanner was 0.25A. So the thermal design question of the day is: How hot will the linear regulator get and do I need a heatsink?

Universal Linear Regulator Board

Universal Linear Regulator Board

So lets start with the obvious first question: How hot is too hot? The answer is of course to be found in the datasheet. The datasheet states an absolute maximum of 150 °C. Note that this is the maximum rating though. While you can safely run the device at 150 °C, you probably don’t want to. Remember that 100 °C is the boiling point of water. So 150 °C is pretty darn hot. But it’s within the parameters given to us.

ST L7800 Datasheet

ST L7800 Datasheet

So how do we calculate how hot the device gets? The key to that question is the dissipated power and a figure called the thermal resistance junction-ambient, symbolized as theta-ja (θja). It is also shown in the previous datasheet snapshot. This figure basically says how many degrees the device’s junction temperature rises ABOVE ambient temperature for a given amount of dissipated power. Ambient temperature, or “room temperature” is often assumed to be at 25 °C. And that’s what we’re gonna work with but when you do the math, please be practical. If you can reasonably expect the temperature to rise above 25 °C, then do the math accordingly.

So our formula for junction temperature is this:

Tjunction = Tambient + (θja * power)

Alright, let’s piece together what we have. Let’s start with the dissipated power. We put in 13.8 V at 0.25 A and get out 6V. That makes 1.95 Watts ([13.8V – 6V] * 0.25A) of power to turn into heat. To calculate the expected junction temperature we simply plug all the values into the formula and solve.

25 + (50 * 1.95) = 122.5 °C

That means we can expect the junction temperature of the device to reach 122.5 °C. This is within the given maximum ratings and thus the answer to the heatsink question is no, we do not need a heatsink.

But not the reality check, think along with me. Again remember that 100 °C is the boiling point of water. Do we really want a device 22.5 °C above that sitting around somewhere? And also we assumed ambient to be at 25 °C. Car ambient temperatures frequently rise well above that, especially when exposed to sunlight. On top of that, car voltages aren’t even close to stable and can exceed 14 volts easily. So the practical answer would be that we would elect to use a heatsink. And that’s exactly what I did.

How to size heatsinks is a more complicated story and will be part of a different article.

Links and Sources:

[1] L7800 Series Datasheet, ST: https://baltic-lab.com/wp-content/uploads/2016/01/L7800.pdf