Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Received unknown message from PMU #35

Closed
hrvojej opened this issue Dec 9, 2021 · 12 comments
Closed

Received unknown message from PMU #35

hrvojej opened this issue Dec 9, 2021 · 12 comments
Labels

Comments

@hrvojej
Copy link

hrvojej commented Dec 9, 2021

Hi,

I'm having problem receiving Data Frames from my PMU.

When I do test with example scripts using randomPMU.py as sample PMU and tinyPDC.py as PDC everything works perfectly.
But when I connect to my PMU I get ConfigFrame2 without any problems after that I got error receiving Data Frames.
PMU is on 192.168.100.214, port is 4712. PCAP capture taken with Wireshark is here.

C:\pypmu\venv\Scripts\python.exe C:/pypmu/iripdc.py
2021-12-09 18:57:08,984 INFO [2] - PDC successfully connected to PMU (192.168.100.214:4712)
CONFIG:  b'\xaaA\x00\x12\x00\x02a\xb2Ct\x00\x0f\x05\r\x00\x05\xd4x'
2021-12-09 18:57:08,999 DEBUG [2] - Received ConfigFrame2 from PMU (192.168.100.214:4712)
RECEIVED MESSAGE FROM PMU: b'\xaa1\x01\xda\x00\x02a\xb2Cv\x0f\x00\x00\x00\x00\xff\xff\xff\x00\x01STATION A       \x00\x02\x00\x00\x00\x08\x00\x00\x00\x01IAPM            IBPM            ICPM            VAPM            VBPM            VCPM            VSPM            V1PM            SV1             SV2             SV3             SV4             SV5             SV6             SV7             SV8             SV9             SV10            SV11            SV12            SV13            SV14            SV15            SV16            \x01\x00W\xe3\x01\x00W\xe3\x01\x00W\xe3\x00\x03\r@\x00\x03\r@\x00\x03\r@\x00\x02\xbf \x00\x03\r@\x00\x00\xff\xff\x00\x01\x00\x04\x002\xc3\x12'
START COMMAND:  b'\xaaA\x00\x12\x00\x02a\xb2Ct\x00\x0fA\xb2\x00\x02\xd2<'
2021-12-09 18:57:08,999 INFO [2] - Requesting to start sending from PMU (192.168.100.214:4712)
2021-12-09 18:57:09,031 WARNING [2] - Received unknown message from PMU (192.168.100.214:4712)
2021-12-09 18:57:09,031 INFO [2] - Connection to PMU closed (192.168.100.214:4712)

Any kind of help is highly appreciated,
Thanks!

@sstevan
Copy link
Contributor

sstevan commented Dec 9, 2021

Hey @hrvojej

You might get better insight if you simply remove try / except on line 144 in pdc.py file.

            try:
                received_message = CommonFrame.convert2frame(received_data, self.pmu_cfg2)  # Try to decode received data
                self.logger.debug("[%d] - Received %s from PMU (%s:%d)", self.pdc_id, type(received_message).__name__,
                                  self.pmu_ip, self.pmu_port)
            except FrameError:
                self.logger.warning("[%d] - Received unknown message from PMU (%s:%d)",
                                    self.pdc_id, self.pmu_ip, self.pmu_port)

to this

            # try:
            received_message = CommonFrame.convert2frame(received_data, self.pmu_cfg2)  # Try to decode received data
            self.logger.debug("[%d] - Received %s from PMU (%s:%d)", self.pdc_id, type(received_message).__name__,
                              self.pmu_ip, self.pmu_port)
            # except FrameError:
            #     self.logger.warning("[%d] - Received unknown message from PMU (%s:%d)",
            #                         self.pdc_id, self.pmu_ip, self.pmu_port)

Even better, you can try with traceback and something like traceback.print_stack() and traceback.print_exc().
This will help you pinpoint the actual issue.

@hrvojej
Copy link
Author

hrvojej commented Dec 10, 2021

Hey @sstevan ,

thank you for that - it helped me find the error:

File "C:\pypmu\synchrophasor\frame.py", line 1973, in _int2stat
    unlocked = DataFrame.UNLOCKED_TIME_WORDS[stat & 0x30]
KeyError: 48

Program correctly identifies stat = 24624 (0x6030).
So stat & 0x30 = 48 .
Problem is that 48 is non-existing key. Fromframe.pyI can see that DataFrame.UNLOCKED_TIME_WORDS gives:
{0: '<10', 1: '<100', 2: '<1000', 3: '>1000'}
So 1, 2 or 3 are only possible values.

Any advice on what can I do now?

I assume that stat in binary is actually 110000000110000 which is 15 bits not 16. So I'm somehow missing one bit here.
This is stat from C37.118, and Unlock time in it:

Unlocked_time

So if I'm reading correctly bits 05-04 is Unlocked time and it suppose to be 11 as I read it from my stat value. From standard it says that this is unlocked time > 1000s which would than be option 3: '>1000' in UNLOCKED_TIME_WORDS.

Anyway I can change code so that value get calculated properly, or should I just hardcode UNLOCKED_TIME_WORDS on 3?

EDIT
I've edited file "C:\pypmu\synchrophasor\frame.py", line 1973
and just hardcoded UNLOCKED_TIME_WORDS on 3 :
unlocked = DataFrame.UNLOCKED_TIME_WORDS[3]

and I started to receive data!
:)

@hrvojej
Copy link
Author

hrvojej commented Dec 10, 2021

Since standard says that:

Bits 4–5―Unlocked time: indicates a range of seconds since loss of synch was detected. This counts
seconds from the loss of lock on time synch until it is reacquired. When sync is reacquired, the code goes to
00. The criteria for determining when lock on time synch is achieved or lost is not specified in this
standard. This will be normally implemented as follows:

Bit code -- Indication
00 -- Locked or unlocked less than 10 s
01 -- Unlocked 10 s or longer but less than 100 s
10 -- Unlocked 100 s or longer but less than 1000 s
11 -- Unlocked 1000 s or more

I guess I shouldn't keep this value hardcoded. Biggest problem is why is my STAT 15bit instead 16bit long and how to get around this?

@sstevan sstevan added the bug label Dec 10, 2021
@sstevan
Copy link
Contributor

sstevan commented Dec 10, 2021

Hey @hrvojej,

Looks like shift operation is missing here:

unlocked = DataFrame.UNLOCKED_TIME_WORDS[(stat & 0x30) >> 4]

Shifting should be done for each flag in stat word.

@hrvojej
Copy link
Author

hrvojej commented Dec 10, 2021

According to your comment I've changed lines 1956 - 1969 in synchrophasor/frame.py

        measurement_status = DataFrame.MEASUREMENT_STATUS_WORDS[stat >> 15]
        sync = bool((stat & 0x2000) >> 13)

        if ((stat & 0x1000) >> 12):
            sorting = "arrival"
        else:
            sorting = "timestamp"

        trigger = bool((stat & 0x800) >> 11)
        cfg_change = bool((stat & 0x400) >> 10)
        modified = bool((stat & 0x200) >> 9)
        time_quality = DataFrame.TIME_QUALITY_WORDS[(stat & 0x1c0) >> 6]
        unlocked = DataFrame.UNLOCKED_TIME_WORDS[(stat & 0x30) >> 4]
        trigger_reason = DataFrame.TRIGGER_REASON_WORDS[stat & 0xf]

According to this:

STAT

After code updating everything seems to be running fine.
Please check if that looks ok with you.
Thanks!

@sstevan
Copy link
Contributor

sstevan commented Dec 10, 2021

Thanks @hrvojej

I will keep this one open until we get this resolved.

@veljkoDjurkovic
Copy link

veljkoDjurkovic commented Jul 19, 2022

@hrvojej
Hello, I found some problems that are causing this error.

First, in line 1920 in frame.py:
stat = measurement_status << 2
This should be written this way:
stat = measurement_status << 1 because, according to the standard, PMU sync takes only 1 bit, so if we shift this two times, we have one zero more than we actually need to have.

Next, in line 1955 should be:
measurement_status = DataFrame.MEASUREMENT_STATUS_WORDS[stat >> 14]
If we shift this one 15 times, we will loose less significant bit in Data error bits.
So, this whole part of code should be written like this:

    measurement_status = DataFrame.MEASUREMENT_STATUS_WORDS[stat >> 14]
    sync = bool(stat & 0x2000)

    if stat & 0x1000:
        sorting = "arrival"
    else:
        sorting = "timestamp"

    trigger = bool(stat & 0x800)
    cfg_change = bool(stat & 0x400)
    modified = bool(stat & 0x200)

    time_quality = DataFrame.TIME_QUALITY_WORDS[(stat & 0x1c0)>>6]
    unlocked = DataFrame.UNLOCKED_TIME_WORDS[(stat & 0x30)>>4]
    trigger_reason = DataFrame.TRIGGER_REASON_WORDS[stat & 0xf]

    return measurement_status, sync, sorting, trigger, cfg_change, modified, time_quality, unlocked, trigger_reason

We don't really have to do any shifting with trigger and cfg_change, since they are casted into bool types, but shifting will not cause any error.
Tell me if you agree with those, and I will have frame.py updated as soon it is possible.

Thank you for helping us!
Best regards!

@hrvojej
Copy link
Author

hrvojej commented Jul 19, 2022 via email

@veljkoDjurkovic
Copy link

Thank you @hrvojej for very fast response!

I'm glad that we might have this issue closed soon.
I'm looking forward to your report.

Veljko

Skalar2001 added a commit to Skalar2001/pypmu-popravka that referenced this issue Jul 28, 2022
First, in line 1920 in frame.py:
stat = measurement_status << 2
This should be written this way:
stat = measurement_status << 1 because, according to the standard, PMU sync takes only 1 bit, so if we shift this two times, we have one zero more than we actually need to have.

Next, in line 1955 should be:
measurement_status = DataFrame.MEASUREMENT_STATUS_WORDS[stat >> 14]
If we shift this one 15 times, we will loose less significant bit in Data error bits.
So, this whole part of code should be written like this:
veljkoDjurkovic added a commit to veljkoDjurkovic/pypmu that referenced this issue Jul 28, 2022
First, in line 1920 in frame.py:
stat = measurement_status << 2
This should be written this way:
stat = measurement_status << 1 because, according to the standard, PMU sync takes only 1 bit, so if we shift this two times, we have one zero more than we actually need to have.

Next, in line 1955 should be:
measurement_status = DataFrame.MEASUREMENT_STATUS_WORDS[stat >> 14]
If we shift this one 15 times, we will loose less significant bit in Data error bits.

time_quality and trigger_reason should be shifted to get exact numbers from TIME_QUALITY_WORDS and TRIGGER_REASON_WORDS dictionaries.
Hofsmo added a commit to hallvar-h/pypmu that referenced this issue Aug 10, 2022
Updates to run in the SINTEF lab

I changed collections to collections.abs in frame.py. Since Sequence was moved to collections.abc as of Python 3.7.

It seems that we are receiving frequency and not frequency deviations. I therefore implemented iicsys#3 (comment) . I also implemented iicsys#35 (comment) to fix a bug.
@hrvojej
Copy link
Author

hrvojej commented Aug 16, 2022

Seems like everything is working correctly.
Can you just comment on line:
sync = bool((stat & 0x2000) >> 13)which is:
sync = bool(stat & 0x2000)
in your code.

Are you sure sync doesn't need any shifting?

@veljkoDjurkovic
Copy link

@hrvojej

The thing is that sync is casted to bool, so we don't need to shift it since bool casting returns True for every number which is not zero.

@hrvojej
Copy link
Author

hrvojej commented Aug 16, 2022

Ok, great, thanks.
I'm closing this bug than.

@hrvojej hrvojej closed this as completed Aug 16, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

3 participants