Monday, March 30, 2015

Auto on-off for amplifier

I ordered a bunch of Digispark boards - for a few dollars each and included bootloader you cannot go wrong. They are basically prototype&forget boards and go under various other names (Picoduino, Pro Nano, Olimexino-85). Banggood.com has them for ~3$.

The first project is an automatic power-on, power-off for an old Sony speaker set, formerly CD/cassette deck.

My goal is for the amplifier to turn on when audio signal is detected and turn off after 30 minutes of silence. This is not so much for power saving as it is to reduce the white noise and GSM pickup during the night.


The speakers can be turned on by connecting a 100 kOhm resistor between two of the four pins on a plug







I've made various measurements to determine the correct input level that's reliably above the silence noise floor.

In my case it was somewehere around 20mV.




The ADC of ATTiny85 can be set to a 1.1V reference, improving the detection precision. Otherwise, by default, the 3.3V reference is used.

I've tested various algorithms and found that peak detection works best. Averaging seemed better on paper but was not able to detect low levels of music.

I haven't drawn a schematic, but here's a wiring picture:


If that makes sense to you as much as it does to me, here's the description.
The Digispark is fed directly from the speakers' 16.5V supply, into the VIN pin. Power dissipation is decent.
A 4N35 optocoupler connects through pins 4 and 5 a 100k resistor across the power-on pins, like in the first picture.
The 4N35 pin 1 is driven by the Digispark pin 4, through a 10k resistor. Pin #2 of the optocoupler goes to GND.

Audio signal is taken directly from the center lead of the RCA jack, through a capacitor (a random one from the box, probably in the nanoFarad range) and goes to PIN2 on the Digispark.
A 10-20kOhm capacitor from the same pin #2 to ground reduces ambient noise. *

TODO: draw a schematic and post it here. Remind me in the comments if I forget.

* To make the circuit more sensitive, increase the resistor value from pin 2 (analog in) to ground.

Code

The input is sampled every 100ms and the peak value is retained. If that peak value is above a threshold ('1' in this case) then the code detects the audio as playing and lights up an LED and turns on the optocoupler.
If after a predefined duration (30 minutes) no audio was detected then it shuts off the optocoupler.

There are various caveats to the Digispark - limited flash space (if Serial-to-USB debugging is used), limited pins (cannot use serial debugging afterwards), some pins cannot be really used (pin 5, I think).

Code has some snippets from this, however the original code does not have reliable detection.


#include <DigiCDC.h>
#include <avr/sleep.h>

#define SIGNAL_THRESHOLD 1
// A1->P2, A2->P4, A3->P3, A0->P5
#define ANALOG_INPUT_PIN 1
#define STATE_OUTPUT_PIN 1
#define AMP_OUTPUT_PIN 4

/* Timing constants
 * maxIdleMinutes - Longer than this, amplifier will be turned off
 * sampleSleeTime - Every 2,000 mSec we sample and process
 */
const int maxIdleMinutes = 30;
const int sampleSleepTime = 100;

// the setup routine runs once when you press reset:
void setup() {
  pinMode(STATE_OUTPUT_PIN, OUTPUT); //LED on Model A  or Pro
  pinMode(AMP_OUTPUT_PIN, OUTPUT); //LED on Model A  or Pro
  analogReference(INTERNAL1V1);

  SerialUSB.begin();
}

// the loop routine runs over and over again forever:
unsigned long average = 0;
unsigned long peak = 0;
unsigned long idleTimeToTurnOff = (unsigned long)(maxIdleMinutes * 60L * 1000L);
unsigned long lastIdle; // Preserves the millis() read when idle was detected

boolean isSoundPlaying() {
  peak = 0;
  long temp_peak, reading;
  for (int i = 0; i < 100; i++) {
    reading = analogRead(ANALOG_INPUT_PIN);
    average = (9 * average + reading) / 10;
    if (reading > peak) peak = reading;
    delay(1);
  }
  SerialUSB.print(average);
  SerialUSB.print('\t');
  SerialUSB.println(peak);
  return peak > SIGNAL_THRESHOLD;
}

void loop() {
  unsigned long now = millis(); // Take current time
  unsigned long diff;
  
  if (!isSoundPlaying()) {
    digitalWrite(STATE_OUTPUT_PIN, 0);
    if (lastIdle != 0)
    {
      diff = 0;
      if (now < lastIdle) // Overflow of millis()
        diff = now + (0xFFFFFFFFL - lastIdle);
      else
        diff = now - lastIdle;
      SerialUSB.print("Idle for ");
      SerialUSB.println(diff, DEC);
      if (diff > idleTimeToTurnOff)
      {
        SerialUSB.print("Turning off");
        // Turn off the Amplifier
        digitalWrite(AMP_OUTPUT_PIN, 0);
        delay(5000);
      }
    }
    else
      lastIdle = now; // Now is first time we see idle, save the time.
  }else{
    // sound is playing
    digitalWrite(STATE_OUTPUT_PIN, 1);
    SerialUSB.print("Turning on");
    digitalWrite(AMP_OUTPUT_PIN, 1);
    lastIdle = 0;
  }

  delay(sampleSleepTime);
}

Convert a 27Mhz RC car to 13.56Mhz





Note: modifying RF equipment is most likely illegal in all countries, unless you know your stuff!
I bought 3 radio-controlled toy cars for parts and for racing around the house, since they were really cheap.
Unfortunately, they all share the same RF channel (27MHz) which means you cannot use two at the same time. I mean, you could, but the fun of having two cars mirroring each other fades away after a few seconds.





So I've wired the oscilloscope ground probe around the antenna to check the frequency and modulation. No surprise for finding out it's 27Mhz with some sort of OOK.



Time to take the car apart to see what's inside:



Notice the first hole on the bottom-right of the board surrounded by 4 soldered leads. That hole is for the adjustment cap, we'll make use of that later.






The transmitter frequency is controlled by the 27.145 MHz oscillator, there's nothing to adjust there. The receiver frequency is in part controlled by a trim capacitor.

Now for the fun part, the TX oscillator is replaced with another one from the parts drawer:




It doesn't look pretty. Ham operators would probably get mad at you.














After adjusting the trim cap on the receiver unit to one extreme I'm able to get the two cars to work independently. Remote range went down from ~10 meters to ~3 meters.

However, if the 27MHz transmitter is within 30cm of the ~16Mhz car it will also control that. Same thing happens the other way around.

I'd be curious to see what the new TX spectrum looks like and what's the typical RF power, before and after the mod.


Note: modifying RF equipment this way is probably illegal in all countries!

To be legal you'd probably have to choose one of the 13.56 MHz or 40.68Mhz ISM bands, those being the closest to this range. But don't quote me on that.

Automatic vent - take two


Take 2:

I've decided to give the original unit a coat of fresh paint since it seemed to work pretty reliably - or so I've thought...
The problem is that as the batteries drained the detection level changed, causing the unit to false trigger and quickly drain the 2xAA batteries within 1 day.

Also it seemed to trigger falsely based on stray light level, time of day, planets' alignment, whether someone has showered or not...




 So I've taken a look with the oscilloscope at the pins of the LED and decided that the capacitive detection method depended a lot of stray RF, making it highly unreliable. So drew up another schematic, this time using the LED as a photodiode (small voltage source). To get rid of having to tweak the constant in the code a small potentiometer (P1) was added - this has the effect of setting the light level:


I had to switch to a microcontroller version with two ADC inputs for this.
Also, another problem was that the servo was draining too much power causing the uC to brownout because of the lowered voltage. This was fixed by D2 and C1.

However the entire arrangement was still too touchy, causing it either to trigger falsely or not detect reliably the small red power-on light.

Take 3:

I decided to take a brute-force approach and wired a 1.5W 220V LED spot light I had lying around.


This made the detection much more reliable but it still triggered randomly sometimes and the new code made the batteries run out much quicker.

Take 4:

So I've thought why not make my own enclosure and get rid of the original one completely.




Sketched up a rotary shutter in SketchUp and proceeded in carving it out of a CD case with a dremel:















However this was has proved not airtight enough and caused more audible noise than the cardboard solution.

Take 5: 

If you can't make it, buy it!



Unfortunately this commercial solution is worse than my cardboard design, in terms of audible noise and air tightness.
It seems I'm off to the drawing board, again.