Welcome to the new FlexRadio Community! Please review the new Community Rules and other important new Community information on the Message Board.
If you are having a problem, please refer to the product documentation or check the Help Center for known solutions.
Need technical support from FlexRadio? It's as simple as Creating a HelpDesk ticket.

Android App

1246715

Comments

  • W4WHL
    W4WHL Member ✭✭
    edited July 2016
    I will look into adding the features you requested.  At some point I plan to add remote audio directly to the App.  But that will not be soon.  I have much more learning to do, before I can tackle that.
  • Steve-N5AC
    Steve-N5AC Community Manager admin
    edited February 2017
    William it's looking awesome!  I'm wondering if you will be the first person to display panadapter data from a FLEX-6000 outside of FlexRadio ;-)  Let me so if I can help with the data dump that you provided earlier, referenced here again:
    10.0.0.4: [954728508, 1073741824, 7213, 1397522435, 0, 0, 0, 0, 100, 2, 89416, 786444, 786444, 786444, 786445, 786444, 786444, 851980, 786444, 786444, 851980, 786444, 851981, 786445, 851981, 786445, 851981, 720906, 786445, 851981, 786445, 851981, 786444, 851980, 851981, 851981, 851981, 851981, 786445, 851981, 851981, 851981, 851979, 851981, 851981, 851981, 786445, 851981, 851981, 786445, 851981, 851981, 851980, 851981, 851981, 786445, 786445, 786445, 851981, 851979, 786445, 1429851, 1566525, 1299560, 1365096, 1429801, 1566472, 0, 0, ...
    We really need to look at the hexadecimal interpretation of some of this data so here is the hex conversion for the first several words:
    01- 0x38E8003C
    02- 0x40000000
    03- 0x00001C2D
    04- 0x534C8003
    05- 0x00000000
    06- 0x00000000
    07- 0x00000000
    08- 0x00000000
    09- 0x00000064
    10- 0x00000002
    11- 0x00015D48
    12- 0x000C000C
    13- 0x000C000C
    14- 0x000C000C
    15- 0x000C000D
    16- 0x000C000C
    17- 0x000C000C
    18- 0x000D000C
    If you refer to the VITA-49 standard, the first word here is the VTIA-49 header.  The header decoder ring is on about page 44 of the standard (depends on if you have the draft or the full standard).   The first byte (3) indicates that this is "Extension Data packet with Stream Identifier".  Extension data means that is is not in standard format -- this is because there is not an FFT format in VITA-49, but they recommend an extension packet.  

    Here's the format of an extension packet:


    image

    The next byte (8) has the top bit set when there will be a class identifier field (true for this packet) and the next bit is on if there will be a packet trailer (false for this packet).  The other two bits are throw away.

    The next nibble (E) describes the time-stamp data indicating that we will have real-time picosecond timestamps in the data.  Really for the FFT we should have eliminated this, but it is here and the data is zeros as you will see later.

    The next nibble (8) is the packet count.  This number rolls through all four bits and starts again.  so it goes 0...1...2...3 .......... E...F...0...1...2 etc.  It happens to be 8 here.  This will help you reassemble packets in the correct order should they get unordered in transport.

    Finally, the 0x003C final 16-bits is the length of the packet in 32-bit words.  In this case, 0x3C = 60 decimal = 240 bytes.  The packet length you get should be this long.

    Since the header said there was a stream identifier, this comes next (word #2) and it is 0x40000000.  You should recognize this as the panadapter steam returned to you when you created the panadapter/panafall.

    Next is the class identifier since that bit was set in the header (word #3 & 4).  It is the next two words.  When strung together, you get: 0x00001C2D 534C8003.  The first word is the organizational unique identifier (OUI) of the company creating the packet.  OUIs are used in Ethernet MAC addresses and other places on the Internet.  If you do a web search for "oui 001c2d" you will see FlexRadio Systems is the owner of this OUI.  Now the class ID.  For all data generated by the SmartSDR codebase, we use the first 16-bits as 0x534C.  This is ASCII "SL", a reference to the codename of SmartSDR before it was named and released: SMOOTHLAKE.  Finally, the 0x8003 can be found in the document I linked to earlier which indicates that this data is FFT data (image below from the Information Class Document):

    image

    Next, words #5, 6, & 7 are all skipped as they would be the timestamp we said was in the data, but that is actually blank at this time.

    Referring back to the Information Class document, the FFT Data Packet Class says:

    image

    So if we look at the first four words of the payload, we get:
    start_bin = 0 (word #8)
    num_bins = 200 (word #9)
    bin_size = 2 (word #10)
    frame_index = 89416 (word #11)

    FFT frames  can be larger than the size of permissible Ethernet packets (we are not doing jumbo frames because some hardware doesn't support it) so multiple packets may be used to send a complete FFT frame.  So in this case, you can fit the whole frame into a packet and so the start_bin is 0 and there are 200 bins in the packet.  Each bin is 2 bytes.  The frame index can help you reassemble frames in some circumstances.

    OK!  We know what we have now right?  Just have to decode the real data now!

    Of course when you created the panadapter, you told SmartSDR how large your window for display is in pixels.  SmartSDR uses this to size the display and perform all the calculations for you. Each 16-bit data element is a position in the Y-axis where the point of the FFT should be plotted.  So a "0" means at the bottom and if your Y-height provided in the creation of the FFT display was, say 20, the maximum value for each pixel will be 19.  Looking at the hex data for words #12-16, you can see that there are data points that read like C,C,C,C,C,C,C,D,C,C,C,C,D,C ... and so on.  Translating to decimal, these are 12, 12, 12, 12, 12, 12, 12, 13, 12, 12, 12, 12, 13, 12 so this is a very averaged panadapter with the noise floor about 12 pixels from the bottom of the window.  I didn't bother decoding past this point.

    Let me know if any of this is confusing, etc.
  • W4WHL
    W4WHL Member ✭✭
    edited July 2016
    Steve,

    That is extremely helpful. Its 5am, so I need some coffee before I can fully digest this.  Can you explain the waterfall data format also?  when you have time.

    From what I'm finding is.  Currently it does not appear that Flex is using timestamps or trailers.  So this makes easy work to sift and parse the packets.  I have successfully been able to capture and buffer each of the class codes I wanted.  I was just really unsure of the data.

    What you posted above for the FFT data, makes perfect since,  And I already have some ideas to experiment with.

    Now if you could point me in the right direction of the waterfall data :)


    William


  • Michael - N5TGL
    Michael - N5TGL Member ✭✭
    edited October 2016
    Wow, William.  Great work.  Using a Nexus 7 like others and same great result.  Nicely done!
  • Walt - KZ1F
    Walt - KZ1F Member ✭✭
    edited November 2016
    Steve, I realize you are working through this with William and I don't want to hijack the conversation. I was kind of hoping I could get William to take the payload and process it into a series of tiles. It looks like there is one tile created per packet. Each tile has a byte array and it was my understanding that byte array is one line of pixels starting at 0,0 (top left of the window). I am not processing the waterfall data yet but when I get to that point I was assuming, and this is largely from looking at the test method in Waterfall, one would scroll the window, display the image (0,0 -> 0,max y). I am inferring from what you are saying that isn't correct. By proceeding with that ordering, there would always be a valid line of pixels at the top of the window.
  • Walt - KZ1F
    Walt - KZ1F Member ✭✭
    edited November 2016
    One thing that perplexes me is, as you and I discussed months ago, when scrolling a Windows window, one scrolls the window, invalidates the top row of pixels, which fires a paint event where the next row of pixels is drawn. Nothing appears to handle it that way now and it seems one has to animate the window to autoscroll say at every ms. I noticed in the header for the tile there is a duration value. Is that how .NET handles it?
  • GI4FZD
    GI4FZD Member
    edited June 2016
    will this be ok on lenovo A10 or cheap allwinner 31s tablet?
    I need to update my ancient advent vega.
    cheers
    Paul
  • W4WHL
    W4WHL Member ✭✭
    edited February 2017
    Now we are getting somewhere.  I successfully graphed live FFT data.  Albeit I'm limiting the pan size to a single packet, so not much resolution.


    https://www.youtube.com/watch?v=nGFuYaNVw-o

  • Walt - KZ1F
    Walt - KZ1F Member ✭✭
    edited November 2016
    That looks like it should be a spectrum display, correct? If so, try doing that as a multi-line, in other words, connect the points as opposed to drawing each from the base to the point.
  • W4WHL
    W4WHL Member ✭✭
    edited July 2016
    Ok, now one thing I don't get yet.  So the panadapter data is not linked to center frequency.  Changing center frequency does not shift the panadapter data.  It stays static.  How do I get the data to shift with center frequency?
  • W4WHL
    W4WHL Member ✭✭
    edited July 2016
    Walt, yest its spectrum.  Since Steve gave me the info for spectrum, I thought I would start with that.
  • Walt - KZ1F
    Walt - KZ1F Member ✭✭
    edited November 2016
    That looks like it should be a spectrum display, correct? If so, try doing that as a multi-line, in other words, connect the points as opposed to drawing each from the base to the point. That is pretty cool though William. Is it upside down? In other words, should those dips be peaks and the peaks be noise floor?
  • Walt - KZ1F
    Walt - KZ1F Member ✭✭
    edited November 2016
    When you said earlier it was 5am I thought you had pulled an all-nighter. Steve's comment was 5am. I was surprised to see you up. It's addictive, huh?
  • Steve-N5AC
    Steve-N5AC Community Manager admin
    edited February 2017
    OK let me answerWalt's questions about the waterfall.  First, let me talk a little about the architectural differences in the panadapter and waterfall.  The panadapter is considered a wasting display -- if you don't see it shortly after it is produced, it is worthless and should be thrown away.  We could argue about this statement, but it is the statement we designed against.  

    Waterfall, on the other hand, can be used long after it is produced.  A couple of the things I really hated about waterfalls I'd seen to date are 1) if you tune the radio, the waterfall gets disjointed from the panadapter and 2) if you decide to alter the color scheme for the waterfall, it only works from that point forward.  So we had two additional design goals to fix these "problems."  

    We also looked at the data that is calculated in the radio and what we can do with it.  You have to understand some more about how the radio works, but the other important fact is that we almost always have extra bins calculated for the waterfall than what are requested for the display.  We discussed what to do with this data.  The two options were 1) throw it away, 2) save the data in case the operator wants to see it later.  We decided 2 was the best option, but it does take more bandwidth to do so.  We may alter this some for the WAN case, but for now it is what we do.

    So the data presented is NOT the upper left of the waterfall window.  It actually starts to the left of the display (hidden) in almost every case.  This is why you can tune to either side and see new data as a general rule.  It's because we calculated and saved that data.  So the waterfall data contains the actual starting location of the data.  The header of the packet is just like the FFT, but with a different information class.  Here's the structure for the payload of the packet:

    image

    Here, we tell you the first frequency represented in the upper left bin of the tile.  This is a VITA-49 frequency representation which is a 64-bit integer.  If you want this in integer Hz, just perform the equivalent of >>20 or if you want as a float in Hz divide by 1048576.  You will then have to align this to the display that you have drawn and throw out any bins that you don't want to display --or-- store them for later use.

    The next element is the width on a pixel -- again you have to be able to figure out how you are going to line this up with your panadapter.

    Next is the width and height of the tile sent.  Generally today we will send a height of one, but we reserve the right to send different heights.  We have discussed processing more data and providing fill data as we have it at a higher resolution.  The width will be the number of bins of width pixel_bandwidth.

    Next is the timecode which increments by one to help you determine if you've lost data.  Finally is a computed auto-black level which you can use in your algorithm if the user selects auto black.  You have to calculate the colors and the black yourself.  There are two reasons for this: 1) by having the client interpret the data, you can then re-interpret it as the user changes the colors, etc.  You have to have done the interpretation or we would have to resend the whole display each time.  2) It allows us to send a fraction of the data, preserving network bandwidth.  Since the data point to color is a hash algorithm that is expanding (data in is 16-bit and data out is 24-bit or more, we save the data transfer).

    Then the data is just 16-bit bin values that must be interpreted as color.  Make sense?

  • Steve-N5AC
    Steve-N5AC Community Manager admin
    edited December 2016
    Looks good William.  I assume you have inverted the Y-Axis (0,0 is at the lower left, not upper left for the panadapter) and that you also have weighted average on based on the behavior that I see.  
  • Walt - KZ1F
    Walt - KZ1F Member ✭✭
    edited November 2016
    Maybe the best, short, answer is no. FFT is just some vague term I recall from my Fortran days. I did try to look it up to refresh/acclimate myself to the terms. It isn't clear what a bin is beyond a fragment of information. The scenario I've been using, while something I vaguely remember doing 30 years ago had to do with scrolling a multi-line text box or a listbox where the data is finite and is moved a pixel height at a time behind the viewport.  When the panadapter is created the center frequency is specifed so for the pane it is in the value of x / 2 is where the center freq is and the low freq is pixel-bandwidth * x/2 below the center freq. Pixel-bandwidth * x is the display's bandwidth. I did not make that connection to autoblack or the user colorizing the pixel. In my case I was going to take that byte array, turn it into a ByteArrayStream and create an Image object, basically a one (or more) pixel height by y width bitmap image that I would draw, starting at 0,0. the next row would start at 0,1 etc until y > window max y, in which case I'd scroll the window up and always be drawing starting at 0, max y.  Thank you for explaining why Eric multipled the width by 1.2. So, for the case of the waterfall the viewport would need to be offset some into the actual image. Correct? It is still unclear how to handle the scrolling after I get to y==y(max). I really want the arrival rate of the waterfall packets to control the scrolling, not an internal timer. With SSDR I've only ever gone back in time once and I can't foresee a need to do it again so I think I won't try to maintain more than the viewport will hold.
  • W4WHL
    W4WHL Member ✭✭
    edited February 2017
    Steve,

    The panadapter data is actually coming in like that.  For some reason the data I'm getting shows a signal above the noise from as a lower value.  Something like this:

    20,20,20,20,20,13,12,15,17,20,20,20,20,20

    Not sure why this is.  of how to account for it.  Since I'm plotting the values as they come in, I have no idea how to make a 12 higher than a 20 LOL. 

    Maybe someone has an algorithm that will do this. 

    But what I would like to know most is, How do I shift the panadapter?  Since the panadapter is a snapshot of data, and not linked to center frequency.  How can I manually shift the panadapter with center frequency?

    William
  • W4WHL
    W4WHL Member ✭✭
    edited July 2016
    Here is a snippet, after converting byte to int

    0, 155, 0, 156, 0, 155, 0, 153, 0, 153, 0, 152, 0, 129, 0, 110, 0, 107, 0, 120, 0, 128, 0, 114, 0, 104, 0, 125, 0, 127, 0, 144, 0, 155, 0, 155, 0, 156

    the lower values representing singals.  Maybe I have something strange with my conversion from byte to int?

    William

    
  • Walt - KZ1F
    Walt - KZ1F Member ✭✭
    edited November 2016
    12 is higher than 20....remember the geometry is 0,0 is top left. in a window 20x50, a height of 20 is on the bottom so a bunch of 20's followed by a couple of 12's will have the 12 be 8 pixels higher than the 20. How are you generating the display? To invert them subtract the y dimension of the window and take the absolute value of that such that you'd get: 0,0,0,0,7,8,3,0,0,0. I am pretty sure Android does the same FU geometry as Windows. 0,0 is top left as opposed to bottom left.
  • Walt - KZ1F
    Walt - KZ1F Member ✭✭
    edited November 2016
    William, how did you get that second set of numbers? they look like coordinate addresses (0,155), (0,156) etc. but that isn't 20's and 12's wit a 13 thrown in for good luck.
  • Walt - KZ1F
    Walt - KZ1F Member ✭✭
    edited November 2016
    so 20 is 20 down from the top, 12 is 12 down from the top so abs(ymax-value) would be 0,0,0,8, etc. In my experience, that should work fine. so something in the way you are drawing them is converting it to the other coordinate system.
  • Walt - KZ1F
    Walt - KZ1F Member ✭✭
    edited November 2016
    I know....Android uses OpenGL and OpenGL uses Cartesian coordinates which is bottom left is 0,0 so do that conversion I mentioned absolute(ymax-value). The x value is fine as it still goes from left to right.
  • W4WHL
    W4WHL Member ✭✭
    edited July 2016
    Here is what I have so far.  Much better me thinks :)

    Sorry my nose was stuck in the code, not ignoring you :)
  • Walt - KZ1F
    Walt - KZ1F Member ✭✭
    edited November 2016
    Is that being drawn in the same thread that received the UDP packet? If so, try this.
    Create a BlockingQueue and another thread that just blocks on the top of the queue. In the steady state, that thread will be blocked. In your callback thread that receives the UDP packet, simply push it into the queue and let it go back to listening for the next UDP packet. As soon as you've pushed the VitaPacket into the BlockingQueue, that worker thread waiting on it will unblock. In that thread, pull off the head of the queue and process and draw it, then notify the UI thread. I think you'll find it is much faster.

    But yes, that is quite nice. You may well be done this week.
  • Walt - KZ1F
    Walt - KZ1F Member ✭✭
    edited November 2016
    You could also undo the weighted average, that too will make it more active, well, unless you prefer it that way. Once you put that on the tablet it will automatically be drawn by the GPU. The implementation you'd likely want is LinkedBlockingQueue.
  • Steve-N5AC
    Steve-N5AC Community Manager admin
    edited December 2016
    Maybe the best, short, answer is no. FFT is just some vague term I recall from my Fortran days. I did try to look it up to refresh/acclimate myself to the terms. It isn't clear what a bin is beyond a fragment of information.

    A Fourier transform takes time-domain data and converts it into frequency-domain data.  For our purposes, it is essentially a large number of receivers with very narrow bandwidth.  Each of the receivers puts it's resultant signal in a bin.  The magnitude of the bin indicates how much signal in that frequency range is present in the source time-domain signal.  An FFT is a fast Fourier transform, just an algorithmically optimized version of the Fourier transform.

    The scenario I've been using, while something I vaguely remember doing 30 years ago had to do with scrolling a multi-line text box or a listbox where the data is finite and is moved a pixel height at a time behind the viewport.  When the panadapter is created the center frequency is specifed so for the pane it is in the value of x / 2 is where the center freq is and the low freq is pixel-bandwidth * x/2 below the center freq. Pixel-bandwidth * x is the display's bandwidth.

    The size of the display and the data we provide are not the same as I mentioned.  You will be disappointed if you make this assumption...

    I did not make that connection to autoblack or the user colorizing the pixel. In my case I was going to take that byte array, turn it into a ByteArrayStream and create an Image object, basically a one (or more) pixel height by y width bitmap image that I would draw, starting at 0,0. the next row would start at 0,1 etc until y > window max y, in which case I'd scroll the window up and always be drawing starting at 0, max y.  Thank you for explaining why Eric multipled the width by 1.2. So, for the case of the waterfall the viewport would need to be offset some into the actual image. Correct?

    Yes.

    It is still unclear how to handle the scrolling after I get to y==y(max). I really want the arrival rate of the waterfall packets to control the scrolling, not an internal timer.

    This is how I would do it -- use the data to cause the scrolling.  BUT if you miss a packet you have to decide how to handle it.  We show a blank line where the data should be.  If you see this in our application, it means that you lost data somehow.  Generally the top two answers are 1) bad network connection or 2) slow PC can't draw fast enough.

    With SSDR I've only ever gone back in time once and I can't foresee a need to do it again so I think I won't try to maintain more than the viewport will hold.

    Fine -- this is certainly your choice as an application designer!
  • Steve-N5AC
    Steve-N5AC Community Manager admin
    edited December 2016
    Remember the data is uint16s so two bytes per pixel.
  • Steve-N5AC
    Steve-N5AC Community Manager admin
    edited December 2016
    Remember the data is uint16s so two bytes per pixel.
  • W4WHL
    W4WHL Member ✭✭
    edited July 2016
    Walt,

    I am running the UDP in a separate thread.  I am also running weighted average on the radio, but no additional averaging in my graphing.

    I was making a big mistake.  First the data is coming in a 16bit shorts vs 8bit .  So I needed to first tell the radio to only send x=700.  700 sample points takes 1400 bytes.  Also when converting to int, I have to throw away the extra zeros in the int array (every other byte).

    I can not get a decent panadapter view in a single packet.  700 samples is plenty for a small screen.

    Currently I'm using java.awt to draw the graph, This will completely change in android, as it does not support awt.  But this was just a test.

    Also since I have no plan in android to have offscreen data, just re-centering the panadapter as you tune works great.  For now I just drew a line dead center, and use that as a tune aid. 

    William


  • W4WHL
    W4WHL Member ✭✭
    edited July 2016
    Yep Steve :)  figured that out the hard way, instead of actually reading what you wrote the first time :)

Leave a Comment

Rich Text Editor. To edit a paragraph's style, hit tab to get to the paragraph menu. From there you will be able to pick one style. Nothing defaults to paragraph. An inline formatting menu will show up when you select text. Hit tab to get into that menu. Some elements, such as rich link embeds, images, loading indicators, and error messages may get inserted into the editor. You may navigate to these using the arrow keys inside of the editor and delete them with the delete or backspace key.