Project Blog 2
The notes on the upper photo tell most of the story. I want to have about 30kV on 50pF to simulate the static on a person who is inadvertently charged, who picks up the DIY JFET oscilloscope probe and threatens the $2000 digital oscilloscope with his static. The probe is supposed to do a great job of protecting the oscilloscope, but I need to test a probe with maybe 100 sparks to see if all the transistors survive.
The first try at increasing the 10kV to 20kV of the multiplier is to charge a variable cap and increase the plate spacing, pushing in mechanical energy (forcing apart the plates, which are attracted by the charge), which increases the voltage by the formula V = Q/C. (The picofarads goes down as the plate spacing goes up.)
I see no corona anywhere in this setup. The edges on the baking pans have pretty generous radii so the electric field doesn't concentrate too much.
But when I raise the upper plate to where it contacts the black, steel ground electrode, the spark just doesn't jump as much as I expected. So I think I will try making a second air-dielectric cap and make a two-stage Marx generator.
June 12, 2018 With a two-stage Marx generator using air-dielectric, 115pF capacitors, I find that the spark gaps must be "tuned" carefully to make the Marx generator work. The gaps I have made use blunt electrodes that have higher breakdown voltages, subject less to the lowering of breakdown voltage that happens when a sharp electrode is used, so the voltage seems to be 80V * 170 mils = 13600V. This is no where near what I want but I may find ways to creep it up. (I still don't have a good way to measure open-circuit voltage, my best effort so far being a divider that has only 323Mohm input resistance.)
I have made a window-glass, high-voltage capacitor, 6 layers of 3/32", 10x12" glass, with "common" or ground plates (foil) on the outside for safety. There are 7 plates in all, 4 common and 3 hot. This is a heavy capacitor. Measures 0.0103uF, pretty high. I put six 4kV rectifiers on it so that it can serve as a filter cap between the multiplier circuit and the Marx generator. This glass cap can store 0.5J at 10kV, quite small, but it will be interesting to see what kind of snap it makes when shorted.
June 28, 2018 I am progressing on 3 PCBs. 1) measure a .03uF capacitor to about 0.2%. Use this cap in 2) a capacitor-divider voltmeter with an input cap of 10pF, division ratio of 3000:1. This will let me measure D.C. high voltage without loading it, the bane of my high-voltage work so far. 3) An NPN 50mA curve tracer so I can look for any parameter degradation, or outright failure, in a 2N3904 that is subjected to shocks from body static, as a demo to IEEE San Antonio life members group of what static does to semiconductors.
I made a second foil-pan capacitor to do a 2-stage Marx generator but it isn't working very well. I will use the new high-impedance voltmeter to see what is going on.
A different multiplier might be better than the 60Hz microwave oven transformer I have been using. I have 800V fast-recovery rectifiers that are a good match to the film 700VAC capacitors from Mouser. Or use seriesed 400VAC blue 2200pF caps. If I make a step-up transformer with a UU core from flyback transformer, using a TL494 PWM IC, there might be a lot more power coming at 20kV or even 30kV, even if there are 43 stages. Use more pF at the low end.
July 7, 2018 I built up the transistor curve tracer first. With enough Arduino sketch to operate eight steps of base current and the digital inputs to control 1000uF cap charging and the "for sure" saturation of the DUT during cap charging, I am seeing a family of Vce/Ic curves. That is pretty neat. I don't know how to get the persistence I need on the Tek DPO 2002B, I just see one curve (one base current) at a time.
There was a megahertz oscillation in OA3, the one that keeps the DUT base at ground. That stopped when I put 1000pF from output to negative input. To get Vce to go from 11.5V down to near ground when the collector current is low, I added 100ohms as a parallel discharging path from the 1000uF. On the oscilloscope screen, in XY acquisition mode, there is a vertical artifact at the left edge. This is because I don't know of a way to "blank the beam" when the 1000uF is being charged. In XY mode, Ch. 1 is horizontal, Vce, and Ch. 2 is vertical, Ic. Ch. 1 2V/div, Ch. 2 1V/div. I had expected to charge the 1000uF in 6ms but 30ms is more what is needed. If I let each base current go for less than 600ms, the oscilloscope doesn't seem to capture all the trace. I am doing normal trigger on the rise of collector current (Ch. 2), pos slope, 840mV level. There may be a better way. One base curve may be frozen using the run/stop button. Cursors display offers two dots but I don't know if it is meaningful, time is the parameter. A regular, Yt, display may be better to pick off base current, collector current, and Vce.
Here is something better about persistence. With the acquisition button, waveform display button, set persistence time (use A knob) to 7s, and clear persistence just before a family starts. Use Intensity, waveform intensity to brighten up the weak traces. The old family fades away as a new family is traced. Pretty nice. Get a photo. Probably, the screen could be saved to USB memory. A lesser oscillopscope (<$2000) wouldn't give all this control. My Tektronix DPO 2002B has "Digital Phosphor" proudly lettered above the display and it is strutting its stuff.
By July 22, the sketch is all done and I can choose between collector curves and 2s-on, 2s-off power cycling to see if 0.18W hurts a 2N3904, over weeks.
July 24, 2018 Progress on microwave-oven transformer multiplier, the one with 6 4kv rectifiers but it might be called 5 stages. At night and outside because of ozone, I photographed the multiplier at 10s aperture time and found a little blue glow on the outermost 100ohm 1/2W, where there are 5 100ohm in series doing a little current limiting. I had formed the resistor lead into a loop but it was a little more than 360 degrees and 0.1" of resistor lead poked out from the loop, toward the grounded hardware-cloth safety cover. That is where it has been doing corona, draining down the output voltage. I took 5" of #22 wire, soldered to that outermost resistor, and formed the wire into a loose helix around the resistor string. My impression is that you don't have to have smooth spheres to cut down on corona, you can do it with a wire helix. That is the way fields are fashioned in electron tubes (vacuum tubes).
The resistor-string helix stopped the corona, and now I know what to look for, tiny purple or blue glows, I can sometimes see them without photography. But another corona point showed up one rectifier down the string, again at a point facing toward the grounded cover. Another loose loop of wire stopped that corona, and photography doesn't show anything more. But the voltage can now rise much higher and there were snappy, scary sparks from multiplier to cover, 0.9" long! I bowed out the cover and that stopped.
Into the ballpoint-pen plastic tube that penetrates the safety cover, I inserted 5mm glass tubing and a string of nine 10M resistors. This is safer to discharge to, like with the string of six neon lamps or the homemade electroscope, gold-leaf style but using a hanging round paper circle, 4.5" diameter. There is a whisper of hiss when discharging to the neon-lamp string though the 90Mohm, as a thin purple arc is drawn at least 0.4".
With higher voltage comes danger of breaking down capacitors. I put in my 150W-lamp-in-series device, in series with transformer secondary. The neon pilot lamp lights up! There is less voltage and it is better for capacitors but it is worth a lot of demonstrating. I have to add a better warning about residual charge, there is a lot of it. Did so.
July 27 With 10 470k 1/2W or 1W in series through the ballpoint-pen tube through the safety cover, with vinyl tubing to reduce corona, go to the window-glass/alum. screen 396pF cap and let some 2N3904 be shocked. Can't get any failure! I am letting a sizable spark, or several, go into E, B, or C and ground on another lead. They show no problem on curve tracer.
Try a 4011, set up to show NAND function with LED, with 10ks from grd or supply to inputs. Shock pin 1, an input, for a full second or two. That makes pin 1 look like stuck-at-one fault but the other input still functions. Out of the pin-1 input comes 0.3mA through 10k to .29V, with supply of 6V.
So I can cause a failure, but not in an NPN. Try a SS9018, 1.1GHz NPN. It is destroyed by putting the base on the cap, and it has a soft breakdown at 6V, no gain. But I see I am missing the ground of the cap! Get that grounded and I see the high-current, snappy sparks, a few per second, like before. Try the 2N3904 again. Sure enough, one spark from grounded cap destroys the EB jct, it is 61ohms now, either way.
Next step is taking the most recent JFET ESD-resistant probe, the one with wide ground margins, put covers over back and front with screws, apply sparks, and see if the probe innards survive.
John Engelbrecht July 28 2018 To make a human-body style of static discharge, it needs 1000Ω in the discharge path. But if the 1000Ω is one resistor, that might be 20,000V across that resistor, and even if the duration is 0.2μs there is likely to be an arc across the resistance material, bypassing much of the ohms. While I was at IBM in Austin, we had a design manual that warned us to limit the voltage on high-ohm resistors to certain values. It was around 100V for 1/4W and 250V for 2W.
I have a lot of 27Ω 1/4W. 1000Ω needs 37 of these in series, and I built that up, wrapping the resistors around a plastic soda straw and coiling up the excess leads into anti-corona circles. If there is a transient 20,000V on this 1000Ω, each resistor gets 540V! But I am not going to make 1000Ω using 100 10Ω resistors, lets just see if a 37-resistor string works. I put a toy golf ball, covered with foil, on top of the resistor string to act as an anti-corona termination. There is a neon lamp across one resistor, and I do see a tiny flicker when I discarge the 396pF, window-glass/aluminum-screen capacitor through the 1000Ω string. When I compare the sight and sound of a spark through the 1kΩ to the spark of a grounded clip lead discharging with no ohms, the 1kΩ damps the spark a lot, maybe to a tenth. Looking at the 1kΩ string in the dark, I see no corona.
Going on, now, to discharging through 2N3904s with the 1kΩ in series, even though the 400pF is a lot more than a human-body 50 or 100pF, one of them survived a collector-to-emitter discharge, repeated the reverse direction, but succumbed when I did 15 sparks, doing all permutations of E-B-C. Another 2N3904 died when I did just two sparks, one E-B with base negative, and the other B-E with emitter negative. But it didn't fail with the appearance of a soft-knee 6V zener like the others have, it behaves on the curve tracer like very low Beta, though on MPJA DMM transistor tester it shows no conduction. With a DMM diode test, both junctions, BE and BC, seems OK, but in my curve tracer it acts like very low Beta. Sounds like 2N3904 is most sensitive to sparks onto base. Internet shows an article where RF BJT base-collector is most sensitive.
These are interesting findings. Go on to the anti-ESD JFET probe and see if the etched spark gap, neon lamp, 360Ω x 4, and reverse diodes to supplies lets the probe survive. This will also be instructive if I do faster anti-ESD probes using RF BJTs, with signal limited to logic levels. Progress on August 1: the JFET probe that was specially etched to have screw-fastened, removable brass covers, so that any damaged parts inside can be replaced, is progressing toward getting RG-6 coax and the covers. The idea is to subject the approximately 15MHz input to sparks and see if it survives, then go on to maybe 200 sparks. If there are part failures, it may be the 360ohm SMD 1206 resistors arcing inside the resistors' coatings, letting too much current through to the limiter diodes, which bypass spark energy to ground inside the shielding covers. This spark testing must be with the 4-wire power cable connected and powered up but no oscilloscope connection; the 4-wire cable acts as an antenna for static energy to get into the probe circuits, since I do not use feedthrough capacitors where the cable penetrates the brass shield, for compactness and economy.
Aug 26, 2018 Successful use of S/N 3 JFET active probe, it survives probably 15kV through 1kΩ direct to mini-grabber and then is able to probe 60Hz sawtooth test signal, -8V to +12V, isolated by 330kΩ resistor to show that the probe continues to have 10MΩ input impedance. The probe's RG-6 coax is connected to the oscilloscope during ESD discharging, I can't see any sneak paths from spark to coax, just a transient for about 80us, clamped to supply in the probe.
This is the culmination of eight months of work. There was no guarantee that the JFET was going to survive, or that sneak paths from spark to coax would not put hundreds of volts of transient into the oscilloscope. I have done maybe 300 discharges onto the yellow mini-grabber. The neon lamp always lights up, seen even with room lights on.
Send e-mail to Jim Brakefield, San Antonio IEEE life member affinity group.
file bio and abstract for IEEE Active Probe Static Immunity.txt
Biographical Information
John Engelbrecht is a resident of south Austin and has been an IEEE member since 1976. He is married and has two children and three grandchildren. His BSEE is from UT Austin. He was employed at IBM in Austin for 18 years doing mainly analog designs. He did electromagnetic compatibility work on printers and worked with Southwest Research Instititue and Honeywell, both in San Antonio, to get TEMPEST listings. One listed printer flew on Air Force One. John received two IBM corporate awards for TEMPEST and two ways of probing electronics during static discharge.
After IBM, John taught at TSTC in Brownwood for 12 years.
John is active with school teachers to demonstrate engineering algebra, and with home schoolers to enhance STEM. John does custom printed-circuit-board etching, instrument design, and Arduino programming.
John has been a deacon at three Baptist churches in Texas and Georgia.
Abstract for Presentation, "Save Your Oscilloscope from Static Destruction"
Digital oscilloscopes are threatened by electrostatic discharge, ESD. Ten-to-one, passive-divider probes give some protection. But when static is 30,000 volts, the 9-Megohm probe resistor can suffer arcing, and the 15-amp pulse that enters the oscilloscope's input will far exceed the 450V transient tolerance of the ADC circuit. Factory repair costs half the purchase value of the oscilloscope.
To counter the ESD threat, various active, 10-to-1 probes can be designed. The subject of this presentation has 15MHz bandwidth, input capacitance of 11pF, input resistance of 10MΩ to 30MΩ, input range of -9V to +12V, and parts cost (probe components only, not including metal shielding, assembly, or power supply) of $3. The probe drives RG-6, 75Ω coax of any length, which is terminated at the oscilloscope. The probe makes use of no less than four components to mitigate ESD. When subjected to 15kV ESD from a human body model, straight to the mini-grabber input connector, the probe recovers in 200μs and transmits to the oscilloscope no more than 16V of transient.
The presentation covers the schematic of the probe, power supply, and 0.2"-long purple sparks onto the probe input, followed by proof that the probe "keeps on ticking." A simpler ESD-immune probe, limited to logic voltages, is mentioned. In conclusion, the 15kV, anti-corona, high-voltage test equipment is displayed, and safety measures to cope with the lethal microwave-oven transformer are described.
Sept 3 2018 With this outstanding success, sparking to the input of an active probe and seeing it survive hundreds of sparks, I go on to etch the last PCB for the negative supplies, the PCB that has two more channels of op amp circuits. Need to get the whole system packaged up so the Tektronix DPO 2002B can be used safely by home-school students.
Sept 2 2018 Found that Arduino can be programmed by Raspberry Pi and a 7" or 10" HDMI monitor. Thinking about four sets in Tahoe, battery powered, Sidewalk Arduino Coding. See https://sites.google.com/site/solderandcircuits/home/tobc-tech-for-students/sidewalk-arduino . Received two sets to evaluate with.
Sept 13 2018 Finished all 3 of the "varying negative supply" for ESD-immune active probes, which vary between -36.2V and -12.6V, to lessen the dissipation in the probes. The current-sense diff amps are working, had to wade through bridges and gaps in the traces. Next in this big project is transferring scattered Arduino I/O onto some clustered pins and use a strip of 0.1"-spaced pins to plug in securely.
Jan 12 2019 For the 2019 One Day Academy STEM Fair (Shannon Evans contact), I was invited back after I had stepper-motor setup dropping ping-pong balls, alongside Cinda Lewis. The main demonstration is Arduino based, again. It is a reaction-time meter, displaying on a laptop using Serial.print. The visual stimulus is a bright, narrow-beam, yellow LED shining at a 3 ounce paper cup, which shadows a CdS cell. When the user sees the yellow LED come on, he knocks the paper cup off the stand. Arduino measures the milliseconds from turning on the LED to the paper cup leaving the stand.
A feature of the Arduino sketch is variable time from pushing an "arm" button to Arduino turning on the LED, varying from .8s to 3s, using random(800,3000). This keeps the user from becoming accustomed to the timing, predicting when to knock the cup, and cheating by starting to knock the cup before seeing the LED come on.
Another feature is averaging successive trials. This is done using a second pushbutton, "reset average." This is a very nice feature.
A third feature is invalidating certain operations. Since college-age people average 190ms on reaction time (when the cue is visual), and some people can train to get down to 109ms, the sketch detects any time below 80ms as being invalid. Also, if the user gets out of sequence between placing the cup on the stand and arming the system, a reaction time over 1500ms is considered invalid. Also, if the cup is not in place when the arm pushbutton is pressed, there is an error message.
All in all, this is a very neat project. But the sketch is not easy to follow.
//file reactionTimeVer3.ino J Engelbrecht 1-8-2019 Uno
// for One Day Academy STEM Fair Shannon Evans LED to knocking a paper cup off a stand
// College-age person, visual cue to hand motion, is avg. 190 milliseconds.
//The basic state machine is working on Jan 9 2019, needs embellishments now in Ver2
//Ver2 4:30PM averaging is working, beeper working
//Ver3 attempt to get in "valid" events and warning of arming preceeding cup placement. "Valid" includes
// excluding any elapsed time <80ms and maybe elapsed time >700ms.
const byte notArmPin=8;
const byte notResetAveragePin=9;
const byte LEDPin=10;
const byte CdScollectorPin=11; // true if light gets through, cup not in place
const byte beeperPin=12;
const byte armAcknowledgePin=13;
//GLOBAL variables
int sumForAverage = 0; //running total of elapsed milliseconds from LED-on to cup-flip, "valid" events only, since
//the last push of Average Reset button
byte numOfEventsInTheAverage=0; //divide sumForAverage by this to get the average milliseconds
boolean state0=true; //a reset state the state machine is a "one hot" state machine
boolean stateCupNotArmed=false; // cup is in place
boolean stateArmed=false; //cup in place, arm pushbutton has been pressed
boolean stateLEDbeforeCupFlip=false;
boolean stateCupFlipped=false;
long timeStartOfLED;
long timeCupFlip;
long elapsedTime;
void setup() {
pinMode(LEDPin,OUTPUT);
pinMode(beeperPin,OUTPUT);
pinMode(armAcknowledgePin,OUTPUT);
pinMode(notArmPin,INPUT_PULLUP);
pinMode(notResetAveragePin,INPUT_PULLUP);
pinMode(CdScollectorPin,INPUT);
Serial.begin(9600);
Serial.println("Reaction Timer sketch for Arduino");
Serial.println("by John Engelbrecht STEM Coach Jan 2019");
}
void loop() {
//the whole loop is traversed regardless of which state is true at the current time
if(!digitalRead(notResetAveragePin) && !digitalRead(notResetAveragePin)) {
sumForAverage=0; numOfEventsInTheAverage=0;
Serial.println("----------------------------");
Serial.println(" Average is cleared.");
delay(300);
}
if(state0 && !digitalRead(notArmPin) && !digitalRead(notArmPin) ) { // !digitalRead(CdScollectorPin) && //digitalRead(notArmPin))
//if cup not in place and Arm button is pressed, don't go to next state
errorBeep(3);
Serial.println("Put the cup back in place.");
}
else
if(state0) {
digitalWrite(LEDPin,HIGH);
digitalWrite(armAcknowledgePin,LOW);
}
if(state0 && !digitalRead(CdScollectorPin) && !digitalRead(CdScollectorPin)) stateIsCupNotArmed();
if(stateCupNotArmed && !digitalRead(notArmPin) && !digitalRead(notArmPin) ) {
stateIsArmed();
digitalWrite(LEDPin,LOW);
digitalWrite(armAcknowledgePin,HIGH);
digitalWrite(beeperPin,HIGH);
delay(20);
digitalWrite(beeperPin,LOW);
delay(random(800,3000));
}
if (stateArmed) {
stateIsLEDbeforeCupFlip(); //the delay after ARMing has elapsed in the previous if statement
digitalWrite(LEDPin,HIGH); //turn on the LED which shines at the cup, and start the timer
timeStartOfLED=millis();
digitalWrite(beeperPin,HIGH);
delay(30);
digitalWrite(beeperPin,LOW);
}
if (stateLEDbeforeCupFlip && digitalRead(CdScollectorPin) && digitalRead(CdScollectorPin) ) {
stateIsCupFlipped();
timeCupFlip=millis();
digitalWrite(armAcknowledgePin,LOW);
elapsedTime=timeCupFlip-timeStartOfLED;
if (elapsedTime>80 && elapsedTime<1500) {
sumForAverage+=elapsedTime;numOfEventsInTheAverage++;
}
else if(elapsedTime<80) {
Serial.println("You can't have a reaction time <80 milliseconds");
errorBeep(4);
stateIsZero();
}
else if(elapsedTime>1500) {
Serial.println("You left the cup on over 1.5 seconds,");
Serial.println("push the reset button and try a new run.");
errorBeep(4);
stateIsZero();
}
}
if(stateCupFlipped) {
Serial.print("reaction time ");Serial.print(elapsedTime);Serial.println(" milliseconds");
if(numOfEventsInTheAverage>0) {
Serial.print(" Average time ");Serial.println(float(sumForAverage)/float(numOfEventsInTheAverage) );
}
stateIsZero();
}
} //end of loop
//FUNCTIONS
void stateIsZero() {
state0=true; //a reset state the state machine is a "one hot" state machine
stateCupNotArmed=false; // cup is in place
stateArmed=false; //cup in place, arm pushbutton has been pressed
stateLEDbeforeCupFlip=false;
stateCupFlipped=false;
}
void stateIsCupNotArmed() {
state0=false; //a reset state the state machine is a "one hot" state machine
stateCupNotArmed=true; // cup is in place
stateArmed=false; //cup in place, arm pushbutton has been pressed, random delay is proceeding
stateLEDbeforeCupFlip=false;
stateCupFlipped=false;
}
void stateIsArmed() {
state0=false; //a reset state the state machine is a "one hot" state machine
stateCupNotArmed=false; // cup is in place
stateArmed=true; //cup in place, arm pushbutton has been pressed
stateLEDbeforeCupFlip=false;
stateCupFlipped=false;
}
void stateIsLEDbeforeCupFlip() {
state0=false; //a reset state the state machine is a "one hot" state machine
stateCupNotArmed=false; // cup is in place
stateArmed=false; //cup in place, arm pushbutton has been pressed
stateLEDbeforeCupFlip=true;
stateCupFlipped=false;
}
void stateIsCupFlipped() {
state0=false; //a reset state the state machine is a "one hot" state machine
stateCupNotArmed=false; // cup is in place
stateArmed=false; //cup in place, arm pushbutton has been pressed
stateLEDbeforeCupFlip=false;
stateCupFlipped=true;
}
void errorBeep(byte numTimes) {
for(byte i=0;i<numTimes;i++) {
digitalWrite(beeperPin,HIGH);
delay(70);
digitalWrite(beeperPin,LOW);
delay(70);
}
}
//NOTES
/*const byte notArmPin=8; pushbutton grounds this digital input
const byte notResetAveragePin=9; pushbutton grounds this digital input
const byte LEDPin=10; this is the bright yellow narrow-beam LED that illuminates the CdS cell
const byte CdScollectorPin=11; // true if light gets through, cup not in place
const byte beeperPin=12; active beeper helps a lot in various situations
const byte armAcknowledgePin=13; optional
//GLOBAL variables
int sumForAverage = 0; //running total of elapsed milliseconds from LED-on to cup-flip, "valid" events only, since
//the last push of Average Reset button
byte numOfEventsInTheAverage=0; //divide sumForAverage by this to get the average milliseconds
boolean state0=true; //a reset state the state machine is a "one hot" state machine
boolean stateCupNotArmed=false; // cup is in place but ARM button not yet pressed
boolean stateArmed=false; //cup in place, arm pushbutton has been pressed
boolean stateLEDbeforeCupFlip=false;
boolean stateCupFlipped=false; these 5 states are shown in order*/
/* This way of doing one-hot state machine is pretty cumbersome. Is better to use Switch-Case for
state machine. Doing so is best done using number codes for the states, as I did in the curve tracer.
That way, Serial.print can output state numbers to Serial Monitor, from which they can be copied to
spreadsheet and plotted, a very nice way to confirm the state machine.
But the way I do a one-hot state machine in this sketch, the states have English names, and
that is nice. This sketch could have used while statements instead of ifs, and that would have made
the advancement of states run a lot faster.
If you are trying to make sense of the code, note this: a state name with "is" in it means it is
a function call. The function will assign boolean values to all five state variables. Only one state
variable may be true at once.
The many if statements in loop() are looped over continuously, if there is no action then loop()
probably executes in about 8*4us*3 = 100us which is actually very fast.
*/
2019 Jan 27 Marlin P. Jones and Associates has a 4.5-digit panel voltmeter for $13. In fact, Amazon has full 5 digits for $9. But I purchased three MPJA panel meters and am thinking how to augment one to use for a Kelvin micro-ohmmeter and microvoltmeter, using chopper op amps I already have. I often need to measure homemade nichrome-wire resistors, and having a microvoltmeter would be nice for use in a resistance bridge. I am thinking in terms of a battery-powered, floating instrument that has no AC power connection, just a red lead and a black lead. The battery would be 12V sealed lead-acid, several amp-hour.
I have had a need for more accuracy than 3.5-digit DMMs provide. I have looked at prices for 6.5-digit bench instruments, they are over $600. A 4.5-digit meter with high input impedance would forestall a 6.5-digit meter purchase.
The $13 meter has limitations. It has only 354kohm input resistance, 9.26mA supply current (5V is fine), fixed 0-33V range (1mV resolution). That is 85uA input current at 30V, quite a low resistance. It has a STM 85003F3P6 $1 microcontroller running the LED digits and a tiny, 6-lead ADC. The ADC is probably 16 bit.
If I develop a chopper-op-amp front end, that would be complemented for accuracy by the 0.1% 0805 SMD resistors I have, and the 5.000V reference IC MAX6350CSA, +- 0.02%.
The first augmentation need is to give robustness: static tolerance, input voltage clamping, and high input impedance. This would be through an emitter-follower circuit that gives a 0.7V fall in a NPN followed by a balancing 0.7V rise in a PNP. I have a circuit that can hold both emitter followers at about 30uA +- 15uA regardless of input voltage. That should give input-offset voltage of several millivolt, and the Vio would be measurable and quantifiable.
Since the MPJA panel meter is fixed 30V range, the battery-powered circuits would need 3mA, +35 and -10V to power the circuits. For micro-ohmmeter, current sourcing at 1A, 100mA, and 10mA would be needed, with high-series-resistance, high-voltage, pseudo current sourcing at 1mA, 100uA, 10uA, and 1uA. The current sourcing would only need to get up to 0.3V, so even the 1A current source wouldn't be too high in power. The 0.3V limitation is to keep silicon junctions off.
I foresee using an Arduino to display a decimal point below the panel meter, and an indication of V or ohms and a range like mV or uohm.
Another use of the panel meter is for maximum-accuracy voltmeter with native (354kohm) input resistance. This would have limited static tolerance.
The provisions for voltmeter go like this. 0 to 33V is choice from above, the bare panel meter with almost no static protection or the emitter-follower buffer which has a lot of protection but introduces some millivolts of Vio, but has input resistance of about 60Mohm. The schematic of the emitter-follower buffer is shown below. For 0 to 3V range, provide a gain block using a regular op amp, supplemented by an output that can reach to 33V. For 0 to 0.3V range, provide the chopper op-amp gain block, with the output part that reaches to 33V. For 0 to 0.03V range, cascade, first with chopper section at x100 followed by x10. A typical display at this x1000 would be 29.123mV, which shows 1uV resolution.
This makes for a very interesting project at low cost. It would give a much better measurement capability than I now have.
Edit this menu via the Pages tab
Show me
goal is to keep Q2 current about constant vs. input voltage, but actually, as Q1 current goes up gradually, let Q2 current rise the same amount to keep Vbe’s about balanced.
Approx. constant current in Q1 is from swamping the 10uA rise with maybe 20uA from a constant current source that isn’t shown in this simulation
R5 is a good control. But it actually has a high sensitivity, check what gets built, that Q2 current rises somewhat as input voltage goes 0V to 30V.
-10 3000000
Vin -V supply R1 R2 I in R2 V on Q3 base I in Q3
0 -10 3.00E+06 300000 2.606E-06 -8.518 1.564E-05
3 -10 3.00E+06 300000 3.515E-06 -8.245 2.109E-05
6 -10 3.00E+06 300000 4.424E-06 -7.973 2.655E-05
9 -10 3.00E+06 300000 5.333E-06 -7.700 3.200E-05
12 -10 3.00E+06 300000 6.242E-06 -7.427 3.745E-05
15 -10 3.00E+06 300000 7.152E-06 -7.155 4.291E-05
18 -10 3.00E+06 300000 8.061E-06 -6.882 4.836E-05
21 -10 3.00E+06 300000 8.970E-06 -6.609 5.382E-05
24 -10 3.00E+06 300000 9.879E-06 -6.336 5.927E-05
27 -10 3.00E+06 300000 1.079E-05 -6.064 6.473E-05
30 -10 3.00E+06 300000 1.170E-05 -5.791 7.018E-05
33 -10 3.00E+06 300000 1.261E-05 -5.518 7.564E-05
rise in Q1 cur 1.000E-05
ratio 9.988E-01 which is close to 1.00
50000 33000 19180 37
Vin R3 R4 R5 V on Q4 base +V supply I in Q4 I in pan mtr I in Q2
0.0 50000 33000 19180 35.784 37 0.000027 0.000000 0.000027
3.0 50000 33000 19180 35.604 37 0.000036 0.000008 0.000028
6.0 50000 33000 19180 35.424 37 0.000046 0.000017 0.000029
9.0 50000 33000 19180 35.244 37 0.000055 0.000025 0.000030
12.0 50000 33000 19180 35.064 37 0.000064 0.000034 0.000031
15.0 50000 33000 19180 34.884 37 0.000074 0.000042 0.000031
18.0 50000 33000 19180 34.704 37 0.000083 0.000051 0.000032
21.0 50000 33000 19180 34.524 37 0.000093 0.000059 0.000033
24.0 50000 33000 19180 34.344 37 0.000102 0.000068 0.000034
27.0 50000 33000 19180 34.164 37 0.000111 0.000076 0.000035
30.0 50000 33000 19180 33.984 37 0.000121 0.000085 0.000036
33.0 50000 33000 19180 33.804 37 0.000130 0.000093 0.000037
rise in Q2 cur 1.00121949064175E-05
The funny thing about this emitter-follower buffer is that emitter followers can't quite get to voltage gain of 1. This is because of slightly above-zero output resistance of emitter follower. The more like a current source the load of an emitter follower is, the closer it gets to gain of 1. This gain error is not modeled in the simulation above. Therefore, when the panel meter is used for gain of 1, it will be a gain of .98 or so. This is likely to be quite stable, and a correction multiplier of about 1.02 could be used to correct for it.
The action of Q4, pushing just enough current to make Q2's current rise slightly as the input rises, only works if -10V is very stable. -10V must be generated from an op amp, and the raw negative supply needs to be -13V or so.
Topic: generating 120VAC for Sidewalk Arduino Coding in Tahoe, off-grid. I spent months around Feb 2019 trying to get a fully DIY inverter working. Tektronix DSO helped a lot. Arduino used to get 5 bits of DAC voltage, and amplify that to about 59VAC peak and use old 60Hz transformers to step it up to 120VAC. Always seemed to be some magnetic core saturation, finally gave it up and did heavy filter of the "modified sine wave" cheap Harbor Freight inverter, adding isolation transformer to be able to bond neutral to earth ground.
The C code that is more-than-basic:
1) The arrays tq[ ] and tqb[ ]. The values in these arrays were generated by a spreadsheet and just copy-pasted into the Arduino sketch. How neat is that?
2) At "if( mask1 & bitPlace ) {
writeToaDACBit (pinsDAC[i-1], valDAC, bitPlace); ", the ampersand is a bitwise AND of two bytes, and then there is a function call. The first parameter is from the DAC-pins array--this is so neat and compact! The IF statement makes use of the coding fact that a Boolean condition can be stated by an entire byte, false being 00000000 and true being anything else. Knowing how to do this, for me, comes from decades of dabbling with code. A young person can pick it up quickly, but it does require a lot of focus.
3) At "return prevVal ^ newVal; ", this is the return of a byte that is a bitwise exclusive OR of two bytes. Exclusive ORing is rarely used in Arduino code, but it fit my need so nicely.
It must be said that my use of Arduino for a DIY inverter depends greatly on the custom circuits I built up on DIY printed circuit boards. After all, Arduino handles 5 volts and 20 milliamps, whereas an inverter is working with 12 amps of battery current and 120 volts. But Arduino is so efficient in generating a neat sine wave at an accurate frequency, and managing the H-bridge switching. These are jobs that could be done without a microcontroller, but Arduino is cheap and very neat.
August 31, 2019 M. and I moved to San Antonio on July 9. (M's family to Leander, we move near granddaughters.) Reese is newly in K at Kallison Elementary!
Sidewalk Arduino Coding is moving ahead slowly. Jessie expressed an interest in making a robot "from scraps" as her Gramma T starts projects with her textile scraps box. We are working on that. It is a portable device, easy enough to take into a school if there is interest. I am joining up with Kallison Ranch Hands which includes background check. New church is Calvary Hills Baptist, which declined a lot for years but has new, young pastor who has done service for N. Am. Mission Board in Colorado. Many new homes near the church.
The big project in the last month is editing Physics Timeline in this web site to print with new Epson Ecotank ET-7700 ink jet printer. That has now happened. About 325 pages including preface, intro, index. I put in dozens of pictures to make it interesting for children, and J and R do indeed like paging through and looking at pictures. J asks questions about "what is this?" I came up with a way of explaining Summer of Love in terms of teenage girls leaving their families and going to live in San Francisco. The index is not by page number (there are no page numbers), but by date. ET-7700 can print duplex, a big advantage. I took the thick printout to Office Depot. Splitting into two volumes, spiral binding is just $10 for the whole deal, with thick, clear, plastic covers that are really nice. I am now working on printing some of the sub-pages from the time line web pages. This will be a slender third volume. 325 pages has brought the black and cyan ink tanks down about 7%. The ink, once charged from supply bottles, has a recommended life of just six months. A new set of five bottles is about $75. Two sets of bottles came in the box. I spent a lot of money on nice Epson paper including premium glossy photo paper. When the digital photo is high resolution, like scanner, an 8x10" glossy printout is very nice. Having a printed time line brings up the next question, will it be worth the large amount of work? I intend to provide one copy to J & R, another for M's family.
April 2020 Arduino to control a DC gearmotor and lead screw. The motor-leadscrew assembly was purchased about 5 years ago as surplus from MPJA.com. The motor has a single-channel rotary encoder wheel that gives about 2200 pulses as the lead-screw follower nut goes through the full range, which is only 3.75". The assembly was built for a large, heavy copier/printer. The assembly is steel and is heavy. The motor works on 8V or higher. Since the encoder has only a single channel, you only know that the motor is turning, not which way it is going.
I wanted to use Arduino Mega 2560 to control the device. I built a wooden table that slides on the steel baseplate and is attached to the follower nut. There is a DC motor driver, DIY, with a relay to do reversals and an NPN power transistor to turn on and off current, with PWM control by Arduino. The PWM works well. There is a little commercial buck converter to get 8V from 12V. This driver can sense motor current through Arduino, the intent being that end-of-lead-screw travel can be sensed by an increase of motor current when the follower jams at either end. But the increase of current is only about 2x, and a mechanical load on the wooden table easily swamps this small current change, so I ended up not sensing end-of-travel by current.
The encoder has a nice optosensor with about 10% hysteresis and TTL output, 10k pullup open collector. This works well into a digital input of Arduino.
I wanted to use interrupt for the encoder, but I also wanted to do Serial.print, and the two can't be done at the same time. I tried noInterrupt and even detachInterrupt, after which I tried Serial.print, and it wouldn't work. So I gave up on interrupt. To sense the end of travel in the direction toward the motor, I arranged a light-pressure microswitch (the type with a lever) to sense the table. A sketch makes the table move and stop at any number of positions, and with a slower terminal speed when needed. I wanted to make the table do a slow sinusoid but the program is hard to think through and I went on to other things. The COVID-19 shut down in underway and Coding Camp at Calvary Hills Baptist Church may not happen, but I am preparing various posters and example Arduino projects anyway.
May 9 2020 Sidewalk Arduino Coding, https://sites.google.com/view/san-a-coding-camp and https://sites.google.com/view/arduino-coding-austin/home/chbc-outreach-idea , have audio components through active and passive beepers, but also through 8-ohm speakers for which I build PCB-based speaker amplifiers. These are in two styles. One is a on-off transistor driving a speaker, for digital signals coming from Arduino, with biasing to allow about 0.15V Class-A, linear signal. The other speaker amplifier is a Class B amplifier that I just finished. This requires a -8V to -15V DC supply, for which I etched a TL494-based negative supply to convert +12V to -11V. This is done with center taps on primary and secondary, balanced MOSFETs driving the primary, minimal dead time, 35kHz on primary, 70kHz on the TL494 oscillator. No feedback. Hope for no transformer saturation due to unbalanced driving resistances in the MOSFETs. The transformer is a ferrite toroid with not all that much inductive reactance, about 125uH for 30 turns. The first transformer used some of the original winding, about #16 wire, with added turns to get more inductance. There was a lot of leakage inductance and inductive spikes of hundreds of volts on the MOSFETs. I put in a snubber between drains, 200 ohms and .02uF. The 200 ohms is hot.
I re-did the transformer completely with #22 primary and secondary, wound quadrafilar, and that has very small leakage inductance but limited voltage between primary and secondary. At 8W output, the DC output drops from 11V to 9V. That is OK. MOSFETs need little sinks. 12V primary-side filtering is ferrite bead and four 100uF caps. Output-side filtering is ferrite bead and three 100uF caps.
The Class B audio amplifier uses a 741 op amp to minimize crossover distortion. The PNP output uses a small PNP and a SOT-223 FZT3019 1-amp transistor to simulate a PNP power transistor. That combination sometimes oscillates, but I have B-E resistors that help it be stable. There is one diode between the NPN and "PNP" bases to lower the crossover distortion. Gain-setting resistors are 10k and 100k. An input RC filter limits very high frequencies. This speaker amplifier just works well input an 8 ohm speaker. The transistors need some sinking. I will put the speaker into a cardboard-box infinite baffle, that improves the sound so much.
May 14 2020 After building up a nice little Class-B audio amplifier that can put 8V peaks onto an 8ohm speaker, needed -12V DC supply. While still in Austin last year, I had etched boards for both the Class-B amp and a DC-DC converter for negative supply, got the supply built. Both boards constitute a "plate amplifier" that attaches to the cardboard speaker box for an old TV speaker. Gives nice audio with just +12V bulk supply. With DIY piecewise linear function generator broken during move to San Antonio, needed sine wave generator to exercise speaker system. Brought out Arduino Due to use DAC output, 12 bits. It was not easy, had to find that sin() even in Due with ARM processor at 84MHz takes 60 us! DAC analogWrite is only 4 us. Used a big lookup table to speed up the sine finding. Came out to be 23us between DAC outputs. Lots of calculation to decide where in lookup table to look. This was so much work that I am showing the full code here in case I need this in the future.
// JE 5-12-2020 DUE_DACver4.ino
// do not see full 0 to 3.3V output from Arduino DUE's DAC, see 560mV to 2.80V.
// On WWW, it is revealed to be between 1/6 of 3.3V and 5/6 of 3.3V.
// With DAC output working, I can try multiple frequencies (harmonics and near harmonics)
// but first check out a sine table for further speed, in ver3.
// Ver3 Note that frequencies above around 30Hz cannot get full 12-bit resolution because
// the analogWrite (4us in Due) or sin() (60us in Due) are too slow.
// Can a sine lookup table be done at 12-bit resolution? No,
// 12-bit resolution is in the voltage direction, to get the smallest voltage steps
// requires about 3x finer resolution in time than 4096 array entries.
// With 4096 entries, max-slope area steps in steps of 3.
// Ver4 tries to speed up prog5 while loop a little but it isn't faster.
// 7.5kHz is definitely there. Ver4 is pretty good result for single sine at a time.
// To put together multiple sine frequencies and phase shifts, that would be multiple
// sine-table lookups, wouldn't it? Would need a user function.
int baseline = 2048; //bias sine wave halfway through the 4096 available levels, 12 bit
unsigned long startTime = micros(); //timestamp for each second of sound
unsigned long timeExpire; //all time-related quantities must be unsigned long
int slookup[4096];
int indexInArray;
unsigned long currentMicros;
unsigned long integerCyclesCompleted ;
unsigned long cycleTimeInMicros;
unsigned long microsIntoThisCycle;
unsigned long factor13;
void setup() {
analogWriteResolution(12);
for ( int sl1 = 0; sl1 < 4096 ; sl1++) { //takes .25s to fill lookup table
slookup[sl1] = int(2048.0 * sin(sl1 * 2 * 3.14159 / 4096) );
//this is done for a full cycle even though it could be done just up to pi/2, 4x better
} //end of for
} //end of setup
void loop() {
for ( float i3 = 60; i3 < 12000.0; i3 *= 1.1 ) { //i3 is Hz it can handle 7500Hz and maybe 20kHz
cycleTimeInMicros = (unsigned long) ( 1.0 / i3 * 1E6 );
startTime = micros();
timeExpire = startTime + 1000000UL; //dwell one second at each frequency
integerCyclesCompleted = 0UL;
while ( micros() < timeExpire ) {
currentMicros = micros(); // stake in time
factor13 = integerCyclesCompleted * cycleTimeInMicros ;
// factor13 tries to save some time in the while loop, this multiply is used twice, but doesn't save time
if ( currentMicros > startTime + factor13 + cycleTimeInMicros ) integerCyclesCompleted++ ;
// the additional one cycleTimeInMicros was tricky
microsIntoThisCycle = currentMicros - factor13 - startTime ; //how deep into the lookup table does it need to go?
indexInArray = int(4096.0 * microsIntoThisCycle / cycleTimeInMicros ) ;
analogWrite(DAC0, baseline + slookup[indexInArray] );
// while loop time is 23us, pretty fast, at 7500Hz there are 6 DAC outputs per cycle.
//Comparing sine() function to sine lookup, speedup is from 80us to 23us
} //end of while
} //end of for
} //end of loop
Summer 2020 Margaret, I, Cheryl W, Violet, Noah ran a 6-hour-a-week summer Arduino Coding Camp at CHBC. Couldn't find a way to attract public-school students, as church outreach, we went with 6 Trail Men and one AHG. It was pretty successful. Projects attracted quite a bit of interest for students. We did visit to Altex to see all their parts.
Oct 3 2020 Started Girls Who Code clubs at CHBC, have 3 in 3rd-5th and 4 in 6th-12th. (Highest grade 8th.)
Oct 5 2020 On subject of 1/f noise project, recording 1/f noise for a year so I can graph the 1/f noise to microHertz, I had purchased ADC, ADS1115, 16-bit, on little PCBs at around $12 each, with pins at 0.1" spacing. This IC requires gain-register and sampling-rate-register loading before serial data may be uploaded, all by I2C. This is quite involved. But I found that Adafruit makes boards that use CircuitPython. A powerful board is Metro M4. It is quite like Arduino Mega 2560 but the processor is better. But price is below $40. There is a CircuitPython library for ADS1115.
This sounds quite attractive. Metro M4 includes a micro-SD card for data logging, just what I need. The funny thing about CircuitPython and Metro M4 is that CircuitPython uses a subset of Python language and is implemented on the board so you can do commands in a shell without compiling, but the Python interpreter is written in C so that the processor can run the interpreter quickly. So CircuitPython is actually C, just like regular Arduino is C, or C++.
CircuitPython is only about 3 years old.
ADS1115 can run at 3.3V (compatible with Metro M4 3.3V) or 5V. I don't know if ADS1115 is more accurate at 5V supply. There is a way to translate I2C between 3.3V and 5V using N-channel MOSFET, that may be useful.
June 5 2021 After 9 or 11 years of wanting to record months of 1/f data, using a chain of DC-coupled amplifiers to get overall gain of 300,000, I have enough equipment together this week to do the recording for five hours and FFT the data. I still have to extend Python code to store data off to SD card, with DAC offset adjusting every couple of hours, and temperature of the first stage.
The upper data above is 512 samples of 1/f noise, amplified about 300,000, from an LSK489 monolithic dual n-ch JFET, hooked up as a simple diff amp with a high quality 4.6mA current source on sources, and also the 1/f noise from an old, carbon-composition 22k resistor grounding one gate. One data point was taken every 32s, and there is a lot of averaging going on.
The JFET diff amp has gain about 17, and the rest of the 300,000 gain is from two TI INA163 $6 instrumentation amplifiers, the first at gain of 30 and the second at gain of 223. (On both INA163 outputs, there are NE5534 low-noise op amps providing inversions to make for balanced outputs from the INA163s.)
The lower chart applies a ramp to the upper data, so that the ending data point equals the beginning data point. This is required so that the FFT will regard this data as exactly one cycle of a periodic waveform. If I didn't apply the ramp before doing FFT, there would be a step (value about 750) from the end of the cycle to the beginning of the next cycle, and that distorts the frequency analysis.
The chart above is the result of passing the 512 data points, in a text file, through https://scistatcalc.blogspot.com/2013/12/fft-calculator.html. The web site replies with the FFT in less than a second! Be careful that there are no blank lines in the text file. The horizontal scale is bins of frequencies. It is a spectrum analysis. The output from the FFT has been plotted with a log vertical axis, but OpenOffice calc doesn't offer a log conversion for the freq scale. So generate a column on the spreadsheet that is a log, and do the following chart.
This shows a really nice, straight line, but it isn't 1/f, it is about 40% off of being 1/f. But when I look at Internet about 1/f noise, it looks like the 1/f is when you square the data to make a power series or whatever they call it, so the jury is still out about it. But the flatness (straightness) of just 512 data points is impressive. 1/f noise is supposed to keep getting stronger as frequency drops (as you collect data for longer periods, like months). 1/f noise is often the reason that long-term measurements "drift." It isn't drift, it is 1/f noise. :^)
Here is a quick review of the hardware behind this noise measurement. The LSK489 dual JFET in SOIC package is heat sinked and is on a PCB that also has the first instrumentation amplifier and a x20 amplifier for an LM35 temperature sensor. This PCB is in a Hammond die-cast aluminum box. Attached to the Hammond box is a Bud aluminum box with a lot of supply filtering, done in a manner to filter out RF noise that otherwise might be rectified by junctions in the amplifiers and show up as audio or video interference. The supplies for the first and second stages are mainly +-15.000V. +-5.000V also go into the Hammond box.
System power is from a 16V SMPS "tabletop" supply from MPJA.com. The 16V is series passed to make 12.49V with a lot of stability, but it is zener regulated and not all that stable. But the zener is in a little oven.
The precision regulation for +-15.000V, 9.100V, and 18.000V (the latter two for DAC) is in a DIY high-frequency supply with a little transformer with four output windings. This is in a foil shield, where there is also a separate PCB with rectifiers and low-ESR aluminum electrolytic capacitors. The rectified and smoothed DC outputs go through a lot of inductive choking, emerge from the shield, and go to a PCB that has three series regulators. Each of these series regulators is actually a stack of two series regulators, the first to get "line" voltage within 2V of the desired output, and the second to be the precision voltage output. Reference is 5.000V from MAX 6350, an $11 buried-zener IC with great temperature stability.
Another assembly is from March 2021. It is the "3.300V Supply" that I thought was needed for ADS1115 Vdd supply, before I found that ADS1115 ADC does have a reference built in. But the whole "3.300V Supply" has a lot more in it. If the ADSD1115, connected to R Pi with I2C, threatens to damage the R Pi if R Pi is not powered on, the "3.300V Supply" reduces the 3.3V Vdd for ADS1115. There is a MAX 6350 in an oven on the "3.300V Supply," and the oven also serves to stabilize a utility INA163 with gain of 223. An inverter op amp provides -5.000V. Not in the oven but on the assembly is a PCB with clamps for the signal going to ADS1115, clamping just outside the 0V to 2.048V range of ADS1115. An Arduino Nano Every beeps a beeper if clamping is happening. There is a series regulator for 5.3V for R Pi and 7" HDMI display, and a little buck regulator to take power off the series regulator. There is also an inverting op amp to create a balancing input to the ADS1115. The ovenized PCB also has a zener reference to compare to the MAX 6350. The "3.300V Supply" has signal connections: four binding posts, eight solder lugs, and a 14-screw barrier strip.
A 13-bit DAC, a DIY model built in 2014, is used with another Nano Every to monitor noise voltage going toward ADS1115 and, if the voltage is getting too near 0V or 2.048V, which is expected to happen with 1/f noise, kick in an offset to re-center the ADS1115 input toward midway, which is 1.024V. The DAC is not real precise, and ADS1115 may measure its output and record the offset among the 1/f data.
The ADS1115 is located 5" from R Pi, making for low capacitance on the I2C wires.
This is the bulk of the circuits that get 1/f noise amplified and measured.
What I have found is that the diff amps that amplify 1/f noise have great temperature stability. It also helps that I have placed the Hammond-boxed first-second stages in an ice chest (without ice) and surrounded the Hammond box with bottles and pouches of water. This slows down any ambient temperature change, which will be needed during the summer cooling season, when the front bedroom will be chilled by the A/C. The plan is actually to substitute a larger ice chest, provide a heater, fan, and controller, and make an oven around the Hammond-water assembly.
Another item intended for 1/f noise measuring is a 6-pole, 4Hz-cutoff, low-pass filter for use with the 1/f noise going toward ADS1115. Sampling by ADS1115 is to be at 25S/s, and I have a precision clock and logic circuit ready to operate a S/H IC that will give a nice, stable voltage for ADS1115. The logic also will monitor whether R Pi misses any samples, and R Pi will record the fact of any misses.
There is so much stability in the cascaded amplifiers that the DAC puts up an offset to center the noise in the ADS1115 range, then that offset is good for hours or days. I had expected that a degree C of temperature change would send the amplified noise signal on a wild tangent, but that is not happening. Differential amplifiers are so good.
Here is a puzzle. It takes me a great amount of circuitry to measure 1/f noise. And yet semiconductor manufacturers routinely measure or sample 1/f noise on their low-noise ICs and put specs on the data sheets. Typical measurement frequency is 10Hz (LSK489), 100Hz (INA163) and 30Hz (NE5534). Are they saddled with a complex tester, or do they have compact, simple 1/f testers? I don't find a 1/f noise test set for sale on Internet. Do they control temperature to keep tempco from masquerading as noise? How do the manufacturers measure 1/f noise?
I found a web site that seemed to say that 1/f noise testing is done on ICs using AC coupling. This surely could be done for noise as low as 10Hz or even 1Hz. I imagine the test-set gain would be comparable to what I use, 300,000 to 500,000. My interest is not measuring 1/f noise at 10Hz. I want to measure at 1uHz and 0.1uHz, and see that the strength of the 1/f noise keeps getting stronger at lower frequency. So I use DC-coupled amplifiers, and that is much harder than using AC coupling.
Another web site studied how tempco influences 1/f noise measurement. The study applied a step change of temperature to the IC, and the signal did the expected asymptotic approach to a new level. FFT, blindly applied to this, showed increased 1/f-appearing "noise." Maybe 1/f noise sampling in high-volume IC manufacturing lets the IC under test stabilize its temperature for 20s.
As I am doing various measurements with R Pi (ADS1115, 16 bit) and Arduino (10 bit), I see that 16-bit resolution isn't needed to see 1/f noise. I assumed 16 bits would be needed, and I assumed that 1/f noise would be hard to find amid changing temperature. It turns out that diff amps combined with temperature stabilization with bulk water control tempco quite well. I also assumed that FFT would be tricky to carry out and would be needed at a million data points, whereas I find scistatcalc...html is free and 512 data points works fine. (But to get a frequency range down to microhertz, it would be nice to FFT on 10,000 data points.)
If I redesigned my equipment for compactness, how much would it simplify? It would get a lot simpler, and commercial, precision supplies would be the thing to use. A compact 1/f tester wouldn't have the three-foot cables I am using. Data collection would be through a PCI adapter in a desktop computer, or a USB measuring device such as Advantech for $692, or Measurement Computing for $1500.
Aug 3 2021 The 1/f noise-measuring project is coming along pretty well, I have taken data sets of 512 points over some hours and it seems to show FFT that is reasonable. The next major step is R Pi Python coding and save-to-SD card.
I have needed 4.5 digits of voltage measuring during the last three months. The mpja.com $13 4.5-digit, positive-only DPM is quite useful. To improve on it, I built an absolute-value circuit. But it is not usable in the range -0V to -40mV. I think I know why, and I have designed an elaborate amplifier and absolute-value-using-chopper-op-amps that will give good performance for much less than the $300 to $400 of a commercial DMM with 4.5 digits. But it will take months to build.
In the meantime, I should code R Pi to take longer-term 1/f data, and let that chug along, accumulating data and finding whether the data is really nonstop, while I am working on the 4.5-digit voltmeter, and a precision current source of 0.3uA to 20mA so that resistance can be measured.
Putting numbers to thin film low noise resistors
Larger atoms in sputtered thin-film resistors are .25nm diameter. Thin-film resistor might have 1u resistive layer. Of that, maybe 25% is conductive, rest is oxide, nitride, etc.
.25e-6/.25e-9=1000 atom thick conductor in thin-film resistor, more or less.
Wire wound resistor might use #34 gauge, .16mm diam. .16e-3/.25nm = 640,000 atoms diam.
Ratio is 640. No wonder wirewound resistor is lower noise. (No excess noise).
Reading about metal resistivity, alloy scattering comes up. Wave nature of electrons helps one believe alloy scattering.
FFT
Reading about fft, I don't see samples beyond 2^14. Log(16384) is only 4.2 decades. Should think about old-style integration method of Fourier analysis, which surely should work on large set of acquisitions. Is double precision enough to go to 100,000 acquisitions? C++ double is 15 digits. 420,000,000 is 9 digits. One would expect that double floats would work fine.
100,000 acquisitions would be supported by 16 bit ADC with some additional averaging. But the most interesting numbers coming out of a Fourier analysis are the lowest harmonics and highest harmonics, the ones you pay attention to as you lay a straightedge to as you look for a straight line on log-log plot. I have a feeling that the lowest and highest harmonics are the ones subject to error during Fourier spectrum analysis.
If I collect 27 acquisitions per second for 6 months, that is 420MSample, 840MByte. 8.6 decades. Surely I can concatenate spectrum analyses with varying averages to build up 8.6 decades. There are bound to be features useful as markers to help line up different spans of freq (different quantities of averaging), lining up both freq and voltage.
Aug 14: I am actually thinking about doing Fourier Transform without FFT, just do the integrations that I did when I was at TSTC about 1999. I think that would work over 50,000 samples, given time on a tower PC. Not every harmonic would have to be checked, concentrate on lowest and highest harmonics.
I am refining R Pi Python, Aug6_21_1_fToFile_v3.py, to go to 65,536 acquisitions with sleep 36ms to simulate 27S/s. It runs 50 minutes and writes a file of 377kB. The file gets written to SD card in 5.6ms. Each acquisition takes 9.52ms, including append to string list. I think 9.52+5.6ms=15.1ms is comfortably within 1/27Hz= 37ms acquisition rate so that the once-every-50-minutes save-to-SD card would not interfere with 27S/s.
It is time to add code to pay attention to the 27S/s handshaking from the logic card, and do the other R Pi tasks I have already wired to various hardware modules, and get DAC offsetting working with R Pi. Later, doing the oven around 1st-2nd stage with the existing water pack can be done.
I did oscilloscope recording at 4s/div of power-on transient at the +in of ADS1115, which includes effect of 4Hz LPF. In only 8 seconds, 1/f data is seen. As soon as a transient from LPF is over, at 8s, 1/f data is seen and there is no thermal transient visible at 0.5V/div! Again, I see the goodness of 100% differential amplifier stages. The LSK489 monolithic JFET N-channel pair by Linear Integrated Systems as the first stage, combined with precision supplies and long-tail-pair current source based on MAX 6350 5.000V reference, are doing an amazing job.
Aug 28 2021 Above and below images are Python using Tkinter (ToolKit INTERface), the popular Python GUI toolkit. I am guided by Geeks for Geeks web site to make bar chart above to see 32000 1/f-noise acquisitions, whereas OpenOffice spreadsheet is choking on just 1000 acquisitions as a chart. The chart above shows nicely the low frequencies in the 1/f noise. Also prominent are the sharp spikes. Zoom on some spikes in the image below.
# C:\Users\User\Documents\Aug14_11_58am.txt has abt 30k samples with ramp applied
# file tkinteraug27v6 better zoom.py on Lenovo laptop
# 1366x768 display resolution
# reads a file and draws lines according to data v6 is connecting dots, not bar chart.
# web site Geeks for Geeks create-different-type-of-lines-using-canvas-class
# Zooming is working. Still needs mod to accept different # of samples,
# and color coding to indicate max, min, avg when multiple acquisitions are shown at one time.
# (like 32000 acquisitions shown by 1200 hor units, each dot represents 27 acquisitions)
import time, math
from tkinter import *
from tkinter.ttk import *
f1 = open('C:\\Users\\User\\Documents\\Aug14_11_58am_no_header.txt') # double \\ is needed, or raw
# no_header means file is only integers, no text identifying what and when
# for l1 in f1:
# print(l1)
time.sleep(2)
class GFG: #GFG is Geeks for Geeks, the web-site source
def __init__(self, master = None):
self.master = master
self.create()
def create(self):
self.canvas = Canvas(self.master)
o=530; s1=o #o means origin, vertically
line_count=-1
zoom=100.0 ; h_offset=.455 #slightly neg h_offset shows start of data
#zoom 0.9 is underfit
for i in f1:
line_count+=1
if int(i)>-5000 and int(i)<5000: # in case there is some spurious data
if line_count%20==0:
print(int(i)) #hand holding
s1_old=s1
s1= int(int(i)*1800.0/16000)+o #vert
s2= int((-zoom+1.0)*h_offset*1200)+int(line_count*zoom/28.0) #hor at -9.0*1200)+ is the end of data
# .50*1200)+ is the start of data
# Zoom variables are zoom and h_offset. No zoom is 1.0. 10x zoom is 10.0.
# h_offset is 0 to 1.0
self.canvas.create_line(s2,s1,s2,s1_old) # x1,y1, x2,y2
self.canvas.pack(fill = BOTH, expand=True) #p. 399 in Python Without Fear Barnes and Noble edition
print('File is closed')
if __name__ == "__main__":
master = Tk()
geeks=GFG(master)
master.title("Lines from Geeks for Geeks different types of lines 1/f Data JE Aug 27'21 vert: voltage
hor: 10x zoom of 28 acq per hor unit@27 S/s, 4Hz LPF Python 3 Thonny 29 lines of code")
master.geometry('1200x650+50+10') # don't put spaces in this string! desired horXvert chart size, xOffset, yOffset
f1.close()
master.mainloop()
To see some of the sharp spikes in the image above, I added zooming in the Python code. It is surprising that 1/f noise has these spikes, and a cluster of them. But I am zooming in on little areas of the 32000 acquisitions, and statistics says that unusual things should crop up.
When I try Fourier frequency analysis using the old integration method (or if FFT works out), I will need this high-resolution charting to see months of data and millions of acquisitions. I had figured that a Linux software package would be needed to see giant data sets, but plain Python, with Tkinter, may do the job.
Dec 23, 2021 Topic: recording megabytes of data to R Pi SD card, for 1/f noise recording
An hour of 7.5-digit-on-average (including commas) data at 27.5S/s rate is 742,500 bytes. To get this to SD card, I looked at what is easy to do with Python and came up with this scheme: make one long string at a time with the data being separated by commas, for 10 minutes at a time or until there is a DAC change to recenter the amplifier output. Calculate MD5 checksum. Tack checksum on the end of data. Pickle and dump to SD card.
Code to try this out on Lenovo ThinkPad Win10 using random-number data:
# checksum200000V2.py JE 12-22-2021 go ahead from generating MD5 to actually pickling and write to file
import hashlib, random, time, pickle, os
# I wonder what happens if I pickle first, then do checksum
#On reflection, make all data one long string with comma separators, get MD5, tack that on end,
# pickle it and write. Amount of data per hour: if data is like '-15000,' from ADS1115,
# 27.5*7 bytes*3600 = 693kB per hour. I have done this test program with 200kB on Lenovo laptop.
print ( 'time in seconds before generating long string ',time.time())
a = ''
aqty = 200000
for i in range(0,aqty):
if random.random()>.5:
inegOrNot='-'
else:
inegOrNot=''
anext=''
for j in range(0,5):
anext = "".join([anext, random.choice('123456789')])
anext = "".join([inegOrNot,anext]) # do this without string+string concatenation
a = ",".join([ a , anext ])
a = a[1:] #remove initial comma
print ( 'time in seconds after generating long string ',time.time())
if aqty<101:
print ( 'string with ',aqty,' items ',a )
#from line 20 to here, it just generates random numbers to test with
theMD5 = hashlib.md5(a.encode('utf-8')) #pythonpool.com/python-md5
#print( theMD5, type(theMD5)) # example 2
print ( 'time in seconds after generating checksum ',time.time())
print( 'checksum (hexdigest) for ',aqty,'numbers in string ',theMD5.hexdigest(), type(theMD5.hexdigest()))
aplusChecksum = a + ',' + theMD5.hexdigest()
print( 'kkk ',aplusChecksum, type(aplusChecksum) )
# if I pickle this and write to file, then with another program I read it, unpickle,
# remove the checksum at end, and get the MD5 for the read-back string, should get same MD5.
os.chdir(r'C:\Users\User\Documents\pickled_Python_data')
fileName = 'pic200000.bin' # works with .bin, not .obj
# thoughtco.com/using-pickle-to-save-objects-2813661
file_1 = open( fileName,'wb') #write binary Remember, file_1 is a writable object
pickle.dump(aplusChecksum,file_1) # Python object is converted to a byte stream & written to disk file
file_1.close() # the writable object has a close method
# now try reading back and unpickle with code check_unpickleV2.py
print('some data ',a[30000:30300])
The read-back code:
# check_unpickleV2.py
# for use after running checksum200000V2.py
import hashlib, random, time, pickle, os
os.chdir(r'C:\Users\User\Documents\pickled_Python_data')
fileName = 'pic200000.bin'
readData = open(fileName,'rb')
aa = pickle.load(readData)
readData.close()
if len(aa)<800:
print(aa)
# it works, the plain-text string reappears and has the MD5 checksum at end
MD5hexDigest = aa[len(aa)-32:]
print(MD5hexDigest)
aa=aa[:len(aa)-33]
if len(aa)<800:
print(aa)
theMD5 = hashlib.md5(aa.encode('utf-8'))
print(theMD5.hexdigest())
if theMD5.hexdigest() == MD5hexDigest:
print( 'Checksum works :^)')
print('some data ',aa[30000:30300])
Thonny Shell
>>> %Run checksum200000V2.py which includes writing pickled file to drive
73
<md5 HASH object @ 0x036C9260> <class '_hashlib.HASH'>
0d8a05a8bf744f73d9784e715a1e9076 <class 'str'>
yes, the same hexdigest is being found even though theMD5 hash object differs!
Above: practice with a little data
Below: 200,000 random, 5-digit integers
time in seconds before generating long string 1640278271.6753738
time in seconds after generating long string 1640278352.5165524
time in seconds after generating checksum 1640278352.5165524
checksum (hexdigest) for 200000 numbers in string
1d4b4b095d4c344207e8c4478c600abf <class 'str'>
kkk <class 'str'>
some data ,39454,54241,58663,-16775,22989,19283,48284,-19798,35878,-37574,66889,-65989,-85441,-41372,85687,16981,-22512,45771,-55386,-56972,98256,-68184,88896,56274,54849,47739,-39234,93733,-97477,-47661,-26537,-34499,-77133,-49633,-43327,-65914,35873,-82719,-58144,-41441,75228,-43375,-38734,-16775,-57714,-12
>>> %Run check_unpickleV2.py
1d4b4b095d4c344207e8c4478c600abf
1d4b4b095d4c344207e8c4478c600abf
Checksum works :^)
some data ,39454,54241,58663,-16775,22989,19283,48284,-19798,35878,-37574,66889,-65989,-85441,-41372,85687,16981,-22512,45771,-55386,-56972,98256,-68184,88896,56274,54849,47739,-39234,93733,-97477,-47661,-26537,-34499,-77133,-49633,-43327,-65914,35873,-82719,-58144,-41441,75228,-43375,-38734,-16775,-57714,-12
Both the reconstructed checksum (hexdigest) and this little sampling of data are perfect.
From the folder where the pickled files are written to, here are the file sizes:
pic50.bin 1kB
pic100.bin 1kB
pic1000.bin 7kB
pic10000.bin 64kB
pic100000.bin 635kB
pic200000.bin 1270kB
Pickling does not compress, in fact, with random numbers, no compression is possible.
This is a major advance toward recording long stretches of 1/f data. I still need to code the DAC stepping to keep amplifier output from going out-of-bound, and I need to put an oven around first-second stages surrounded by water-bottle thermal inertia.
Jan 1 2022 Good progress on 1/f noise project, got oven working for first and second stages.
Both heater strings are seen, 6W total made from 1/4W resistors, and 5W resistors in copper heat spreaders. PVC pipes at bottom duct air from the fan at back (not seen) to the front, and it spreads out all over, guided by an overall box that is removed for this picture. TL494 PWM controller at right. Water bottles are loaded in the top box, ready to receive amplifier box. 130mL water pouches to be added after amplifier is inside.
2022 Feb 5 The 1/f noise oven for 1st-2nd stages doesn't have enough power, between 6W and 29W, to heat more than 5deg F, so I am working on a 65W heating pad controller using Arduino and a servomotor to operate the heat-select button.
2022 Feb 5 For C. H. before Girls Who Code, we took the project of the Nunchuk controlling a Processing (language-IDE) cube from Maik Schmidt's 1st edition Arduino A Quick Start Guide. This has been a lot of work and frustration. Progress is being made. Here is some of what happened. The book has code for both Arduino and Processing. The division isn't really obvious but I found a web site that warned about the split. The Arduino code has a .ino (.pde) file, a .cpp file, and a .h file. It seems that you put all these in the same directory (folder) and it works, but I am not sure about that. These three files are available at the pragprog web site for Schmidt's second edition, but the long code for the Processing cube isn't in the second edition. I scanned and OCRed the code and had to patch up a lot of errors (skip =, i becomes ; , 1 becomes lower-case L, () and 0 become O).
Installing Processing in either Ubuntu and Microsoft Windows is not straightforward, but I found a good web site guiding Ubuntu install. Processing is a big IDE and somehow does major graphics and interactive graphics without straining the processor. (16000 "hairs" in Examples Performance Esfera.) When I paste the Schmidt cube code into Processing, it shows the cube if an Arduino is connected by USB, even if the Arduino doesn't have the Arduino code for Nunchuk.
Nunchuk has had problems. We are doing the work during dry weather and I think static shocks are killing electronics. The Nunchuk I brought home won't show an I2C address when I run the I2C scanner code. That scanner code, from Internet, turns out to be vital to facilitate I2C device work, I first tried it yesterday and got a long-dormant 16x2 LCD display working on an Uno. But that work was delayed while I discovered that Arduino IDE's Tools, Manage Libraries is needed for .h files. Using this must be with on-line connection, and it seems to go to some web site and look for .h files. You must be careful to spell and punctuate correctly for the exact .h file you need. The manager seems to lock up for up to a minute, but give it time to respond. It looks like the .h file you install goes to the proper folder on your file system so you don't have to worry about the path. Usage of the manager is similar to installing additional Arduino boards such as Nano Every, through Tools, Board, Board Manager.
Back to Nunchuk. The I2C scanner program is important, as I said. We hope the second Nunchuk works today to make the cube spin in Processing. I need to order more Nunchuks and 16x2 or 16x4 or 20x4 LCD displays. It is now the proper time to order some I2C Adafruit devices: hub that allows same-address devices to be addressed, and 3.3V-5V MOSFET interface circuit.
Ten days of working on the Nunchuk and cube in Processing has seen a lot of learning, but it shows how frustrating it is when you don't have a mentor. Read the next paragraph to see how it turned out.
2022 Jan 29 A short project with C. H. to get an exotic, graphics cube in Processing language, shown on a laptop or tower computer, to respond to a Wii Nunchuk's accelerometers as received via I2C by Arduino. We know this can work because of chapter 7 of Maik Schmidt's first edition of Arduino A Quick Start Guide. Schmidt gives all the code that is needed, and it is a lot. The Arduino code is downloadable from pragprog, https://pragprog.com/titles/msard2/arduino-a-quick-start-guide-second-edition/ where it is for the second edition, but we don't recognize the Programming-language graphics cube code on the web site. But C. H. got the Serial Monitor of Arduino to show full Nunchuk function, so we had hope that the cube could be added.
Instead of typing in so much cube code, I tried scanning on my HP scanner and using the OCR-to-Wordpad feature. This worked in the main but had some defects: some i became ;, some 1 became lower-case l, some () became O, some 0 became O, some = were ignored, and some sections of xxx = yyy had the yyy part moved down onto separate lines as if the OCR was trying to columnize them. So I did a lot of work to patch those errors, and some of it waited for Processing to flag problems with wavy red lines.
At Room C2 at Calvary Hills Baptist, C. H. and I had gotten the Arduino part working on C.'s Linux computer, and saw three tabs in the Arduino code, one each for .ino, .h, and .cpp. The Arduino program didn't persist for a whole week, though (computer turned off?), and we couldn't get the three tabs back in a usable way. See above for using the Arduino Library Manager.
While I was finishing the Arduino work on Thursday, I found odd and messy waveforms coming from Nunchuk, as seen by plotter of Arduino IDE. It looks like the y axis is seeing 1g of gravity and the other two axes are seeing 1/2g and 0g. (Offsets when the nunchuk is at rest.) I wanted to see if leaning the nunchuk over 90 degrees would shift the three lines of plot, which would help make sense of the accelerometer data. (Yes, it did.) That has to wait on getting the Arduino files back to working together. The Arduino code does a lot of averaging and it surely is needed. I calculated a peak data rate of nunchuk data, 2kSamples/sec, assuming the basic I2C rate of 100kb/s. 2kSamples/sec would certainly let averaging happen.
Yet another problem at Room C2 was Processing. Schmidt's first edition didn't emphasize enough which code needed to run in Processing, and I found a web site that provided that emphasis. So we understood that Processing needed to be downloaded and installed. I led that effort, and we actually saw the Processing IDE once, but then couldn't get it to reappear once we closed the window. I had to practice at home for Processing, and found Jim Plaxco's excellent http://www.artsnova.com/processing/Installing-Processing-on-Ubuntu-LTS-Focal-Fossa.html to be a fine guide. Plaxco, an artist, went so far as creating an icon for the favorites bar in Ubuntu 20.04LTS. That worked (at my home Linux computer) when I made a 64x64-pixel .png of the Processing logo, screen-captured from the web site. Plaxco sent me through some Ubuntu terminal that I hadn't done so far, and C. H. was completely new to Linux terminal, so all the Processing setup has been a challenge and needs finish up in Room C2. I find that Processing's example images include dynamic graphics (mouse movable) that is quite impressive (dense) and very fast.
I copied my OCRed cube code into Processing and found more OCR errors, then it ran up to the point of looking for an Arduino USB connection, and balked. But I think it will work when we try it in Room C2. I found the current version of Processing, ver 3, to not accept global variables for WIDTH and HEIGHT, so I put 500 constants in for those. On Feb 8, I was able to get a non-schocked Nunchuk to work through Arduino Uno's I2C, then through USB, into my Lenovo laptop, and the cube tumbled in response to Nunchuk. Run the Arduino code first, than get the Processing started.
The Schmidt cube-nunchuk work has been challenging. But that is normal in computer work. If you don't have the patience and resilience to plunge through difficulty, you aren't going to get through the problems and see amazing results.
Continuing the idea from the previous paragraph, here is a list of what we overcame to get the cube to rotate.
I bought the first edition of Schmidt's Arduino A Quick Start Guide, which has the cube code for the Processing language. (I suspect the cube code was deleted from the second edition because it is hard to get it working, and you have to have the right version of Processing, and Maik probably got a lot of e-mail complaining that the code wasn't working, and he just dropped the cube from second edition.)
C.H. was willing to type in some of the Arduino code, to kick off our joint project.
I found the rest of the Arduino code on the pragprog.com web site.
I picked up on Maik's enthusiasm for Nunchuk, and ordered two Nunchuks, three years ago, and made a little printed circuit board to connect to the connector. This is the Maker influence that enables a lot of Arduino and Raspberry Pi work. C.H. soldered four wires. Maik warned to use Nunchuk on 3.3V, not 5V, and we have carefully observed that.
I had experience with I2C, knew about I2C addressing, and recognized the Uno pins for SCL and SDA. This is a significant point; Uno has a lot of pins!
C.H. happened upon the right conditions for the three Arduino files, .ino, .h, and .cpp. Data came across Arduino and USB and showed up in Serial Monitor. This was the success that helped us push through more challenges.
I came across a blog on a web site that explained that the Processing IDE had to be installed for the cube.
We got Processing installed on an Ubuntu computer, the one that C.H. is using. We overcame the struggle to get Processing running, by me using a Microsoft Windows laptop and a home Ubuntu computer for two more installations, using detailed instructions discovered on Internet.
We recognized body static, on cold winter days, was killing some of our electronics (one of the Nunchuks, and threatening Arduinos), and we used discharge methods to protect the replacement parts. And we had those replacement parts. We used neon lamps to prove the static threat and give us a concrete sense of static.
When the first Nunchuk was shocked (other people used the room at CHBC and probably handled the Nunchuk and shocked it to death), I had an I2C 16x2 LCD display to try out, to prove to myself that I2C was going to work with Uno. I found the need to install an appropriate .h file using Arduio IDE's library manager. I knew of I2C scanner code to reveal I2C address of the 16x2 display, and decided that the lack of address for Nunchuk meant it was dead.
I used my big HP scanner to scan and OCR the long Processing code for the cube out of Maik's first edition, and found ways to overcome the character-recognition errors that come through OCR. (Key was Processing's generous IDE help that suggests cures for problems. It told me to replace HEIGHT and WIDTH with constants.)
I had to recognize that the Arduino code must be operating before Processing is started, and you can't have Arduino Serial Monitor or Serial Plotter working when Processing is started.
But once the Nunchuk Arduino code gets compiled and uploaded to any particular Arduino, and you don't replace the Nunchuk code with anything else, the Arduino code is operating, 2/3 second after Arduino is powered on. The practical effect is that you attach Arduino to the computer (Microsoft Windows or Ubuntu, whatever has Processing installed) by USB, with computer power on, the Arduino code is running on the Arduino microcontroller, then you start up Processing, open the sketch for the cube, and it should look for the Arduino data coming from Nunchuk. I have done this several times and it works. Another aspect is that, for the cube to work on another computer, just get Processing working on the other computer (not an easy job), and you move the Arduino to that computer and restart the cube code in Processing.
Accelerometers give two types of data. 1) Just sitting still, the three axes of the accelerometer are experiencing gravity, and that causes voltage to be on the three channels. (I had to find a web site that explained this. Totally unexpected.) If you tilt the Nunchuk while looking at Arduino Plotter, you can see the three channels rise and fall. But you have to ignore the messy data-overflow nature of the data. 2) When you move the Nunchuk without tilting, with motion of two feet at 0.5 Hz, in other words translate the Nunchuk, you can see force on the order of 0.2g in the Arduino Plotter. Again, you have to ignore spasms of messy data. And it helps to visualize where the accelerometer I.C. is on the little PCB inside the Nunchuk. The cube rotates by the #1 signal, not the #2 signal. Maik's Processing code filters out high frequencies.
The Maik Schmidt Processing cube rotated by Nunchuk operating by I2C through Arduino Uno. The white vertex of the cube is pointed more or less to the viewer. The black vertex is hidden. Three faces are seen: wht-red, wht-grn, and wht-blue.
Arduino Plotter showing confusion of the Nunchuk data. Joysticks at bottom are easy enough to interpret; the Nunchuks I received have terrible joystick behavior. The 3 axes of accelerometer are seen in purple, blue, and brown. If you move the Nunchuk at 1/2 ft per second, you can see some acceleration. But the biggest effect is just to let it be still and slowly spin the Nunchuk around its three axes; acceleration of gravity causes the three voltages to change order, up and down. But there is a lot of being-near-limit-and-going-full-scale-to-opposite-limit. Nevertheless, the cube is controllable.
Nunchuk translations, attempting to do one axis at a time. The old, very poor Nunchuk is white, the new is black.
Nunchuk rotations, it is hard to move the Nunchuk for one axis of rotation at a time, and I missed one of the axes.
The new Nunchuk is good enough to pick up neck heartbeat
Processing language has examples. This is the performance category, and the code is named Esfera. Moving the mouse makes this hair ball rotate and the hairs move in a very nice manner. This is 16000 hairs! The screen is updated often enough that it isn't choppy. There is a lot of computing going on! Even so, the fan in the laptop is not going fast.
#JE Feb 2022 second try at a text game gameFeb2022v12.py
#When used in Girls Who Code, value is to show what Python can do, show that text game is hard to do, demo set, list, iterate thru chest, boolean, demo ease of user controls, so many versions to get function
# ver1 has give_away but does not filter out incorrent give input, ver2 brings in pick
# global/local trouble, go to ver3
# Var inside fct goesn't need global if not reassigning
# Var inside fct muct be declared global if reassigning it and the value needs to apply globally
# Ver3 [counting weight by removing items from copy of chest] is removing items from chest, not just the copy.
# Iterate thru chest, it works and is better.
# Ver3 is working pretty well Feb 15 including eating and energy deduction when moving forward or back
# to work toward an end-of-game goal, pop a gem in after 23 moves. But isn't working, go to ver5.
# Ver5 is working pretty well, doesn't have geography yet.
# Ver6 adds more food warnings.
# Ver7 adds some geography. Ver8 extends route from 8 to 15 states.
# Ver9 attempts to put in a wolf. Thoughts: doesn't require pick or give. Sound of wolf from
# distance. Player may move toward cave, tell direction (f,b) and distance. Do wolf randomly,
# only when player may reach cave, and wolf disappears randomly.
# Ver9 has wolf working halfway. Ver11 tries to go further and does get wolf working.
# Ver 12 pretties it up.
#for early versions, concentrate on state machine, assign geographic tags later
#items in your chest are in a list, chest[], because list may be appended and removed from, .remove(item), one item at a time
#each stop may have an action that can be accomplished, like look in hollow tree, look under bridge,
# pick up gem, buy an item with coins, go forward, go back. Action can have a state number.
#Initially, make no forks in the road, just go in a fixed loop but either way.
#Build in stones to build a bridge over a stream; rope to swing over stream, coins to buy food.
#dictionary translates single keyboard key to a text message.
#Score could be function of items in your chest (more is better) and number of stops (less is better).
import time, random
chest = ['coin', 'coin', 'coin', 'coin', 'rope', 'rope', 'food'] #beginning supplies
# must be coordinated with the code section, to let action be give_away, ac=='g':
energy = 120
# the iterable "dictionary" is handy to translate code to plain language
action = { 'l':'look around', 'p':'pick up', 'g':'give away', 'e':'eat', 'f':'forward', 'b':'back' }
numStops = 15 # the main places you go to. Any extra actions are added state numbers like 11, 12.
mainStops = [0,10,20,30,40,50,60,70,80,90,100,110,120,130,140]
# make geographyAtStops descriptive, showy, creepy, exciting; your choice. No limit on length of strings.
geographyAtStops = {0:'You are in a clearing in the forest.',10:'You are in a rocky field.',
20:'You see a cave.',
30:'You stand beside an empty hut. Spiders are creeping about.',40:'You see ruins of an ancient building.',
50:'You are at the marketplace of a village. Here is an abandoned food cart.',
60:'You are on a mountain ridge. Everything below is hidden by fog.',
70:'You are at the edge of a pit in the ground. Animals have fallen in and died. Far ahead is a cave.',
80:'You are on the edge of a thicket. An animal is rustling, out of your sight. A cave is nearby, forward, along your path.',
90:'You are in a dank cave. You smell that there are bats. No wolf will follow you here.',
100:'A cave is back along your path. Ahead is a dark stand of pine trees.',
110:'In the distance, backward on the path, you remember there is a cave.',
120:'A rainbow is overhead.',130:'A unicorn runs across the path. Is it fleeing a wolf?',
140:"The fumarole is steaming a lot today. Wolves don't like the stinky steam."}
pickMenu = {0:'nothing',10:'stone',20:'gem',30:'nothing',40:'stone',50:'food',60:'nothing',70:'stone',80:'nothing',90:'nothing',
100:'food',110:'gem',120:'food',130:'nothing',140:'nothing'} #change the items freely
# make the items of chest and pickMenu start with letters that don't repeat; not coin and cabbage
#NOTE coordinate mainStops, geographyAtStops, and pickMenu
state=0; #state is the location or stop, like 0, 30, or 130
loopCount=0; extraGemPlaced = False; generalDelay= .6; wolfIsThere= False
#User controls: wolfPrintAssist, wolfOn
wolfPersistToLoopCount=8; wolfPrintAssist = False; wolfOn=True #***************************
#-------------------start of user defined functions
def chest_print(chest, state): #this is a user-defined function
#print('Location',state,' Your treasure chest weighs ',end="") # end="" keeps the print on the same line
chest_weight=0
for i in chest:
if 'rope' in i:
chest_weight += 2
if 'stone' in i:
chest_weight += 11
if 'food' in i:
chest_weight += 1
print(chest_weight,'pounds, ',end="")
for i in chest:
print(i,'',end="")
print(' ') # let a new line happen in shell
return chest_weight #call this function to print the chest, if you don't assign chest_weight to a var that is OK
def key():
print("Key: f forward b back l look p pick_up g give_away e eat_from_chest")
def detectFood(chest):
isFood=False
for i in chest:
if i=='food':
isFood = True
return isFood # there is at least one item of food in chest
#-------------------end of user defined functions
print("Your chest weighs",chest_print(chest,state),'pounds')
ac='q' #q is a default condition to do nothing special, the states set ac to q to prevent repeated triggers
while(True): #this is a big loop
gemCount=0
for i in chest:
if i=='gem':
gemCount += 1
if gemCount > 1:
print('\n-------------There are two gems in your treasure chest.')
time.sleep(1)
print('You have won the game with energy remaining:',energy)
time.sleep(1); print('\a');quit()
loopCount += 1
if loopCount>19 and not extraGemPlaced and pickMenu[state]=='nothing':
pickMenu[state]='gem' #dictionary may be modified pop in an extra gem, at a place that initially had no gem
extraGemPlaced = True
if wolfPersistToLoopCount<loopCount: #wolf is complicated, 33 lines!
wolfIsThere = False
if wolfOn and state>65 and state<115 and wolfPersistToLoopCount<loopCount: #you are in wolf territory
if loopCount % 7 == 0 and wolfIsThere == False: #sort of random
wolfIsThere = True
wolfPersistToLoopCount = loopCount+random.randrange(4,8)
if loopCount % 2 ==0:
wolfState = 50 #behind
else:
wolfState = 130 #ahead
time.sleep(.4)
if wolfPrintAssist:
print('\a\nWARNING You hear a wolf howl! Wolf at state ',wolfState,loopCount)
else:
print('\a\nWARNING You hear a wolf howl!')
if wolfPrintAssist:
print('wolfIsThere=',wolfIsThere)
#wolf location should home in toward player state.
if wolfIsThere:
if wolfState<state:
wolfState += 10
else:
wolfState -= 10
if wolfPrintAssist:
print('state,wolfState ',state,wolfState )
if wolfState == state and state != 90:
print('\a The wolf caught up with you and ate you.')
print('Game over.')
quit()
if wolfState == state and state == 90 and wolfIsThere:
print(' You can hear the wolf panting. Do not move out of the cave. Just look. You may eat if you have food in your chest.')
if wolfState-state==10 or state-wolfState ==10:
print(' You can hear the wolf creeping around, smelling you.')
while(ac not in 'lpgefb'): #if user types in a wrong character
key()
ac = input( 'l,p,g,e,f,b ENTER ') #opportunity to type in correct character
# the loop hangs here until user types in an action
if ac=='f':
state += 10
if state> (numStops-1)*10:
state=0
time.sleep(.3); energy -= 4 + chest_print(chest,state)/2
if geographyAtStops[state] != 'nothing':
print('\n',geographyAtStops[state],' You see',pickMenu[state],'\b.')
else:
print('You are at',state,'WHERE YOU SEE',pickMenu[state],'\b.')
ac='q'
if ac=='b':
state -= 10
if state< 0:
state=numStops*10-10
time.sleep(.3); energy -= 4 + chest_print(chest,state)/2
if geographyAtStops[state] != 'nothing':
print('\n',geographyAtStops[state],' You see',pickMenu[state],'\b.')
else:
print('You are at',state,'WHERE YOU SEE',pickMenu[state],'\b.')
ac='q'
if ac=='l': # lower-case L, not number one
time.sleep(.7)
energy -= 2
print('\nYour energy is',energy,' You can pick up',pickMenu[state],'\b.')
time.sleep(.7)
chest_print(chest, state)
ac='q'
if ac=='e':
if detectFood(chest): #uses the user-defined function
chest.remove('food')
time.sleep(generalDelay);print('\nChest has',len(chest),'items');chest_print(chest,state);time.sleep(generalDelay);
energy += 30
ac='q'
else:
print('\nThere is no food in your treasure chest. You need to find food along your path.')
ac='q'
if ac=='g':
time.sleep(generalDelay);print('\nChest has',len(chest),'items');chest_print(chest,state);time.sleep(generalDelay);
print('Give a grinch one of these by first letter ',set(chest))
ad=input()
if ad=='c':
chest.remove('coin')
if ad=='r':
chest.remove('rope')
if ad=='s':
chest.remove('stone')
if ad=='g':
chest.remove('gem')
if ad=='f':
chest.remove('food')
time.sleep(generalDelay);print('\nNow chest has',len(chest),'items');chest_print(chest,state);time.sleep(generalDelay)
ac='q'
if ac=='p':
# access dict using sq.brackets, not paren
chest.append(pickMenu[state]) #pick up whatever single item is there
while 'nothing' in chest:
chest.remove('nothing')
print('Your chest now has',len(chest),'items');chest_print(chest,state);time.sleep(generalDelay)
pickMenu[state]='nothing' #because you picked it up
ac='q'
if energy<0:
print('\nYou have EXPIRED from lack of energy!')
time.sleep(1)
quit()
if energy<40:
if detectFood(chest): #uses the user-defined function
print('------------Eat food from your chest.')
else:
print('You are near starving, you must find some food, put it in your chest, then eat it. If you are carrying stones, give them away.')
time.sleep(1.5)
#end of big loop------------------------
--------------------------------------------------------------------------------------
Shell
Python 3.7.9 (bundled)
>>> %Run gameFeb2022v12.py
5 pounds, coin coin coin coin rope rope food
Your chest weighs 5 pounds
Key: f forward b back l look p pick_up g give_away e eat_from_chest
l,p,g,e,f,b ENTER f
5 pounds, coin coin coin coin rope rope food
You are in a rocky field. You see stone.
Key: f forward b back l look p pick_up g give_away e eat_from_chest
l,p,g,e,f,b ENTER f
5 pounds, coin coin coin coin rope rope food
You see a cave. You see gem.
Key: f forward b back l look p pick_up g give_away e eat_from_chest
l,p,g,e,f,b ENTER f
5 pounds, coin coin coin coin rope rope food
You stand beside an empty hut. Spiders are creeping about. You see nothing.
Key: f forward b back l look p pick_up g give_away e eat_from_chest
l,p,g,e,f,b ENTER b
5 pounds, coin coin coin coin rope rope food
You see a cave. You see gem.
Key: f forward b back l look p pick_up g give_away e eat_from_chest
l,p,g,e,f,b ENTER p
Your chest now has 8 items
5 pounds, coin coin coin coin rope rope food gem
Key: f forward b back l look p pick_up g give_away e eat_from_chest
l,p,g,e,f,b ENTER f
5 pounds, coin coin coin coin rope rope food gem
You stand beside an empty hut. Spiders are creeping about. You see nothing.
Key: f forward b back l look p pick_up g give_away e eat_from_chest
l,p,g,e,f,b ENTER f
5 pounds, coin coin coin coin rope rope food gem
You see ruins of an ancient building. You see stone.
Key: f forward b back l look p pick_up g give_away e eat_from_chest
l,p,g,e,f,b ENTER f
5 pounds, coin coin coin coin rope rope food gem
You are at the marketplace of a village. Here is an abandoned food cart. You see food.
Key: f forward b back l look p pick_up g give_away e eat_from_chest
l,p,g,e,f,b ENTER p
Your chest now has 9 items
6 pounds, coin coin coin coin rope rope food gem food
Key: f forward b back l look p pick_up g give_away e eat_from_chest
l,p,g,e,f,b ENTER e
Chest has 8 items
5 pounds, coin coin coin coin rope rope gem food
Key: f forward b back l look p pick_up g give_away e eat_from_chest
l,p,g,e,f,b ENTER f
5 pounds, coin coin coin coin rope rope gem food
You are on a mountain ridge. Everything below is hidden by fog. You see nothing.
Key: f forward b back l look p pick_up g give_away e eat_from_chest
l,p,g,e,f,b ENTER f
5 pounds, coin coin coin coin rope rope gem food
You are at the edge of a pit in the ground. Animals have fallen in and died. Far ahead is a cave. You see stone.
Key: f forward b back l look p pick_up g give_away e eat_from_chest
l,p,g,e,f,b ENTER f
5 pounds, coin coin coin coin rope rope gem food
You are on the edge of a thicket. An animal is rustling, out of your sight. A cave is nearby, forward, along your path. You see nothing.
WARNING You hear a wolf howl!
Key: f forward b back l look p pick_up g give_away e eat_from_chest
l,p,g,e,f,b ENTER f
5 pounds, coin coin coin coin rope rope gem food
You are in a dank cave. You smell that there are bats. No wolf will follow you here. You see nothing.
Key: f forward b back l look p pick_up g give_away e eat_from_chest
l,p,g,e,f,b ENTER l
Your energy is 76.5 You can pick up nothing.
5 pounds, coin coin coin coin rope rope gem food
You can hear the wolf creeping around, smelling you.
Key: f forward b back l look p pick_up g give_away e eat_from_chest
l,p,g,e,f,b ENTER l
Your energy is 74.5 You can pick up nothing.
5 pounds, coin coin coin coin rope rope gem food
You can hear the wolf panting. Do not move out of the cave. Just look. You may eat if you have food in your chest.
Key: f forward b back l look p pick_up g give_away e eat_from_chest
l,p,g,e,f,b ENTER l
Your energy is 72.5 You can pick up nothing.
5 pounds, coin coin coin coin rope rope gem food
You can hear the wolf creeping around, smelling you.
Key: f forward b back l look p pick_up g give_away e eat_from_chest
l,p,g,e,f,b ENTER l
Your energy is 70.5 You can pick up nothing.
5 pounds, coin coin coin coin rope rope gem food
Key: f forward b back l look p pick_up g give_away e eat_from_chest
l,p,g,e,f,b ENTER l
Your energy is 68.5 You can pick up nothing.
5 pounds, coin coin coin coin rope rope gem food
Key: f forward b back l look p pick_up g give_away e eat_from_chest
l,p,g,e,f,b ENTER f
5 pounds, coin coin coin coin rope rope gem food
A cave is back along your path. Ahead is a dark stand of pine trees. You see food.
WARNING You hear a wolf howl!
Key: f forward b back l look p pick_up g give_away e eat_from_chest
l,p,g,e,f,b ENTER b
5 pounds, coin coin coin coin rope rope gem food
You are in a dank cave. You smell that there are bats. No wolf will follow you here. You see gem.
Key: f forward b back l look p pick_up g give_away e eat_from_chest
l,p,g,e,f,b ENTER l
Your energy is 53.5 You can pick up gem.
5 pounds, coin coin coin coin rope rope gem food
You can hear the wolf creeping around, smelling you.
Key: f forward b back l look p pick_up g give_away e eat_from_chest
l,p,g,e,f,b ENTER l
Your energy is 51.5 You can pick up gem.
5 pounds, coin coin coin coin rope rope gem food
You can hear the wolf panting. Do not move out of the cave. Just look. You may eat if you have food in your chest.
Key: f forward b back l look p pick_up g give_away e eat_from_chest
l,p,g,e,f,b ENTER l
Your energy is 49.5 You can pick up gem.
5 pounds, coin coin coin coin rope rope gem food
You can hear the wolf creeping around, smelling you.
Key: f forward b back l look p pick_up g give_away e eat_from_chest
l,p,g,e,f,b ENTER l
Your energy is 47.5 You can pick up gem.
5 pounds, coin coin coin coin rope rope gem food
You can hear the wolf panting. Do not move out of the cave. Just look. You may eat if you have food in your chest.
Key: f forward b back l look p pick_up g give_away e eat_from_chest
l,p,g,e,f,b ENTER l
Your energy is 45.5 You can pick up gem.
5 pounds, coin coin coin coin rope rope gem food
You can hear the wolf creeping around, smelling you.
Key: f forward b back l look p pick_up g give_away e eat_from_chest
l,p,g,e,f,b ENTER l
Your energy is 43.5 You can pick up gem.
5 pounds, coin coin coin coin rope rope gem food
You can hear the wolf panting. Do not move out of the cave. Just look. You may eat if you have food in your chest.
Key: f forward b back l look p pick_up g give_away e eat_from_chest
l,p,g,e,f,b ENTER l
Your energy is 41.5 You can pick up gem.
5 pounds, coin coin coin coin rope rope gem food
Key: f forward b back l look p pick_up g give_away e eat_from_chest
l,p,g,e,f,b ENTER p
Your chest now has 9 items
5 pounds, coin coin coin coin rope rope gem food gem
-------------There are two gems in your treasure chest.
You have won the game with energy remaining: 41.5
────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
Python 3.7.9 (bundled)
>>>
Mar 11 2022 Computer thoughts at the time of Altex San Antonio building my custom Windows 11 computer, in case the People's Republic of China invades Taiwan and cuts off the supply of chips, also because my Windows 8.1 computer, ANODE, is 9 years old. 1) Windows 11 use is between 1% and 9%, a low adoption rate. Most Win 11 is upgrades from Win 10, when the motherboard is recent enough to have 64-bit processor, 4GB of memory, 64GB of storage, UEFI secure boot and TPM 2.0. (Win 11 has been available since last October.) Over the years, I have sometimes been an early adopter. This was the case at TSTC when I used USB before anyone else. 2) Computers with two or more drives are mainly SSD (Flash memory) plus one rotating HDD. My choice is directed by my sense of foreboding of SSD wearout when the SSD has to accept lots of writes. SSD is best used for the OS, an application that doesn't need much writing. Data that changes is better kept on a rotating HDD. My new computer has two 1TB HDD, WD Black, and I have asked that the OS be installed on mirrored HDD for resiliency (Microsoft Storage Spaces). I may add two leftover WD RE-4 250GB drives, to make a total of four HDD, which would make the computer a sandbox to explore Storage Spaces. Like making two storage pools, or is it better to make one storage pool? Most motherboards have six SATA connections, and they go mostly unused, except in John's computers. Likewise, most motherboards have 3-6 PCI-e adapter slots which go mostly unused; my computers don't have much usage of these. 3) The Altex build seems to have them using "ADK," Assessment and Deployment Kit (devicepartner.microsoft.com), Microsoft OEM Preinstall Kit, OPK (suites of tools for OEM to preinstall Windows), Express Deployment Tool. It may be that Microsoft is not allowing DIYers to install Windows any more. This may be because it is so intricate that Microsoft gets too many calls from DIYers who can't figure it out, and they are denying DIYers the freedom to install. From the license: "You must provide end user support...reasonable telephone support." Part of the Microsoft restrictions on system builders is about AAD, Azure Active Directory, which guards against cybersecurity attack. "Windows 11 can tap into the new speeds and battery features of Intel's new Alder Lake processors." 4) Though Win 11 is supposed to be much more resilient against attacks, one can search Internet for Windows 11 virus and find plenty of attacks. So I will be operating my new computer mostly isolated from Internet. 5) In contrast to Microsoft, Linux continues to be DIY friendly. There is a Windows Subsystem for Linux, and it has some virus susceptibility.
Body-Static Discharge
Three arc-proof, gigohm, cheap discharge resistors for painlessly discharging 20,000V of body static
Closeup. Upper two show the end to contact to ground. Bottom is reversed to show the neon lamp that is near the finger end of the resistor.
Girls Who Code at Calvary Hills Baptist has had trouble with static electricity. Even in mild weather, the A/C drops humidity down enough that we pick up 20,000V when we slide around on the plastic chairs and then stand up. It is so much voltage, sometimes, that we get partial discharges from 3" away from the metal frame, as we reach back to discharge to the metal frame of the chair we had been sitting on. The static has killed two Arduinos and one nunchuk controller. I have gotten the students used to handing off an Arduino only after equalizing body voltage by skin-to-skin contact. With the use of neon lamps, we often check out static when we arrive at Room C2. The girls do not like static shocks now that they know what is happening. We refer to the blue arc as "lightning." The girls recognize the reason they get little shocks at home, and they have learned to cope with automobile static (sliding across seat covers and hopping out of the vehicle) by holding onto the steel U ring (bolted to the frame of the vehicle) that the door latches onto, holding on continuously as they slide off the seat and stand beside the vehicle--this gives a gradual discharge that doesn't hurt.
The next advance in our static technology is the discharge devices photographed above. They are really cheap, a plastic straw (milkshake size) with a slip of paper spiraled around and taped down, where the paper has a thick pencil track, graphite, that has around 1000 megohms. The special thing about the resistance is that it is so long that static will not bridge across the ends of the resistor, like it does when you merely hold a 10Mohm resistor to do your body discharge. These homemade resistors have so much resistance that I have no meter that can measure that high. But it doesn't take much current to discharge your body capacitance, which is around 200 pF.
I will be asking girls if they want to manufacture some of these long dischargers and sell them for $1.
The device with the neon lamp doesn't show much orange flash because the 90V lamp gets only 1% of the energy of the discharge. You need some darkness to see the little glow. But the glow lasts for a substantial fraction of a second, maybe 0.2s, which indicates the ohms, since the time constant = R*C has to be around 1gigohm * 200pF = 0.2s.
The label on these dischargers says: "No-feel static discharge pencil graphite."
The middle device is the plainest, with a widening of the track at the ends, one to hold onto and the other to touch onto ground or any metal. There must be a tiny spark upon discharge, but there is zero sensation since the current is around 20000/one billion ohms = 20 microamps.
The top device has an extended paper end that bends a little when it approaches the metal you are discharging to. Just like pith balls or little pieces of paper or light foam "peanuts" or balloons, there is a force of attraction when the voltage is high, and the paper extension is flexible enough that it bends. And after the discharge, it springs back.
The bottom device has an interruption of the pencil track, and a neon lamp bridges the gap. In darkness, you can see a tiny orange glow during discharge.
These devices are fun to experiment with when the humidity is low.
Listening to 120Hz Low-Pass Filter
I built a two-pole, 120Hz LPF to use at Calvary Hills Baptist Girls Who Code with an audio system that will have a small subwoofer. When you put stereo music from YouTube into this filter and listen to the filter output using a good speaker system with 9" auto speakers, you mainly hear bass drum (kick drum). The Voice by Moody Blues has good bass drum. Bach's Toccata and Fugue in D minor on a pipe organ has some low organ frequencies that are below 120Hz. A two-pole LPF lets through a little voice so you can understand what is being filtered out, whereas a four-pole LPF would block so much of the music that you probably wouldn't understand what music is playing, just be listening to the LPF output.
The filter I built is powered by the 16VDC boosted voltage that is used for the MPJA.com $6 stereo amplifiers that I built up last week. This little, cheap speaker amplifier has bridged output that puts half the supply voltage on both sides of the speaker. I put a second stereo module in the assembly to take the 120Hz LPF filter output and amplify it for a subwoofer I have. The filter mixes left and right audio channels and LPFs the mix. The filter will be tacked onto the speaker-amplifier assembly.
So little music comes through a subwoofer that it makes me ask the question, why have a subwoofer? (Subwoofer is a marketing term that means below 100Hz for professional audio, which covers about 2.4 octaves above the minimum audio frequency for human hearing, 20Hz.) You do subwoofer partly to vibrate your chest and seating. There is valid music below 120Hz: drums and pipe organ. A BB♭ tuba can produce 29 Hz. Note that telephones, at least before 1990, passed 300Hz to 3000Hz, a very limited frequency range. When I recorded a short video of the 120Hz system on July 8, 2022, I found that the Android smart phone is unable to produce 120Hz since its speaker is so small.
1/f Noise Progress
Starting at Christmas, I have gotten back into 1/f noise measuring and recording after taking 12 months off. (See above, Jan 1 2022.)
The oven with 6W+29W heater strings plus 55W heating pad doesn't deliver enough temperature regulation. Needed to keep room air at 79ºF. Bought a new space heater but the thermostat doesn't work well enough. Outfitted a solid-state relay to operate the space heater from a thermistor temperature-sense circuit. That seems to maintain the room within a 1ºF band (or better) when ceiling fan plus box fan stir the air. Most days, the 1st-stage LM35 is seeing 0.11 to 0.14ºC band of temperature, and that is small enough that temperature compensation of the 1/f data can be done, seeing as how I will record the LM35 1st-stage temperature. I have five days of recording complete and documented in
Jan31 23 compare avg of 6 7 8 to reduce ringing 4Hz Feb9.ods
and screen captures of charts imported to
1/f noise system extended Jan13 to auto DAC steps v3.odt
both on Win11 computer. Data is being recorded to R Pi SD card, with auto generation of file names.
Next is revamping Python code to do a good job of recording data.
That has been working since about June 19, one data file written every 3 hrs. Code is June17_20pt4secPerRecord_v7.py on R Pi.
I also did Fourier analysis code in Python, finding the As and Bs, which is NOT FFT, not limited to a power-of-2 number of samples.
Aug 2023 Homemade Telescope
I realized that 8" reflector mirror and diagonal mirror can be purchased, just the glass. From China. $130. Might be good quality. I am building the "tube," as an open-frame tube. Mirror cell is merely MDF, glued cereal-box cardboard surround, bubble wrap to even out the pressure on the mirror, maybe better than a fancy 9-point suspension. Mirror alignment is conventional triple screws and one spring pulling back on the bottom of the "tube." Support for eyepiece, finder, diagonal mirror is aluminum channels, four of them. The finder will be $200 Celestron illuminated-crosshair finder IF the China mirrors are good. I have the diagonal roughly mounted with a C clamp to start checking optics. Last night was the first try. I focused on red lights at the tall transmitter tower two miles away. Partially obscured by tree. Focused on parking lot light 200 feet away but that is too bright. The tube struts need to be stiffened by plywood panels, there is way too much flex, which throws off alignment. In fact, how do you align a larger telescope like this?