Acoustics

Enter Your Electronics & Design Project for a chance to win an $200 Shopping cart of product!

Back to The Project14 homepage

Project14 Home
Monthly Themes
Monthly Theme Poll

 

My holiday may be looming, but actually, after seeing the relatively positive response to my last quick project which looked at abusing a Rohde & Schwarz RTM3004’s arbitrary waveform generation features to produce audio, I thought it might be a good idea to up the ante somewhat and go even more bonkers and try to make music with a power supply. It'sa me, part two!

 

Sound but with a Catch (or Two)!

This time, the challenge gets tougher. Arbitrary waveform generators are designed primarily to produce fast waveforms, often much faster than necessary for audible sound. Lab benchtop DC power supplies, on the other hand, generally are not designed to produce much of a waveform at all, let alone be fast. Instead, they’re designed to generate a steady output, changing at a much slower rate when reprogrammed to a different output. Even though they may advertise sequencing or “arbitrary” waveform capabilities, these are much more limited by comparison. Another consideration is that the supplies are often not capable of producing negative voltages, unless they are a four-quadrant variety.

 

This is where I have lucked out – I have one of Rohde & Schwarz’s specialty power supplies, the NGM202, which is fast. Whereas their performance series HMP4040.04 can run 100-points per second, the NGM202 can do a blistering 1000-points per second. With fast transient response features and a fast recovery time, challenging down-programming transitions (i.e. high to low voltage) should be handled well as the power supply is a two-quadrant unit. Let’s put that to the test.

 

Why is this important? Well recall that sound waves can be made from alternating electrical waves. The problem with a slow arbitrary waveform generator that can run 100Hz is that the maximum frequency of sound you can get (assuming a sample with full output followed by a sample with zero output for a square wave) is 50Hz. That’s a power-line hum. With a waveform generator that can do 1000Hz, this increases to 500Hz or about B4 on the musical scale. That’s not the greatest, but at least that’s something we can work with.

 

Another issue is timing granularity. With arbitrary waveform on power supplies, it is normally specified as a quad consisting of voltage, current, dwell time and interpolation. The dwell time units in the case of the NGM202 seem to be 1ms. Because of this, the actual tones that the unit can generate are quite limited at the high end – the scale goes something like this:

Dwell (ms)   Frequency (Hz)
1            500
2            250
3            166.6666667
4            125
5            100
6            83.33333333
7            71.42857143
8            62.5
9            55.55555556
10           50
11           45.45454545
12           41.66666667
13           38.46153846
14           35.71428571
15           33.33333333
16           31.25
17           29.41176471
18           27.77777778
19           26.31578947
20           25
21           23.80952381
22           22.72727273
23           21.73913043
24           20.83333333
25           20
26           19.23076923
27           18.51851852
28           17.85714286
29           17.24137931
30           16.66666667
31           16.12903226
32           15.625
33           15.15151515
34           14.70588235
35           14.28571429
36           13.88888889
37           13.51351351
38           13.15789474
39           12.82051282
40           12.5

That’s not quite the musical scale, but I’ll give it a shot anyway. The other option would be to try and synthesize something akin to a pulse wave (e.g. 1ms on, x ms off) to get some in-between frequency values. Another simpler option would be to use the lower end of the musical scale, as the alignments are a bit finer with lower frequencies – this is the option I decided to choose.

 

Another issue is that the power supply is not actually outputting a true AC signal, instead, it will be alternating between zero and a positive DC voltage. This results in an average voltage across the speaker which is non-zero, potentially resulting in extra heating of the speaker coil and asymmetric cone excursion. If the amplitude is limited, this isn’t a big issue, but the easy fix for this is to shove a capacitor in series to block the DC (although with frequency-response altering effects). For simplicity, I decided to forego this entirely.

 

There is one upside to using a power supply though – you can produce really loud sounds. In fact, you could even blow up a speaker if you give it enough juice … so best be conservative with the settings.

 

Making the Idea Happen

The first thing I needed was some music to play. Video-game music usually fits well with square-waves, so I decided that after my joke with the oscilloscope project, that I should just do the Mario theme. Being lazy and not wanting to code it all myself, I stole some Arduino code from https://gist.github.com/gskielian/6135641.

 

But since I like to use pyvisa for automation, I would have to translate the code into Python. Or so I thought. What I discovered is that if I just reimplement the tone() and delay() functions to make it compatible with the NGM202, then the rest of the code can remain unchanged. Python is even friendly enough to ignore the semi-colons at the end of the Arduino lines … for illustration, the code is below without any cleaning up:

# Mario Theme on a R&S NGM202 Power Supply
# by Gough Lui (goughlui.com) - March 2020
# 
# Adapted from 
# https://gist.github.com/gskielian/6135641
#
# No warranties. Code depends on pyvisa. Change SCPI resource identifier to match your device.
# No liability accepted for damages however incurred.

import visa
import time

def tone (c,f,t) :
  dura = "{:4e}".format(8/f) # Scale down frequency by 4, half period, scientific format string
  ins_ngm202.write("ARB:DATA "+str(outvolt)+","+str(outcur)+","+dura+",0,0.0,"+str(outcur)+","+dura+",0")
  ins_ngm202.write("ARB:TRAN "+str(outch))
  ins_ngm202.write("ARB 1")
  ins_ngm202.write("OUTP 1")
  ins_ngm202.query("*OPC?")
  time.sleep(t/1000*2) # Play notes twice as long ...
  ins_ngm202.write("OUTP 0")

def delay (t) :
  time.sleep(t/1000) # Keep silent delays the same though ...

resource_manager = visa.ResourceManager()
ins_ngm202 = resource_manager.open_resource("TCPIP0::192.168.80.18::INST0::INSTR")
ins_ngm202.timeout = 10000

outvolt = 0.75
outcur = 0.5
outch = 1

print("Available:" + "\n" + ins_ngm202.query("*IDN?"))
input("Play Mario Theme?")

# Set Up NGM202
print("Setting Up - NGM202")
ins_ngm202.write("INST:NSEL "+str(outch))
ins_ngm202.write("SENS:VOLT:RANG:AUTO 0")
ins_ngm202.write("SENS:VOLT:RANG 5")
ins_ngm202.write("SENS:CURR:RANG:AUTO 0")
ins_ngm202.write("SENS:CURR:RANG 1")
ins_ngm202.write("OUTP 0")
ins_ngm202.write("OUTP:GEN 0")
ins_ngm202.write("OUTP:MODE SOUR")
ins_ngm202.write("SOUR:VOLT 0.0")
ins_ngm202.write("SOUR:CURR "+str(outcur))
ins_ngm202.query("*OPC?")

# Begin Playback - Code is Arduino Code Directly Taken!
# Lucky Python ignores all semi-colons and I have written tone() and delay()
# functions to take care of the code without needing modification.
print("Begin Melody")
tone(9,660,100);
delay(150);
tone(9,660,100);
delay(300);
tone(9,660,100);
delay(300);
tone(9,510,100);
delay(100);
tone(9,660,100);
delay(300);
tone(9,770,100);
delay(550);
tone(9,380,100);
delay(575);

tone(9,510,100);
delay(450);
tone(9,380,100);
delay(400);
tone(9,320,100);
delay(500);
tone(9,440,100);
delay(300);
tone(9,480,80);
delay(330);
tone(9,450,100);
delay(150);
tone(9,430,100);
delay(300);
tone(9,380,100);
delay(200);
tone(9,660,80);
delay(200);
tone(9,760,50);
delay(150);
tone(9,860,100);
delay(300);
tone(9,700,80);
delay(150);
tone(9,760,50);
delay(350);
tone(9,660,80);
delay(300);
tone(9,520,80);
delay(150);
tone(9,580,80);
delay(150);
tone(9,480,80);
delay(500);

tone(9,510,100);
delay(450);
tone(9,380,100);
delay(400);
tone(9,320,100);
delay(500);
tone(9,440,100);
delay(300);
tone(9,480,80);
delay(330);
tone(9,450,100);
delay(150);
tone(9,430,100);
delay(300);
tone(9,380,100);
delay(200);
tone(9,660,80);
delay(200);
tone(9,760,50);
delay(150);
tone(9,860,100);
delay(300);
tone(9,700,80);
delay(150);
tone(9,760,50);
delay(350);
tone(9,660,80);
delay(300);
tone(9,520,80);
delay(150);
tone(9,580,80);
delay(150);
tone(9,480,80);
delay(500);

tone(9,500,100);
delay(300);

tone(9,760,100);
delay(100);
tone(9,720,100);
delay(150);
tone(9,680,100);
delay(150);
tone(9,620,150);
delay(300);

tone(9,650,150);
delay(300);
tone(9,380,100);
delay(150);
tone(9,430,100);
delay(150);

tone(9,500,100);
delay(300);
tone(9,430,100);
delay(150);
tone(9,500,100);
delay(100);
tone(9,570,100);
delay(220);

tone(9,500,100);
delay(300);

tone(9,760,100);
delay(100);
tone(9,720,100);
delay(150);
tone(9,680,100);
delay(150);
tone(9,620,150);
delay(300);

tone(9,650,200);
delay(300);

tone(9,1020,80);
delay(300);
tone(9,1020,80);
delay(150);
tone(9,1020,80);
delay(300);

tone(9,380,100);
delay(300);
tone(9,500,100);
delay(300);

tone(9,760,100);
delay(100);
tone(9,720,100);
delay(150);
tone(9,680,100);
delay(150);
tone(9,620,150);
delay(300);

tone(9,650,150);
delay(300);
tone(9,380,100);
delay(150);
tone(9,430,100);
delay(150);

tone(9,500,100);
delay(300);
tone(9,430,100);
delay(150);
tone(9,500,100);
delay(100);
tone(9,570,100);
delay(420);

tone(9,585,100);
delay(450);

tone(9,550,100);
delay(420);

tone(9,500,100);
delay(360);

tone(9,380,100);
delay(300);
tone(9,500,100);
delay(300);
tone(9,500,100);
delay(150);
tone(9,500,100);
delay(300);

tone(9,500,100);
delay(300);

tone(9,760,100);
delay(100);
tone(9,720,100);
delay(150);
tone(9,680,100);
delay(150);
tone(9,620,150);
delay(300);

tone(9,650,150);
delay(300);
tone(9,380,100);
delay(150);
tone(9,430,100);
delay(150);

tone(9,500,100);
delay(300);
tone(9,430,100);
delay(150);
tone(9,500,100);
delay(100);
tone(9,570,100);
delay(220);

tone(9,500,100);
delay(300);

tone(9,760,100);
delay(100);
tone(9,720,100);
delay(150);
tone(9,680,100);
delay(150);
tone(9,620,150);
delay(300);

tone(9,650,200);
delay(300);

tone(9,1020,80);
delay(300);
tone(9,1020,80);
delay(150);
tone(9,1020,80);
delay(300);

tone(9,380,100);
delay(300);
tone(9,500,100);
delay(300);

tone(9,760,100);
delay(100);
tone(9,720,100);
delay(150);
tone(9,680,100);
delay(150);
tone(9,620,150);
delay(300);

tone(9,650,150);
delay(300);
tone(9,380,100);
delay(150);
tone(9,430,100);
delay(150);

tone(9,500,100);
delay(300);
tone(9,430,100);
delay(150);
tone(9,500,100);
delay(100);
tone(9,570,100);
delay(420);

tone(9,585,100);
delay(450);

tone(9,550,100);
delay(420);

tone(9,500,100);
delay(360);

tone(9,380,100);
delay(300);
tone(9,500,100);
delay(300);
tone(9,500,100);
delay(150);
tone(9,500,100);
delay(300);

tone(9,500,60);
delay(150);
tone(9,500,80);
delay(300);
tone(9,500,60);
delay(350);
tone(9,500,80);
delay(150);
tone(9,580,80);
delay(350);
tone(9,660,80);
delay(150);
tone(9,500,80);
delay(300);
tone(9,430,80);
delay(150);
tone(9,380,80);
delay(600);

tone(9,500,60);
delay(150);
tone(9,500,80);
delay(300);
tone(9,500,60);
delay(350);
tone(9,500,80);
delay(150);
tone(9,580,80);
delay(150);
tone(9,660,80);
delay(550);

tone(9,870,80);
delay(325);
tone(9,760,80);
delay(600);

tone(9,500,60);
delay(150);
tone(9,500,80);
delay(300);
tone(9,500,60);
delay(350);
tone(9,500,80);
delay(150);
tone(9,580,80);
delay(350);
tone(9,660,80);
delay(150);
tone(9,500,80);
delay(300);
tone(9,430,80);
delay(150);
tone(9,380,80);
delay(600);

tone(9,660,100);
delay(150);
tone(9,660,100);
delay(300);
tone(9,660,100);
delay(300);
tone(9,510,100);
delay(100);
tone(9,660,100);
delay(300);
tone(9,770,100);
delay(550);
tone(9,380,100);
delay(575);

print("Song End. Closing instrument!")
ins_ngm202.write("OUTP 0")
ins_ngm202.write("OUTP:GEN 0")
ins_ngm202.write("ARB 0")
ins_ngm202.close()


Disclaimer: I do not recommend running this code on your own unit – if you do so, you do it at your own risk. This code is particularly harsh on the NGM202’s output relay, toggling at each note due to how the NGM202 handles Arbitrary Waveform on/off events. It also causes the output to be cycled very quickly, which results in a high stress on the power supply’s regulation circuitry. But it does work, for the most part, as you will see in the next part.

 

The code allows you to define the instrument’s VISA resource name, the output amplitude, current limit and channel. This probably won’t work on any supply which doesn’t have at least the NGL/NGM’s capabilities and syntax. Some of the hacks include a transposition done within the tone function and tempo slowdown as the power supply gets really unhappy if you command it to change its output too quickly.

 

The speaker is one from a computer peripherals-brand which I picked up at a liquidation sale and shoved in my junk-box for many years. It is connected directly to the Channel 1 outputs using a pair of banana to crocodile clip cables.

 

Video

The result is above – because of time constraints, I didn’t bother to create much of an explanatory introduction, as … well, we have this article and I’m rapidly running out of time. But that’s not to say I don’t have more ideas that I want to try. The result isn’t exactly as neat as I thought it would be – some of the lost notes appear to be a firmware issue with the NGM202 when the arbitrary function is called upon a lot in a short space of time. In fact, I found that if the code used “ARB 0” to stop the arbitrary function rather than “OUTP 0”, it would play only a third or half the song before getting stuck and staying silent. But that’s perhaps not unexpected, since I am pushing the capabilities right to the edge. I bet Rohde & Schwarz didn’t intend their power supply to be used like this …

 

Conclusion

The conclusion is obvious – power supplies can create music too. But not all power supplies. You need one that’s fast in output programming capabilities with a fast arbitrary waveform generation function as well. But if it’s fast enough … it can kind of make music and quite loudly too. It’s not an intended use for power supplies, hence discovering a few issues, and is harsh on the regulation circuit and output relay. I don’t recommend running this code on your own unit. But I hope you might have enjoyed this follow-up to my abuse of test equipment for weird acoustical profit.