Thursday 7 December 2017

Anritsu PSN50 Power Sensor

As I got further with the Rohde and Schwarz sweep generator I realized I really had no accurate way of measuring the power output. My spectrum analyzer was pretty good but also not overly precise and not calibrated.

Power meters are pretty expensive and usually the power sensor is sold separately. Power sensors often are as much or more than the meter and for USB power sensors this is even more the case.

I found this Anritsu PSN50 power sensor very cheaply on eBay. I found there is some software for it that seems to support Windows but decided this was Ok and bought it.

Then I realized I couldn't download the software. After talking with Anritsu support it appears the sensor is only intended for use with Anritsu base-station test systems (portable spectrum analyzers) and the stand-alone software is intended only for calibrating the sensor and retails for $3K AUD!!

Anritsu support were not unhelpful but didn't help. I was essentially asking them to expose an internal interface. They basically told me they have no information on the interface. I asked again in a different way but the result was unless it is information they have already published they can't give me any more.

Before I put it back on eBay - can I hack it?

Talking to the Sensor

I found an Ada fruit guide on how to talk to unknown USB devices. It explained configuration, endpoints etc. The first step is using lsusb on linux to see what the device reports. In the case of the PSN50 I got this:

Bus 004 Device 002: ID 0b5b:ffc8  
Device Descriptor:
  bLength                18
  bDescriptorType         1
  bcdUSB               2.00
  bDeviceClass            2 Communications
  bDeviceSubClass         0 
  bDeviceProtocol         0 
  bMaxPacketSize0         8
  idVendor           0x0b5b 
  idProduct          0xffc8 
  bcdDevice            0.00
  iManufacturer           1 Anritsu Company
  iProduct                2 PSN50 Power Sensor
  iSerial                 0 
  bNumConfigurations      1
  Configuration Descriptor:
    bLength                 9
    bDescriptorType         2
    wTotalLength           67
    bNumInterfaces          2
    bConfigurationValue     1
    iConfiguration          0 
    bmAttributes         0x80
      (Bus Powered)
    MaxPower              100mA
    Interface Descriptor:
      bLength                 9
      bDescriptorType         4
      bInterfaceNumber        0
      bAlternateSetting       0
      bNumEndpoints           1
      bInterfaceClass         2 Communications
      bInterfaceSubClass      2 Abstract (modem)
      bInterfaceProtocol      1 AT-commands (v.25ter)
      iInterface              0 
      CDC Header:
        bcdCDC               1.10
      CDC ACM:
        bmCapabilities       0x02
          line coding and serial state
      CDC Union:
        bMasterInterface        0
        bSlaveInterface         1 
      CDC Call Management:
        bmCapabilities       0x00
        bDataInterface          1
      Endpoint Descriptor:
        bLength                 7
        bDescriptorType         5
        bEndpointAddress     0x82  EP 2 IN
        bmAttributes            3
          Transfer Type            Interrupt
          Synch Type               None
          Usage Type               Data
        wMaxPacketSize     0x0008  1x 8 bytes
        bInterval               2
    Interface Descriptor:
      bLength                 9
      bDescriptorType         4
      bInterfaceNumber        1
      bAlternateSetting       0
      bNumEndpoints           2
      bInterfaceClass        10 CDC Data
      bInterfaceSubClass      0 
      bInterfaceProtocol      0 
      iInterface              0 
      Endpoint Descriptor:
        bLength                 7
        bDescriptorType         5
        bEndpointAddress     0x03  EP 3 OUT
        bmAttributes            2
          Transfer Type            Bulk
          Synch Type               None
          Usage Type               Data
        wMaxPacketSize     0x0040  1x 64 bytes
        bInterval               0
      Endpoint Descriptor:
        bLength                 7
        bDescriptorType         5
        bEndpointAddress     0x83  EP 3 IN
        bmAttributes            2
          Transfer Type            Bulk
          Synch Type               None
          Usage Type               Data
        wMaxPacketSize     0x0040  1x 64 bytes
        bInterval               0
Device Status:     0x0001
  Self Powered

So that abstract modem looked pretty promising. It appears to be a USB serial device. This makes sense as the device has a serial port in addition to the USB. So how to talk to it?

Well it turned out Linux just quietly loaded a serial device for me. I found there was a /dev/serial/by-id/usb-Anritsu_Company_PSN50_Power_Sensor-if00 device. For some reason I couldn't get screen or mincom etc to talk to it properly. The device would just keep sending back 'NO TERM'. If I cat the device from one terminal while echoing a command from another terminal it would respond with a BAD CMD. That's pretty promising though - I can talk to it!

Commands

Anritsu make a number of other USB power sensors that you ARE supposed to talk to with a computer (like this one). For these they publish commands so I tried a few of those. Not many of the commands worked but I found a couple that did. For example I figured out that IDN? would respond with the ID of the device:

ANRITSU,PSN50,0748037,0748037,1.00

TEMP? Returned the current temperature of the device. 

AVG? Returns 0 and I figured out if I say AVG 1 it said 'OK'. So that means if I send a command with a question it queries (makes sense) and without it sets some state. If the state change is good it says 'OK'

STATUS? Returns a byte which contains the status of the device. I haven't figured this out yet.

ZERO Makes the device sit there for a long time and eventually say 'OK'. From reading the user guide it appears it is supposed to reset the zero power setting (i.e. you do this with nothing connected).

But nothing I tried gave me the power level. So what to do? Well I decided to try brute force. I used some code like that below to search for all 3 letter commands (assuming no numbers). Only looking for commands that return values too (like the power level!). I found the device would lock up if I sent the commands to quickly so I had to add a small delay between commands.
import serial
import time

commands = []

port = serial.Serial(timeout=5.0, port="/dev/serial/by-id/usb-Anritsu_Company_PSN50_Power_Sensor-if00")


def test_commands(prefix, seq_len, test_func):
    for charOrd in range(ord('A'),ord('Z')+1):
        if len(prefix) < 3:
            print("Starting "+prefix+chr(charOrd)+"...")

        test_func(prefix+chr(charOrd))

        if len(prefix) < seq_len-1:
            test_commands(prefix+chr(charOrd), seq_len, test_func)


def check_command(command):
    # print ("Trying "+command)
    port.write(command+"?\n")
    response = port.readline()
    if "BAD CMD" not in response:
        print("** Got One!! " + command+"?")
        print(response)
        commands.append(command)
    time.sleep(0.05);


test_commands("", 3, check_command)

port.close()

print commands

This took quite some time to run and it only gave me two more but it gave me an important one!

POW? Returns the power level in dbM (as a floating point)
VER? Returns the version of the firmware (1.0)

I tried running a four letter scan and it took a full two days and yielded nothing extra.

Anritsu publish an application note on using the device with their other equipment. This tallied with the commands I was seeing such as averaging mode, temperature etc. The application note also talked about setting the centre frequency of the device and that it had calibration constants for each 500MHz slab of bandwidth.

I modified my script a bit to search for commands with up to a three letter prefix before FREQ? so AAAFREQ? through to ZZZFREQ? and I found CFFREQ? returned a number. After a bit of fiddling it appears the number is from 0.05 through to 6.0 and is the frequency in GHz (0.05 is the lowest frequency and is 50MHz).

The application note also talked about a limit (min/max) mode but I haven't found commands for this. it could be they are doing it in software. Similarly they talk about setting an offset for doing relative power measurements but again this could be done in software. There is also a max hold mode in the manual and I would have thought this would have to be done in firmware but again I haven't found a command.

Power Measurements

By creating a couple of small python tools I can take power readings and switch the centre frequency. I took some readings from my signal generator and compared the readings my spectrum analyzer reported.

I found for signals over 1GHz the measurements were quite close and made me feel like the power sensor was working. But for frequencies below 1GHz they were miles out (20dB or more). Interestingly at 990MHz this was already quite wrong and got worse as you go down. The CFFREQ command didn't seem to make a whole lot of difference too which is odd. The numbers were consistent from run to run however so I could (if I had a source I could trust) make up adjustment factors. The size of the error though will limit the dynamic range significantly.

Hardware

The unit has four screws on the bottom and you can remove the bottom plate. Initially I thought this is as far as I could get in without undoing the power input connector (which would surely stuff up the calibration). Later I realized the screws at the end come undone so now I can fully access the board.

Here is the bottom side. Nothing much to see apart from some passives for the different power supplies etc. There is a light-pipe near the USB port. I figured out (accidentally) the LED is red/green as I tried to ZERO the device while I had a signal applied. The LED went red and it stopped talking to me for a while.


Here is the top side. The highlights are:
  • Main micro is a PIC18F455 running at 20MHz
  • LTC2444 high speed, 24bit 16 channel DAC. This seems like way overkill for this. Not really sure why...
  • AD8629 Low offset, low drift, low noise op amps that look like they read the actual power off the detectors. The CalXpert software guide explains the internals of the sensor and how it has a high and a low power path. See section 1.2 here
  • MAX32221 RS-232 Line driver
  • LTC1258 4.1V LDO



I can't believe they machined the case. Wow.